Package cc.redberry.core.tensorgenerator

Source Code of cc.redberry.core.tensorgenerator.TensorGenerator

/*
* 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.core.tensorgenerator;

import cc.redberry.core.combinatorics.symmetries.Symmetries;
import cc.redberry.core.context.CC;
import cc.redberry.core.indexmapping.IndexMappings;
import cc.redberry.core.indexmapping.Mapping;
import cc.redberry.core.indices.SimpleIndices;
import cc.redberry.core.number.Complex;
import cc.redberry.core.number.Rational;
import cc.redberry.core.solver.frobenius.FrobeniusSolver;
import cc.redberry.core.tensor.*;
import cc.redberry.core.transformations.expand.ExpandTransformation;
import cc.redberry.core.transformations.symmetrization.SymmetrizeSimpleTensorTransformation;
import cc.redberry.core.transformations.symmetrization.SymmetrizeUpperLowerIndicesTransformation;
import cc.redberry.core.utils.IntArray;
import cc.redberry.core.utils.TensorUtils;
import gnu.trove.map.hash.TIntObjectHashMap;
import org.apache.commons.math3.util.ArithmeticUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

/**
* Generates tensor of the most general form with specified free indices from specified tensors.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @since 1.0
*/
public class TensorGenerator {

    private final Tensor[] samples;
    private final int[] lowerArray, upperArray;
    private final List<SimpleTensor> coefficients = new ArrayList<>();
    private final boolean symmetricForm;
    private final Symmetries symmetries;
    private final SimpleIndices indices;
    private Tensor result;
    private final boolean withCoefficients;

    private TensorGenerator(SimpleIndices indices, Tensor[] samples, Symmetries symmetries, boolean symmetricForm, boolean withCoefficients, boolean raiseLowerSamples) {
        if (raiseLowerSamples)
            this.samples = expandSamples(samples);
        else this.samples = samples;

        this.symmetries = symmetries;
        this.indices = indices;
        this.symmetricForm = symmetricForm;
        this.lowerArray = indices.getLower().copy();
        this.upperArray = indices.getUpper().copy();
        this.withCoefficients = withCoefficients;
        Arrays.sort(lowerArray);
        Arrays.sort(upperArray);
        generate();
    }


    private void generate() {

        //processing low indices
        int totalLowCount = lowerArray.length, i, k;
        int[] lowCounts = new int[samples.length + 1];
        for (i = 0; i < samples.length; ++i)
            lowCounts[i] = samples[i].getIndices().getFree().getLower().length();
        lowCounts[i] = totalLowCount;

        //processing up indices
        int totalUpCount = upperArray.length;
        int[] upCounts = new int[samples.length + 1];
        for (i = 0; i < samples.length; ++i)
            upCounts[i] = samples[i].getIndices().getFree().getUpper().length();
        upCounts[i] = totalUpCount;

        //solving Frobenius equations
        FrobeniusSolver fbSolver = new FrobeniusSolver(lowCounts, upCounts);

        //processing combinations
        int u, l;
        int[] combination;
        SumBuilder result = new SumBuilder();
        while ((combination = fbSolver.take()) != null) {

            List<Tensor> tCombination = new ArrayList<>();
            u = 0;
            l = 0;
            for (i = 0; i < combination.length; ++i)
                for (int j = 0; j < combination[i]; ++j) {
                    Tensor temp = samples[i];

//                    IndexMappingDirect im = new IndexMappingDirect();
                    IntArray termLow = temp.getIndices().getFree().getLower();
                    IntArray termUp = temp.getIndices().getFree().getUpper();

                    int[] oldIndices = new int[termUp.length() + termLow.length()],
                            newIndices = oldIndices.clone();
                    for (k = 0; k < termUp.length(); ++k) {
                        oldIndices[k] = termUp.get(k);
                        newIndices[k] = upperArray[u++];
                    }
                    for (k = 0; k < termLow.length(); ++k) {
                        oldIndices[k + termUp.length()] = termLow.get(k);
                        newIndices[k + termUp.length()] = lowerArray[l++];
                    }
                    temp = ApplyIndexMapping.applyIndexMapping(temp, new Mapping(oldIndices, newIndices), indices.getAllIndices().copy());
                    tCombination.add(temp);
                }

            //creating term & processing combinatorics
            Tensor[] prodArray = tCombination.toArray(new Tensor[tCombination.size()]);
            Tensors.resolveAllDummies(prodArray);
            Tensor term = SymmetrizeUpperLowerIndicesTransformation.symmetrizeUpperLowerIndices(Tensors.multiplyAndRenameConflictingDummies(prodArray));
            if (symmetricForm || !(term instanceof Sum)) {
                Tensor coefficient;
                if (withCoefficients) {
                    coefficient = CC.generateNewSymbol();
                    coefficients.add((SimpleTensor) coefficient);
                } else coefficient = Complex.ONE;

                term = Tensors.multiply(coefficient, term, term instanceof Sum ? new Complex(new Rational(1, term.size())) : Complex.ONE);
            } else if (withCoefficients)
                term = FastTensors.multiplySumElementsOnFactors((Sum) term);
            result.put(term);
        }
        this.result = (symmetries == null || symmetries.isEmpty()) ? result.build() : symmetrize(result.build(), symmetries);
    }

