Package cc.redberry.physics.feyncalc

Source Code of cc.redberry.physics.feyncalc.DiracTraceTransformation

/*
* Redberry: symbolic tensor computations.
*
* Copyright (c) 2010-2013:
*   Stanislav Poslavsky   <stvlpos@mail.ru>
*   Bolotin Dmitriy       <bolotin.dmitriy@gmail.com>
*
* This file is part of Redberry.
*
* Redberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Redberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Redberry. If not, see <http://www.gnu.org/licenses/>.
*/
package cc.redberry.physics.feyncalc;

import cc.redberry.core.context.CC;
import cc.redberry.core.context.NameAndStructureOfIndices;
import cc.redberry.core.graph.GraphType;
import cc.redberry.core.graph.PrimitiveSubgraph;
import cc.redberry.core.graph.PrimitiveSubgraphPartition;
import cc.redberry.core.indices.IndexType;
import cc.redberry.core.indices.IndicesFactory;
import cc.redberry.core.number.Complex;
import cc.redberry.core.parser.ParseToken;
import cc.redberry.core.parser.ParseTokenTransformer;
import cc.redberry.core.parser.ParseUtils;
import cc.redberry.core.parser.Parser;
import cc.redberry.core.parser.preprocessor.ChangeIndicesTypesAndTensorNames;
import cc.redberry.core.parser.preprocessor.TypesAndNamesTransformer;
import cc.redberry.core.tensor.*;
import cc.redberry.core.tensor.iterator.FromChildToParentIterator;
import cc.redberry.core.transformations.ExpandAndEliminateTransformation;
import cc.redberry.core.transformations.Transformation;
import cc.redberry.core.utils.IntArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;

import static cc.redberry.core.indices.IndicesFactory.createSimple;
import static cc.redberry.core.indices.IndicesUtils.*;
import static cc.redberry.core.tensor.Tensors.*;

/**
* Calculate traces of gamma matrices in four dimensions.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*/
public class DiracTraceTransformation implements Transformation {
    /*
     * Defaults
     */
    private static final String gammaMatrixStringName = "G";
    private static final String gamma5StringName = "G5";
    private static final String leviCivitaStringName = "eps";

    private final int gammaName, gamma5Name;
    private final IndexType metricType, matrixType;
    private final LeviCivitaSimplifyTransformation simplifyLeviCivita;

    private final ParseTokenTransformer tokenTransformer;
    private final Expression deltaTrace;

    /**
     * Creates transformation with specified notation for gamma matrix.
     *
     * @param gammaMatrix tensor, which will be considered as gamma matrix
     */
    public DiracTraceTransformation(final SimpleTensor gammaMatrix) {
        checkNotation(gammaMatrix);
        this.gammaName = gammaMatrix.getName();
        //no gamma5 should be in tensors
        this.gamma5Name = Integer.MIN_VALUE;
        final IndexType[] types = TraceUtils.extractTypesFromMatrix(gammaMatrix);
        this.metricType = types[0];
        this.matrixType = types[1];

        tokenTransformer = new ChangeIndicesTypesAndTensorNames(new TypesAndNamesTransformer() {
            @Override
            public IndexType newType(IndexType oldType, NameAndStructureOfIndices oldDescriptor) {
                switch (oldType) {
                    case LatinLower:
                        return metricType;
                    case Matrix1:
                        return matrixType;
                }
                return oldType;
            }

            @Override
            public String newName(NameAndStructureOfIndices oldDescriptor) {
                switch (oldDescriptor.getName()) {
                    case gammaMatrixStringName:
                        return gammaMatrix.getStringName();
                    case gamma5StringName:
                        throw new IllegalArgumentException("Gamma5 is not specified.");
                    case leviCivitaStringName:
                        throw new IllegalArgumentException("Levi-Civita is not specified.");
                    default:
                        return oldDescriptor.getName();
                }
            }
        });

        this.simplifyLeviCivita = null;
        this.deltaTrace = (Expression) tokenTransformer.transform(CC.current().getParseManager().getParser().parse("d^a_a=4")).toTensor();
    }

