Package cc.redberry.core.tensor

Source Code of cc.redberry.core.tensor.Tensors

/*
* Redberry: symbolic tensor computations.
*
* Copyright (c) 2010-2012:
*   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.tensor;

import cc.redberry.core.combinatorics.Symmetry;
import cc.redberry.core.context.CC;
import cc.redberry.core.context.NameDescriptor;
import cc.redberry.core.indices.*;
import cc.redberry.core.number.Complex;
import cc.redberry.core.parser.ParseNodeTransformer;
import cc.redberry.core.tensor.functions.*;
import cc.redberry.core.transformations.ApplyIndexMapping;
import cc.redberry.core.transformations.Expand;
import cc.redberry.core.utils.TensorUtils;
import java.util.HashSet;
import java.util.Set;

/**
* <p>Factory methods to create any tensor are collected in this class. Using
* the methods implemented in this class is the preferred way to create a
* tensor.</p>
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @see TensorFactory
* @see TensorBuilder
*/
public final class Tensors {

    private Tensors() {
    }

    // ==========================  Factory Methods ============================
    /**
     * Returns tensor in the integer power. Common result is an object of class
     * Power, but for some input arguments result could have different type.
     *
     * @param argument base
     * @param power    power
     *
     * @return result of argument exponentiation
     */
    public static Tensor pow(Tensor argument, int power) {
        return pow(argument, new Complex(power));
    }

    /**
     * Returns tensor in the scalar power. Common result is an object of class
     * Power, but for some input arguments result could have different type.
     *
     * @param argument base
     * @param power    power
     *
     * @return result of argument exponentiation
     */
    public static Tensor pow(Tensor argument, Tensor power) {
        PowerBuilder pb = new PowerBuilder();
        pb.put(argument);
        pb.put(power);
        return pb.build();
    }

    /**
     * <p>Returns result of multiplication of several tensors. Einstein notation
     * assumed. Common result is an object of class Product, but for some input
     * arguments result could have different type.</p> <p>If there is a chance
     * that some factors have conflicting (same name) dummy indices use {@link #multiplyAndRenameConflictingDummies(Tensor...)}
     * instead.</p>
     *
     * @param factors array of factors to be multiplied
     *
     * @return result of multiplication
     */
    public static Tensor multiply(final Tensor... factors) {
        //TODO add check for indices consistency
        return ProductFactory.FACTORY.create(factors);
    }

    /**
     * <p>Returns result of multiplication of several tensors taking care about
     * all conflicting dummy indices in the factors. Einstein notation assumed.
     * Common result is an object of class Product, but for some input arguments
     * result could have different type.</p>
     *
     * @param factors array of factors to be multiplied
     *
     * @return result of multiplication
     */
    public static Tensor multiplyAndRenameConflictingDummies(Tensor... factors) {
        Tensor t = ProductFactory.FACTORY.create(factors);
        if (!(t instanceof Product))
            return t;

        //postprocessing product
        Product p = (Product) t;
        //all product indices
        Set<Integer> totalIndices = new HashSet<>();
        int i, j;
        Indices indices = p.indices;
        for (i = indices.size() - 1; i >= 0; --i)
            totalIndices.add(IndicesUtils.getNameWithType(indices.get(i)));

        int[] forbidden;
        Tensor current;
        //processing indexless data
        for (i = 0; i < p.indexlessData.length; ++i) {
            current = p.indexlessData[i];
            if (current instanceof Sum || current instanceof Power) {
                forbidden = new int[totalIndices.size()];
                j = -1;
                for (Integer index : totalIndices)
                    forbidden[++j] = index;
                p.indexlessData[i] = ApplyIndexMapping.renameDummyFromClonedSource(current, forbidden);
                totalIndices.addAll(TensorUtils.getAllIndicesNames(p.indexlessData[i]));
            }
        }
        Set<Integer> free;
        for (i = 0; i < p.data.length; ++i) {
            current = p.data[i];
            if (current instanceof Sum || current instanceof Power) {
                free = new HashSet<>(current.getIndices().size());
                for (j = current.getIndices().size() - 1; j >= 0; --j)
                    free.add(IndicesUtils.getNameWithType(current.getIndices().get(j)));
                totalIndices.removeAll(free);
                forbidden = new int[totalIndices.size()];
                j = -1;
                for (Integer index : totalIndices)
                    forbidden[++j] = index;
                p.data[i] = ApplyIndexMapping.renameDummyFromClonedSource(current, forbidden);
                totalIndices.addAll(TensorUtils.getAllIndicesNames(p.data[i]));
            }
        }
        return p;
    }