    private Tensor symmetrize(Tensor result, Symmetries symmetries) {
        //todo rewrite this slag
        SimpleTensor st = Tensors.parseSimple("#$#$#A$#ASD" + indices);
        Expression expr = Tensors.expression(st, result);
        Tensor symmetrized = SymmetrizeSimpleTensorTransformation.symmetrize(
                st, st.getIndices().getAllIndices().copy(), symmetries);
        if (symmetrized instanceof Product)
            symmetrized = Tensors.multiply(symmetrized, ((Product) symmetrized).getFactor().reciprocal());

        assert symmetrized instanceof Sum;

        result = ExpandTransformation.expand(expr.transform(symmetrized));


        if (!(result instanceof Sum))
            return result;

        TIntObjectHashMap<List<Tensor[]>> coefficients = new TIntObjectHashMap<>();
        Tensor oldCoefficient, newCoefficient = null;
        TensorBuilder rebuild = result.getBuilder();
        List<Tensor[]> list;
        for (Tensor t : result) {
            assert t instanceof Product;
            if (t instanceof Product) {
                Tensor[] sc = ((Product) t).getAllScalarsWithoutFactor();
                if (sc.length == 0)
                    continue;

                assert sc.length == 1;
                oldCoefficient = sc[0];

                list = coefficients.get(oldCoefficient.hashCode());
                if (list == null) {
                    list = new ArrayList<>();
                    coefficients.put(oldCoefficient.hashCode(), list);
                }

                Mapping match = null;
                for (Tensor[] transformed : list) {
                    match = IndexMappings.getFirst(transformed[0], oldCoefficient);
                    if (match != null) {
                        newCoefficient = match.getSign() ? Tensors.negate(transformed[1]) : transformed[1];
                        break;
                    }
                }
                if (match == null) {
                    if (oldCoefficient instanceof SimpleTensor) {
                        newCoefficient = oldCoefficient;
                    } else {
                        if (withCoefficients) {
                            newCoefficient = CC.generateNewSymbol();
                            this.coefficients.add((SimpleTensor) newCoefficient);
                            this.coefficients.removeAll(TensorUtils.getAllSymbols(oldCoefficient));
                        }
                    }
                    list.add(new Tensor[]{oldCoefficient, newCoefficient});
                }

                rebuild.put(Tensors.multiply(((Product) t).getFactor(), newCoefficient, ((Product) t).getDataSubProduct()));
            }
        }
        return rebuild.build();
    }

    private Tensor result() {
        return result;
    }


    /**
     * Generates tensor of the most general form with specified free indices from specified tensors.
     *
     * @param indices          free indices of the resulting tensor
     * @param samples          samples which used to  generate tensor of the general form
     * @param symmetries       symmetries of the resulting tensor
     * @param symmetricForm    specifies whether the resulting tensor should be symmetric
     * @param withCoefficients specifies whether each term in the result should be multiplied on arbitrary coefficient
     * @param raiseLower       specifies whether indices of samples should be raised and lowered in the most general form
     * @return tensor of the most general form with specified free indices from specified tensors
     */
    public static Tensor generate(SimpleIndices indices, Tensor[] samples,
                                  Symmetries symmetries, boolean symmetricForm,
                                  boolean withCoefficients, boolean raiseLower) {
        return new TensorGenerator(indices, samples, symmetries, symmetricForm, withCoefficients, raiseLower).result();
    }


    /**
     * Generates tensor of the most general form with specified free indices from specified tensors.
     *
     * @param indices          free indices of the resulting tensor
     * @param samples          samples which used to  generate tensor of the general form
     * @param symmetries       symmetries of the resulting tensor
     * @param symmetricForm    specifies whether the resulting tensor should be symmetric
     * @param withCoefficients specifies whether each term in the result should be multiplied on arbitrary coefficient
     * @param raiseLower       specifies whether indices of samples should be raised and lowered in the most general form
     * @return tensor of the most general form with specified free indices from specified tensors and array of
     *         generated coefficients
     */
    public static GeneratedTensor generateStructure(SimpleIndices indices, Tensor[] samples,
                                                    Symmetries symmetries, boolean symmetricForm,
                                                    boolean withCoefficients, boolean raiseLower) {
        TensorGenerator generator = new TensorGenerator(indices, samples, symmetries, symmetricForm, withCoefficients, raiseLower);
        SimpleTensor[] generatedCoefficients = TensorUtils.getAllSymbols(generator.result()).toArray(new SimpleTensor[0]);
        return new GeneratedTensor(generatedCoefficients,
                generator.result());
    }


    private static class Wrapper {
        private final Tensor tensor;

        private Wrapper(Tensor tensor) {
            this.tensor = tensor;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Wrapper wrapper = (Wrapper) o;

            return IndexMappings.mappingExists(tensor, wrapper.tensor)
                    || IndexMappings.mappingExists(wrapper.tensor, tensor);
        }

        @Override
        public int hashCode() {
            return tensor.hashCode();
        }
    }

    private static Tensor[] expandSamples(Tensor[] samples) {
        //select diff samples:
        HashSet<Wrapper> set = new HashSet<>();
        for (Tensor sample : samples)
            set.add(new Wrapper(sample));


        ArrayList<Tensor> r = new ArrayList<>();
        for (Wrapper st : set) {
            r.ensureCapacity(ArithmeticUtils.pow(2, st.tensor.getIndices().getFree().size()));
            r.addAll(Arrays.asList(TensorGeneratorUtils.allStatesCombinations(st.tensor)));
        }
        return r.toArray(new Tensor[r.size()]);
    }

}
TOP

Related Classes of cc.redberry.core.tensorgenerator.TensorGenerator

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.