    /**
     * Creates transformation with specified notations for gamma matrices and Levi-Civita tensor.
     *
     * @param gammaMatrix tensor, which will be considered as gamma matrix
     * @param gamma5      tensor, which will be considered as gamma5 matrix
     * @param leviCivita  tensor, which will be considered as Levi-Civita tensor
     */
    public DiracTraceTransformation(final SimpleTensor gammaMatrix,
                                    final SimpleTensor gamma5,
                                    final SimpleTensor leviCivita) {
        this(gammaMatrix, gamma5, leviCivita, true);
    }

    /**
     * Creates transformation with specified notations for gamma matrices and Levi-Civita tensor.
     *
     * @param gammaMatrix    tensor, which will be considered as gamma matrix
     * @param gamma5         tensor, which will be considered as gamma5 matrix
     * @param leviCivita     tensor, which will be considered as Levi-Civita tensor
     * @param minkowskiSpace if {@code true}, then Levi-Civita tensor will be considered in Minkovski
     *                       space (so e.g. e_abcd*e^abcd = -24), otherwise in Euclidean space
     *                       (so e.g. e_abcd*e^abcd = +24)
     */
    public DiracTraceTransformation(final SimpleTensor gammaMatrix,
                                    final SimpleTensor gamma5,
                                    final SimpleTensor leviCivita,
                                    final boolean minkowskiSpace) {
        checkNotation(gammaMatrix, gamma5, leviCivita);
        this.gammaName = gammaMatrix.getName();
        this.gamma5Name = gamma5.getName();
        final IndexType[] types = TraceUtils.extractTypesFromMatrix(gammaMatrix);
        this.metricType = types[0];
        this.matrixType = types[1];

        tokenTransformer = new ChangeIndicesTypesAndTensorNames(new TypesAndNamesTransformer() {
            @Override
            public IndexType newType(IndexType oldType, NameAndStructureOfIndices oldDescriptor) {
                switch (oldType) {
                    case LatinLower:
                        return metricType;
                    case Matrix1:
                        return matrixType;
                }
                return oldType;
            }

            @Override
            public String newName(NameAndStructureOfIndices oldDescriptor) {
                switch (oldDescriptor.getName()) {
                    case gammaMatrixStringName:
                        return gammaMatrix.getStringName();
                    case gamma5StringName:
                        return gamma5.getStringName();
                    case leviCivitaStringName:
                        return leviCivita.getStringName();
                    default:
                        return oldDescriptor.getName();
                }
            }
        });

        this.simplifyLeviCivita = new LeviCivitaSimplifyTransformation(leviCivita, minkowskiSpace);
        this.deltaTrace = (Expression) tokenTransformer.transform(CC.current().getParseManager().getParser().parse("d^a_a=4")).toTensor();
    }