    /**
     * Returns result of summation of several tensors. Common result is an
     * object of class Sum, but for some input arguments result could have
     * different type.
     *
     * @param tensors array of summands
     *
     * @return result of summation
     */
    public static Tensor sum(Tensor... tensors) {
        return SumFactory.FACTORY.create(tensors);
    }

    /**
     * Returns new simple tensor with specified string name and indices.
     *
     * @param name    string name of the tensor
     * @param indices indices
     *
     * @return new instance of {@link SimpleTensor} object
     */
    public static SimpleTensor simpleTensor(String name, SimpleIndices indices) {
        NameDescriptor descriptor = CC.getNameManager().mapNameDescriptor(name, indices.getIndicesTypeStructure());
        return new SimpleTensor(descriptor.getId(),
                                UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(),
                                                                    indices));
    }

    /**
     * Returns new simple tensor with specified int name (see {@link cc.redberry.core.context.NameManager}
     * for details) and indices.
     *
     * @param name    int name of the tensor
     * @param indices indices
     *
     * @return new instance of {@link SimpleTensor} object
     */
    public static SimpleTensor simpleTensor(int name, SimpleIndices indices) {
        NameDescriptor descriptor = CC.getNameDescriptor(name);
        if (descriptor == null)
            throw new IllegalArgumentException("This name is not registered in the system.");
        if (!descriptor.getIndicesTypeStructure().isStructureOf(indices))
            throw new IllegalArgumentException("Specified indices are not indices of specified tensor.");
        return new SimpleTensor(name,
                                UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(),
                                                                    indices));
    }

    /**
     * Returns new tensor field with specified string name, indices and
     * arguments list. Free indices of arguments assumed as arguments indices
     * bindings of this field bindings.
     *
     * @param name      int name of the field
     * @param indices   indices
     * @param arguments arguments list
     *
     * @return new instance of {@link TensorField} object
     */
    public static TensorField field(String name, SimpleIndices indices, Tensor[] arguments) {
        SimpleIndices[] argIndices = new SimpleIndices[arguments.length];
        for (int i = 0; i < argIndices.length; ++i)
            argIndices[i] = IndicesFactory.createSimple(null, arguments[i].getIndices().getFree());
        return field(name, indices, argIndices, arguments);
    }

    /**
     * Returns new tensor field with specified string name, indices, arguments
     * list and explicit argument indices bindings.
     *
     * @param name       int name of the field
     * @param indices    indices
     * @param argIndices argument indices bindings
     * @param arguments  arguments list
     *
     * @return new instance of {@link TensorField} object
     */
    public static TensorField field(String name, SimpleIndices indices, SimpleIndices[] argIndices, Tensor[] arguments) {
        if (argIndices.length != arguments.length)
            throw new IllegalArgumentException("Argument indices array and arguments array have different length.");
        if (arguments.length == 0)
            throw new IllegalArgumentException("No arguments in field.");
        for (int i = 0; i < argIndices.length; ++i)
            if (!arguments[i].getIndices().getFree().equalsRegardlessOrder(argIndices[i]))
                throw new IllegalArgumentException("Arguments indices are inconsistent with arguments.");

        IndicesTypeStructure[] structures = new IndicesTypeStructure[argIndices.length + 1];
        structures[0] = indices.getIndicesTypeStructure();
        for (int i = 0; i < argIndices.length; ++i)
            structures[i + 1] = argIndices[i].getIndicesTypeStructure();
        NameDescriptor descriptor = CC.getNameManager().mapNameDescriptor(name, structures);
        return new TensorField(descriptor.getId(),
                               UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(), indices),
                               arguments, argIndices);
    }

    /**
     * Returns new tensor field with specified int name (see {@link cc.redberry.core.context.NameManager}
     * for details), indices, arguments list and explicit argument indices
     * bindings.
     *
     * @param name       int name of the field
     * @param indices    indices
     * @param argIndices argument indices bindings
     * @param arguments  arguments list
     *
     * @return new instance of {@link TensorField} object
     */
    public static TensorField field(int name, SimpleIndices indices, SimpleIndices[] argIndices, Tensor[] arguments) {
        if (argIndices.length != arguments.length)
            throw new IllegalArgumentException("Argument indices array and arguments array have different length.");
        if (arguments.length == 0)
            throw new IllegalArgumentException("No arguments in field.");
        NameDescriptor descriptor = CC.getNameDescriptor(name);
        if (descriptor == null)
            throw new IllegalArgumentException("This name is not registered in the system.");
        if (!descriptor.isField())
            throw new IllegalArgumentException("Name correspods to simple tensor (not a field).");
        if (descriptor.getIndicesTypeStructures().length - 1 != argIndices.length)
            throw new IllegalArgumentException("This name corresponds to field with different number of arguments.");
        if (!descriptor.getIndicesTypeStructure().isStructureOf(indices))
            throw new IllegalArgumentException("Specified indices are not indices of specified tensor.");
        for (int i = 0; i < argIndices.length; ++i) {
            if (!descriptor.getIndicesTypeStructures()[i + 1].isStructureOf(argIndices[i]))
                throw new IllegalArgumentException("Arguments indices are inconsistent with field signature.");
            if (!arguments[i].getIndices().getFree().equalsRegardlessOrder(argIndices[i]))
                throw new IllegalArgumentException("Arguments indices are inconsistent with arguments.");
        }
        return new TensorField(name,
                               UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(), indices),
                               arguments, argIndices);
    }

    /**
     * Returns new tensor field with specified int name (see {@link cc.redberry.core.context.NameManager}
     * for details), indices and arguments list. Free indices of arguments
     * assumed as arguments indices bindings of this field bindings.
     *
     * @param name      int name of the field
     * @param indices   indices
     * @param arguments arguments list
     *
     * @return new instance of {@link TensorField} object
     */
    public static TensorField field(int name, SimpleIndices indices, Tensor[] arguments) {
        if (arguments.length == 0)
            throw new IllegalArgumentException("No arguments in field.");
        NameDescriptor descriptor = CC.getNameDescriptor(name);
        if (descriptor == null)
            throw new IllegalArgumentException("This name is not registered in the system.");
        if (!descriptor.getIndicesTypeStructure().isStructureOf(indices))
            throw new IllegalArgumentException("Specified indices are not indices of specified tensor.");
        SimpleIndices[] argIndices = new SimpleIndices[arguments.length];
        for (int i = 0; i < arguments.length; ++i)
            argIndices[i] = IndicesFactory.createSimple(null, arguments[i].getIndices().getFree());
        return new TensorField(name,
                               UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(), indices),
                               arguments, argIndices);
    }

    /**
     * Creates an expression object from two tensors.
     *
     * @param left  left part of expression
     * @param right right part of expression
     *
     * @return new object of type {@link Expression}
     */
    public static Expression expression(Tensor left, Tensor right) {
        return ExpressionFactory.FACTORY.create(left, right);
    }

    /**
     * Creates a sinus object from scalar argument. Common result is an object
     * of class Sin, but for some input argument result could have different
     * type.
     *
     * @param argument scalar argument of sinus
     *
     * @return sinus of argument
     */
    public static Tensor sin(Tensor argument) {
        return Sin.SinFactory.FACTORY.create(argument);
    }

    /**
     * Creates a cosine object from scalar argument. Common result is an object
     * of class Cos, but for some input argument result could have different
     * type.
     *
     * @param argument scalar argument of cosine
     *
     * @return cosine of argument
     */
    public static Tensor cos(Tensor argument) {
        return Cos.CosFactory.FACTORY.create(argument);
    }

    /**
     * Creates a tangent object from scalar argument. Common result is an object
     * of class Tan, but for some input argument result could have different
     * type.
     *
     * @param argument scalar argument of tangent
     *
     * @return tangent of argument
     */
    public static Tensor tan(Tensor argument) {
        return Tan.TanFactory.FACTORY.create(argument);
    }

    /**
     * Creates a cotangent object from scalar argument. Common result is an
     * object of class Cot, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of cotangent
     *
     * @return cotangent of argument
     */
    public static Tensor cot(Tensor argument) {
        return Cot.CotFactory.FACTORY.create(argument);
    }

    /**
     * Creates a arcsinus object from scalar argument. Common result is an
     * object of class ArcSin, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of arcsinus
     *
     * @return arcsinus of argument
     */
    public static Tensor arcsin(Tensor argument) {
        return ArcSin.ArcSinFactory.FACTORY.create(argument);
    }

    /**
     * Creates a arccosine object from scalar argument. Common result is an
     * object of class ArcCos, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of arccosine
     *
     * @return arccosine of argument
     */
    public static Tensor arccos(Tensor argument) {
        return ArcCos.ArcCosFactory.FACTORY.create(argument);
    }

    /**
     * Creates a arctangent object from scalar argument. Common result is an
     * object of class ArcTan, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of arctangent
     *
     * @return arctangent of argument
     */
    public static Tensor arctan(Tensor argument) {
        return ArcTan.ArcTanFactory.FACTORY.create(argument);
    }

    /**
     * Creates a arcotangent object from scalar argument. Common result is an
     * object of class ArcCot, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of arccotangent
     *
     * @return arcotangent of argument
     */
    public static Tensor arccot(Tensor argument) {
        return ArcCot.ArcCotFactory.FACTORY.create(argument);
    }

    /**
     * Creates a natural logarithm object from scalar argument. Common result is
     * an object of class Log, but for some input argument result could have
     * different type.
     *
     * @param argument scalar argument of logarithm
     *
     * @return natural logarithm of argument
     */
    public static Tensor log(Tensor argument) {
        return Log.LogFactory.FACTORY.create(argument);
    }

    /**
     * Creates a exponent object from scalar argument. Common result is an
     * object of class Exp, but for some input argument result could have
     * different type. See {@link #pow(Tensor, Tensor)}.
     *
     * @param argument scalar argument of exponent
     *
     * @return exponent of argument
     */
    public static Tensor exp(Tensor argument) {
        return Exp.ExpFactory.FACTORY.create(argument);
    }

    public static SimpleTensor createKronecker(int index1, int index2) {
        return CC.current().createKronecker(index1, index2);
    }

    public static SimpleTensor createMetric(int index1, int index2) {
        return CC.current().createMetric(index1, index2);
    }

    public static SimpleTensor createMetricOrKronecker(int index1, int index2) {
        return CC.current().createMetricOrKronecker(index1, index2);
    }

    public static boolean isKronecker(Tensor t) {
        if (!(t instanceof SimpleTensor))
            return false;
        return CC.current().isKronecker((SimpleTensor) t);
    }

    public static boolean isMetric(Tensor t) {
        if (!(t instanceof SimpleTensor))
            return false;
        return CC.current().isMetric((SimpleTensor) t);
    }

    public static boolean isKroneckerOrMetric(Tensor t) {
        if (!(t instanceof SimpleTensor))
            return false;
        return CC.current().isKroneckerOrMetric((SimpleTensor) t);
    }

    public static boolean isKroneckerOrMetric(SimpleTensor t) {
        return CC.current().isKroneckerOrMetric(t);
    }

    /**
     * Parses a string to tensor.
     *
     * @param expression string to be parsed
     *
     * @return result of parsing
     */
    public static Tensor parse(String expression) {
        return CC.current().getParseManager().parse(expression);
    }

    public static Tensor parse(String expression, ParseNodeTransformer... preprocessors) {
        return CC.current().getParseManager().parse(expression, preprocessors);
    }

    /**
     * Parses a string to tensor and casts it to SimpleTensor.
     *
     * @param expression string to be parsed
     *
     * @return simple tensor
     */
    public static SimpleTensor parseSimple(String expression) {
        Tensor t = parse(expression);
        if (!(t instanceof SimpleTensor))
            throw new IllegalArgumentException("Input tensor is not SimpleTensor.");
        return (SimpleTensor) t;
    }

    /**
     * Parses a string to tensor and casts it to Expression.
     *
     * @param expression expression to be parsed
     *
     * @return expression object
     */
    public static Expression parseExpression(String expression) {
        Tensor t = parse(expression);
        if (!(t instanceof Expression))
            throw new IllegalArgumentException("Input tensor is not Expression.");
        return (Expression) t;
    }

    public static void addSymmetry(String tensor, IndexType type, boolean sign, int... symmetry) {
        parseSimple(tensor).getIndices().getSymmetries().add(type.getType(), new Symmetry(symmetry, sign));
    }

    public static void addSymmetry(SimpleTensor tensor, IndexType type, boolean sign, int... symmetry) {
        tensor.getIndices().getSymmetries().add(type.getType(), new Symmetry(symmetry, sign));
    }

    /**
     * Multiplies a tensor by minus one.
     *
     * @param tensor tensor to be negotiated
     *
     * @return tensor of opposite sign
     */
    public static Tensor negate(Tensor tensor) {
        if (tensor instanceof Complex)
            return ((Complex) tensor).negate();
        return multiply(Complex.MINUSE_ONE, tensor);
    }

    //TODO discuss with Stas (move multiplySumElementsOnFactor and multiplySumElementsOnFactorAndExpandScalars to other class)
    public static Tensor multiplySumElementsOnFactor(Sum sum, Tensor factor) {
        if (TensorUtils.isZero(factor))
            return Complex.ZERO;
        if (TensorUtils.isOne(factor))
            return sum;
        final Tensor[] newSumData = new Tensor[sum.size()];
        for (int i = newSumData.length - 1; i >= 0; --i)
            newSumData[i] = multiply(factor, sum.get(i));
        return new Sum(newSumData, IndicesFactory.createSorted(newSumData[0].getIndices().getFree()));
    }

    public static Tensor multiplySumElementsOnFactorAndExpandScalars(Sum sum, Tensor factor) {
        if (TensorUtils.isZero(factor))
            return Complex.ZERO;
        if (TensorUtils.isOne(factor))
            return sum;
        final Tensor[] newSumData = new Tensor[sum.size()];
        for (int i = newSumData.length - 1; i >= 0; --i)
            newSumData[i] = Expand.expand(multiply(factor, sum.get(i)));
        return new Sum(newSumData, IndicesFactory.createSorted(newSumData[0].getIndices().getFree()));
    }

    //TODO discuss with Stas (move setIndicesToSimpleTensor and setIndicesToField to other class, may be into SimpelTensor class) ??
    public static TensorField setIndicesToField(TensorField field, SimpleIndices newIndices) {
        NameDescriptor descriptor = CC.getNameDescriptor(field.name);
        if (!descriptor.getIndicesTypeStructure().isStructureOf(newIndices))
            throw new IllegalArgumentException("Specified indices are not indices of specified tensor.");
        return new TensorField(field.name, newIndices, field.args, field.argIndices);
    }

    public static SimpleTensor setIndicesToSimpleTensor(SimpleTensor simpleTensor, SimpleIndices newIndices) {
        NameDescriptor descriptor = CC.getNameDescriptor(simpleTensor.name);
        if (!descriptor.getIndicesTypeStructure().isStructureOf(newIndices))
            throw new IllegalArgumentException("Specified indices are not indices of specified tensor.");
        return new SimpleTensor(simpleTensor.name, UnsafeIndicesFactory.createOfTensor(descriptor.getSymmetries(), newIndices));
    }
}
TOP

Related Classes of cc.redberry.core.tensor.Tensors

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.