    @Override
    public Tensor transform(Tensor tensor) {
        //todo may be check for contains gammas
        tensor = ExpandAndEliminateTransformation.expandAndEliminate(tensor);
        FromChildToParentIterator iterator = new FromChildToParentIterator(tensor);
        Tensor current;
        out:
        while ((current = iterator.next()) != null) {
            if (isGammaOrGamma5(current)
                    && current.getIndices().getFree().size(matrixType) == 0) {
                iterator.set(Complex.ZERO);
            } else if (current instanceof Product) {
                if (current.getIndices().getFree().size(matrixType) != 0)
                    continue;
                //fast check
                boolean needTrace = false;
                for (Tensor t : current)
                    if (isGammaOrGamma5(t)) {
                        needTrace = true;
                        break;
                    }
                if (!needTrace)
                    continue;

                //selecting unitary matrices from product
                //extracting trace combinations from product
                Product product = (Product) current;
                //positions of matrices
                IntArrayList positionsOfMatrices = new IntArrayList();
                int sizeOfIndexless = product.sizeOfIndexlessPart();
                ProductContent pc = product.getContent();
                PrimitiveSubgraph[] partition
                        = PrimitiveSubgraphPartition.calculatePartition(pc, matrixType);

                //calculated traces
                ProductBuilder traces = new ProductBuilder();

                traces:
                for (PrimitiveSubgraph subgraph : partition) {
                    if (subgraph.getGraphType() != GraphType.Cycle)
                        continue;

                    int numberOfGammas = 0, numberOfGamma5s = 0;

                    Tensor gamma;
                    //actual positions in current
                    int[] positions = subgraph.getPartition();
                    assert positions.length > 1;

                    for (int i = positions.length - 1; i >= 0; --i) {
                        positions[i] = positions[i] + sizeOfIndexless;
                        gamma = product.get(positions[i]);
                        if (gamma instanceof SimpleTensor) {
                            if (((SimpleTensor) gamma).getName() == gammaName)
                                ++numberOfGammas;
                            else if (((SimpleTensor) gamma).getName() == gamma5Name)
                                ++numberOfGamma5s;
                            else
                                //not a gamma matrix
                                continue traces;
                        } else {
                            //not a gamma matrix
                            continue traces;
                        }
                    }

                    //early terminations
                    if (numberOfGammas % 2 == 1
                            || (numberOfGammas == 2 && numberOfGamma5s % 2 == 1)) {
                        iterator.set(Complex.ZERO);
                        continue out;
                    }
                    if (numberOfGammas == 0 && numberOfGamma5s % 2 == 1) {
                        iterator.set(Complex.ZERO);
                        continue out;
                    }

                    positionsOfMatrices.addAll(positions);
                    if (numberOfGamma5s == 0)
                        traces.put(traceWithout5(product.select(positions), numberOfGammas));
                    else {
                        //early check
                        if (numberOfGammas == 0) {
                            //numberOfGamma5s % 2 == 0
                            traces.put(Complex.FOUR);
                            continue traces;
                        }


                        //eliminating excess products of gamma5s
                        if (numberOfGamma5s > 1) {
                            //take into account odd number of swaps
                            boolean sign = false;
                            //product of gammas as ordered array (will be filled without excess gamma5s)
                            final SimpleTensor[] orderedProduct = new SimpleTensor[numberOfGammas + (numberOfGamma5s % 2 == 0 ? 0 : 1)];
                            int counter = -1;

                            //index of tensor in product content, which is contracted with current gamma5
                            int positionOfPreviousGamma = -2;

                            SimpleTensor currentGamma;
                            for (int positionOfGamma = 0; positionOfGamma < positions.length; ++positionOfGamma) {
                                currentGamma = (SimpleTensor) product.get(positions[positionOfGamma]);
                                if (currentGamma.getName() == gamma5Name) {
                                    //adding one gamma5 if they are odd number
                                    if (positionOfPreviousGamma == -2) {
                                        if (numberOfGamma5s % 2 == 1) {
                                            orderedProduct[++counter] = currentGamma;
                                            positionOfPreviousGamma = -1;
                                        } else {
                                            positionOfPreviousGamma = positionOfGamma;
                                        }
                                        continue;
                                    }
                                    if (positionOfPreviousGamma == -1)
                                        positionOfPreviousGamma = positionOfGamma;
                                    else {
                                        //odd number of swaps
                                        if ((positionOfGamma - positionOfPreviousGamma) % 2 == 0)
                                            sign ^= true;
                                        positionOfPreviousGamma = -1;
                                    }
                                } else
                                    orderedProduct[++counter] = currentGamma;
                            }

                            //fixing new indices contractions
                            int u = 0, l = 0;
                            for (int i = 0; ; ++i) {
                                if (i == orderedProduct.length - 1) {
                                    orderedProduct[i] = setMatrixIndices(orderedProduct[i], u, 0);
                                    break;
                                }
                                orderedProduct[i] = setMatrixIndices(orderedProduct[i], u, ++l);
                                u = l;
                            }

                            Tensor withoutExcessGamma5s = multiply(orderedProduct);

                            if (numberOfGamma5s % 2 == 0)
                                withoutExcessGamma5s = traceWithout5(withoutExcessGamma5s, numberOfGammas);
                            else {
                                withoutExcessGamma5s = traceWith5(withoutExcessGamma5s, numberOfGammas);
                                withoutExcessGamma5s = simplifyLeviCivita.transform(withoutExcessGamma5s);
                            }

                            if (sign)
                                withoutExcessGamma5s = negate(withoutExcessGamma5s);
                            traces.put(withoutExcessGamma5s);
                        } else
                            traces.put(traceWith5(product.select(positions), numberOfGammas));
                    }
                }
                if (positionsOfMatrices.isEmpty())
                    continue out;

                //final simplifications
                traces.put(product.remove(positionsOfMatrices.toArray()));
                current = traces.build();
                current = ExpandAndEliminateTransformation.expandAndEliminate(current);
                current = deltaTrace.transform(current);
                if (simplifyLeviCivita != null)
                    current = simplifyLeviCivita.transform(current);
                iterator.set(current);
            }
        }
        return iterator.result();
    }

    private SimpleTensor setMatrixIndices(SimpleTensor gamma, int matrixUpper, int matrixLower) {
        int[] indices = gamma.getIndices().getAllIndices().copy();
        for (int i = indices.length - 1; i >= 0; --i)
            if (!CC.isMetric(getType(indices[i]))) {
                indices[i] = getState(indices[i]) ?
                        createIndex(matrixUpper, getType(indices[i]), getState(indices[i]))
                        : setType(getType(indices[i]), matrixLower);
            }
        return simpleTensor(gamma.getName(), IndicesFactory.createSimple(null, indices));
    }


    private boolean isGammaOrGamma5(Tensor tensor) {
        if (tensor instanceof SimpleTensor) {
            int name = ((SimpleTensor) tensor).getName();
            if (name == gammaName)
                return true;
            if (name == gamma5Name) {
                if (simplifyLeviCivita == null)
                    return false;
                return true;
            }
        }
        return false;
    }

    /*
     * *********************
     * Trace without gamma5
     * *********************
     */

    /**
     * cached substitutions of traces without 5
     */
    private final TIntObjectHashMap<Expression> cachedSubstitutions = new TIntObjectHashMap<>();

    private Tensor traceWithout5(Tensor tensor, int numberOfGammas) {
        Expression substitution = cachedSubstitutions.get(numberOfGammas);
        if (substitution == null) {
            ParseToken rawSubstitution = createRawGammaSubstitution(numberOfGammas);
            substitution = (Expression) tokenTransformer.transform(rawSubstitution).toTensor();
            cachedSubstitutions.put(numberOfGammas, substitution);
        }

        tensor = substitution.transform(tensor);
        tensor = ExpandAndEliminateTransformation.expandAndEliminate(tensor);
        tensor = deltaTrace.transform(tensor);
        return tensor;
    }

    private static ParseToken createRawGammaSubstitution(int numberOfGammas) {
        ParseToken substitution = cachedRawGammaTraces.get(numberOfGammas);
        if (substitution == null) {

            //product of gamma matrices as array
            Tensor[] gammas = new Tensor[numberOfGammas];
            int matrixIndex = setType(IndexType.Matrix1, 0) - 1, metricIndex = -1;
            int firstUpper, u = firstUpper = ++matrixIndex, i;
            for (i = 0; i < numberOfGammas; ++i) {
                gammas[i] = Tensors.simpleTensor(gammaMatrixStringName,
                        createSimple(null,
                                u | 0x80000000,
                                i == numberOfGammas - 1 ? firstUpper : (u = ++matrixIndex),
                                ++metricIndex));

            }
            Expression expression = expression(Tensors.multiply(gammas), traceOfArray(gammas));
            substitution = ParseUtils.tensor2AST(expression);
            cachedRawGammaTraces.put(numberOfGammas, substitution);
        }
        return substitution;
    }

    private static Tensor traceOfArray(Tensor[] product) {
        //calculates trace using recursive algorithm
        if (product.length == 1)
            return Complex.ZERO;
        if (product.length == 2)
            return multiply(Complex.FOUR,
                    createMetricOrKronecker(product[0].getIndices().get(IndexType.LatinLower, 0),
                            product[1].getIndices().get(IndexType.LatinLower, 0)));
        if (product.length % 2 != 0)
            return Complex.ZERO;
        SumBuilder sb = new SumBuilder();
        Tensor temp;
        for (int i = 0; i < product.length - 1; ++i) {
            temp = multiply(Complex.TWO,
                    createMetricOrKronecker(product[i].getIndices().get(IndexType.LatinLower, 0),
                            product[i + 1].getIndices().get(IndexType.LatinLower, 0)),
                    traceOfArray(subArray(product, i, i + 1)));
            if (i % 2 != 0)
                temp = negate(temp);
            sb.put(temp);
            swap(product, i, i + 1);
        }
        return multiply(Complex.ONE_HALF, sb.build());
    }

    private static Tensor[] subArray(Tensor[] array, int a, int b) {
        Tensor[] result = new Tensor[array.length - 2];
        int k = 0;
        for (int i = 0; i < array.length; ++i) {
            if (i == a || i == b)
                continue;
            result[k++] = array[i];
        }
        return result;
    }

    private static void swap(Tensor[] array, int a, int b) {
        Tensor temp = array[a];
        array[a] = array[b];
        array[b] = temp;
    }

    /*
    * Cached parse tokens
    */
    private static TIntObjectHashMap<ParseToken> cachedRawGammaTraces = new TIntObjectHashMap<>();

    public static void resetCache() {
        cachedRawGammaTraces = new TIntObjectHashMap<>();
    }


    /*
     * *********************
     * Trace with gamma5
     * *********************
     */
    //cached substitutions of traces with 5
    /**
     * Tr[G_a*G_b*G_c*G_d*G5] = -4*I*e_abcd
     */
    private Transformation traceOf4GammasWith5;
    /**
     * Chiholm-Kahane identitie:
     * G_a*G_b*G_c = g_ab*G_c-g_ac*G_b+g_bc*G_a-I*e_abcd*G5*G^d
     */
    private Transformation chiholmKahaneIdentity;


    private Tensor traceWith5(Tensor product, int numberOfGammas) {
        if (traceOf4GammasWith5 == null) {
            traceOf4GammasWith5 = (Expression) tokenTransformer.transform(traceOf4GammasWith5Token).toTensor();
            chiholmKahaneIdentity = (Expression) tokenTransformer.transform(chiholmKahaneToken).toTensor();
        }

        if (numberOfGammas == 4)
            return traceOf4GammasWith5.transform(product);

        product = chiholmKahaneIdentity.transform(product);
        product = ExpandAndEliminateTransformation.expandAndEliminate(product);
        product = traceOf4GammasWith5.transform(product);
        product = simplifyLeviCivita.transform(product);
        return transform(product);
    }

    private static final void checkNotation(SimpleTensor gammaMatrix) {
        final IndexType[] types = TraceUtils.extractTypesFromMatrix(gammaMatrix);
        IndexType metricType = types[0];
        IndexType matrixType = types[1];
        if (gammaMatrix.getIndices().size() != 3
                || gammaMatrix.getIndices().size(metricType) != 1
                || gammaMatrix.getIndices().size(matrixType) != 2)
            throw new IllegalArgumentException("Not a gamma: " + gammaMatrix);
    }

    private static final void checkNotation(SimpleTensor gammaMatrix,
                                            SimpleTensor gamma5Matrix,
                                            SimpleTensor leviCivita) {
        final IndexType[] types = TraceUtils.extractTypesFromMatrix(gammaMatrix);
        IndexType metricType = types[0];
        IndexType matrixType = types[1];

        if (gammaMatrix.getIndices().size() != 3
                || gammaMatrix.getIndices().size(metricType) != 1
                || gammaMatrix.getIndices().size(matrixType) != 2)
            throw new IllegalArgumentException("Not a gamma: " + gammaMatrix);

        if (gamma5Matrix.getIndices().size() != 2
                || gamma5Matrix.getIndices().size(matrixType) != 2)
            throw new IllegalArgumentException("Not a gamma5: " + gamma5Matrix);

        if (leviCivita.getIndices().size() != 4
                || leviCivita.getIndices().size(metricType) != 4)
            throw new IllegalArgumentException("Not a Levi-Civita: " + leviCivita);
    }


    private static final Parser parser;
    /**
     * Tr[G_a*G_b*G_c*G_d*G5] = -4*I*e_abcd
     */
    private static final ParseToken traceOf4GammasWith5Token;
    /**
     * Chiholm-Kahane identitie:
     * G_a*G_b*G_c = g_ab*G_c-g_ac*G_b+g_bc*G_a-I*e_abcd*G5*G^d
     */
    private static final ParseToken chiholmKahaneToken;

    static {
        parser = CC.current().getParseManager().getParser();
        traceOf4GammasWith5Token = parser.parse("G_a^a'_b'*G_b^b'_c'*G_c^c'_d'*G_d^d'_e'*G5^e'_a' = -4*I*eps_abcd");
        chiholmKahaneToken = parser.parse("G_a^a'_c'*G_b^c'_d'*G_c^d'_b' = g_ab*G_c^a'_b'-g_ac*G_b^a'_b'+g_bc*G_a^a'_b'-I*e_abcd*G5^a'_c'*G^dc'_b'");
    }
}
TOP

Related Classes of cc.redberry.physics.feyncalc.DiracTraceTransformation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.