Package cc.redberry.core.indexmapping

Source Code of cc.redberry.core.indexmapping.IndexMappings

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

import cc.redberry.core.utils.OutputPort;
import cc.redberry.core.indices.Indices;
import cc.redberry.core.indices.IndicesUtils;
import cc.redberry.core.number.Complex;
import cc.redberry.core.tensor.*;
import cc.redberry.core.tensor.functions.*;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* Central public facade of this package. Provides static methods for calculation of mappings between indices.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @since 1.0
*/
public final class IndexMappings {

    private IndexMappings() {
    }

    /**
     * Creates output port of mappings from tensor <i>{@code from}</i> onto tensor <i>{@code to}</i>.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return output port of mappings
     */
    public static MappingsPort createPort(Tensor from, Tensor to) {
        return new MappingsPort(createPortOfBuffers(new IndexMappingBufferImpl(), from, to));
    }

    /**
     * Creates output port of mappings of two simple tensors and does not take into account the arguments of fields.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return port of mappings of indices
     */
    public static MappingsPort simpleTensorsPort(SimpleTensor from, SimpleTensor to) {
        final IndexMappingProvider provider = ProviderSimpleTensor.FACTORY_SIMPLETENSOR.create(IndexMappingProvider.Util.singleton(new IndexMappingBufferImpl()), from, to);
        provider.tick();
        return new MappingsPort(new MappingsPortRemovingContracted(provider));
    }

    /**
     * Creates output port of mappings of two products of tensors represented as arrays of multipliers, where
     * each multiplier of {@code from} will be mapped on the multiplier of {@code to} at the same
     * position. Such ordering can be obtained via {@link cc.redberry.core.transformations.substitutions.ProductsBijectionsPort}.
     * In contrast to {@link #createPortOfBuffers(cc.redberry.core.tensor.Tensor, cc.redberry.core.tensor.Tensor)}, this method
     * will fully handles mappings of free indices on contracted ones (like e.g. _i^j -> _k^k).
     *
     * @param from from tensor
     * @param to   to tensor
     * @return port of mappings of indices
     */
    public static MappingsPort createBijectiveProductPort(Tensor[] from, Tensor[] to) {
        if (from.length != to.length)
            throw new IllegalArgumentException("From length != to length.");
        if (from.length == 0)
            return new MappingsPort(IndexMappingProvider.Util.singleton(new IndexMappingBufferImpl()));
        if (from.length == 1)
            return new MappingsPort(createPortOfBuffers(from[0], to[0]));
        return new MappingsPort(
                new MappingsPortRemovingContracted(
                        new SimpleProductMappingsPort(IndexMappingProvider.Util.singleton(new IndexMappingBufferImpl()), from, to)));
    }


    /**
     * Returns the first mapping of tensor {@code from} on tensor {@code to}.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return mapping of indices of tensor {@code from} on tensor {@code to}
     */
    public static Mapping getFirst(Tensor from, Tensor to) {
        IndexMappingBuffer buffer = createPortOfBuffers(from, to).take();
        if (buffer == null) return null;
        return new Mapping(buffer);
    }

    /**
     * Tests whether specified mapping is a mapping from <i>{@code from}</i> tensor onto <i>{@code to}</i> tensor.
     *
     * @param mapping mapping
     * @param from    tensor <i>{@code from}</i>
     * @param to      tensor <i>{@code to}</i>
     * @return {@code true} if specified mapping is a mapping from <i>{@code from}</i> tensor onto
     *         <i>{@code to}</i> tensor and {@code false} in other case.
     */
    public static boolean testMapping(Mapping mapping, Tensor from, Tensor to) {
        return IndexMappingBufferTester.test(new IndexMappingBufferTester(mapping), from, to);
    }


    /**
     * Returns {@code true} if there is mapping from {@code a} on tensor {@code b} or vice versa.
     *
     * @param a tensor
     * @param b tensor
     * @return {@code true} if there is mapping from {@code a} on tensor {@code b} or vice versa
     */
    public static boolean anyMappingExists(Tensor a, Tensor b) {
        return mappingExists(a, b) || mappingExists(b, a);
    }

    /**
     * Returns {@code true} if there is mapping of tensor {@code from} on tensor {@code to}.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return {@code true} if there is mapping of tensor {@code from} on tensor {@code to}
     */
    public static boolean mappingExists(Tensor from, Tensor to) {
        return getFirstBuffer(from, to) != null;
    }

    /**
     * Returns {@code true} if there is positive mapping of tensor {@code from} on tensor {@code to}.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return {@code true} if there is positivemapping of tensor {@code from} on tensor {@code to}
     */
    public static boolean positiveMappingExists(Tensor from, Tensor to) {
        IndexMappingBuffer buffer;
        OutputPort<IndexMappingBuffer> port = createPortOfBuffers(from, to);
        while ((buffer = port.take()) != null)
            if (!buffer.getSign())
                return true;
        return false;
    }


    /**
     * Returns {@code true} if tensor u mathematically (not programming) equals to tensor v.
     *
     * @param u tensor
     * @param v tensor
     * @return {@code true} if specified tensors are mathematically (not programming) equal
     */
    public static boolean equals(Tensor u, Tensor v) {
        if (u == v)
            return true;
        Indices freeIndices = u.getIndices().getFree();
        if (!freeIndices.equalsRegardlessOrder(v.getIndices().getFree()))
            return false;
        int[] free = freeIndices.getAllIndices().copy();
        IndexMappingBuffer tester = new IndexMappingBufferTester(free, false);
        OutputPort<IndexMappingBuffer> mp = IndexMappings.createPortOfBuffers(tester, u, v);
        IndexMappingBuffer buffer;

        while ((buffer = mp.take()) != null)
            if (!buffer.getSign())
                return true;

        return false;
    }

    /**
     * Returns {@code true} if tensor u mathematically (not programming) equals to tensor v,
     * {@code false} if they they differ only in the sign and {@code null} otherwise.
     *
     * @param u tensor
     * @param v tensor
     * @return {@code true} {@code true} if tensor u mathematically (not programming) equals to tensor v,
     *         {@code false} if they they differ only in the sign and {@code null} otherwise
     */
    public static Boolean compare1(Tensor u, Tensor v) {
        Indices freeIndices = u.getIndices().getFree();
        if (!freeIndices.equalsRegardlessOrder(v.getIndices().getFree()))
            return null;
        int[] free = freeIndices.getAllIndices().copy();
        IndexMappingBuffer tester = new IndexMappingBufferTester(free, false);
        IndexMappingBuffer buffer = IndexMappings.createPortOfBuffers(tester, u, v).take();
        if (buffer == null)
            return null;
        return buffer.getSign();
    }

    /**
     * Returns {@code true} if specified tensor is zero in consequence of its symmetries: is both symmetric and
     * asymmetric with respect to some permutation at the same time.
     *
     * @param t tensor
     * @return {@code true} if specified tensor is zero in consequence of its symmetries
     */
    public static boolean isZeroDueToSymmetry(Tensor t) {
        int[] indices = IndicesUtils.getIndicesNames(t.getIndices().getFree());
        IndexMappingBufferTester bufferTester = new IndexMappingBufferTester(indices, false);
        OutputPort<IndexMappingBuffer> mp = IndexMappings.createPortOfBuffers(bufferTester, t, t);
        IndexMappingBuffer buffer;
        while ((buffer = mp.take()) != null)
            if (buffer.getSign())
                return true;
        return false;
    }

    /**
     * Returns a set of all possible mappings of tensor {@code from} on tensor {@code to}.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return a set of all possible mappings of tensor {@code from} on tensor {@code to}
     */
    public static Set<Mapping> getAllMappings(Tensor from, Tensor to) {
        return getAllMappings(IndexMappings.createPort(from, to));
    }

    private static Set<Mapping> getAllMappings(OutputPort<Mapping> opu) {
        Set<Mapping> res = new HashSet<>();
        Mapping c;
        while ((c = opu.take()) != null)
            res.add(c);
        return res;
    }

    /* *
     * *
     * * Non public methods
     * *
     * */

    /**
     * Creates output port of mappings of tensor {@code from} on tensor {@code to}.
     *
     * @param from from tensor
     * @param to   to tensor
     * @return output port of mappings
     */
    static OutputPort<IndexMappingBuffer> createPortOfBuffers(Tensor from, Tensor to) {
        return createPortOfBuffers(new IndexMappingBufferImpl(), from, to);
    }

    /**
     * Creates output port of mappings of tensor {@code from} on tensor {@code to} with specified
     * mappings rules defined in specified {@link IndexMappingBuffer}.
     *
     * @param buffer initial mapping rules
     * @param from   from tensor
     * @param to     to tensor
     * @return output port of mapping
     */
    static OutputPort<IndexMappingBuffer> createPortOfBuffers(final IndexMappingBuffer buffer,
                                                                    final Tensor from, final Tensor to) {
        final IndexMappingProvider provider = createPort(IndexMappingProvider.Util.singleton(buffer), from, to);
        provider.tick();
        return new MappingsPortRemovingContracted(provider);
    }

    static IndexMappingBuffer getFirstBuffer(Tensor from, Tensor to) {
        return createPortOfBuffers(from, to).take();
    }

    private static Tensor extractNonComplexFactor(Tensor t) {
        Product p = (Product) t;
        if (p.getFactor().isMinusOne())
            return p.get(1);
        else
            return null;
    }

    /* Main routine */

    static IndexMappingProvider createPort(IndexMappingProvider opu, Tensor from, Tensor to) {
        if (from.hashCode() != to.hashCode())
            return IndexMappingProvider.Util.EMPTY_PROVIDER;

        if (from.getClass() != to.getClass()) {

            Tensor nonComplex;
            //Processing case -2*(1/2)*g_mn -> g_mn
            if (from instanceof Product && !(to instanceof Product)) {
                if (from.size() != 2)
                    return IndexMappingProvider.Util.EMPTY_PROVIDER;

                if ((nonComplex = extractNonComplexFactor(from)) != null)
                    return new MinusIndexMappingProviderWrapper(createPort(opu, nonComplex, to));
                return IndexMappingProvider.Util.EMPTY_PROVIDER;
            }

            //Processing case g_mn -> -2*(1/2)*g_mn
            if (to instanceof Product && !(from instanceof Product)) {
                if (to.size() != 2)
                    return IndexMappingProvider.Util.EMPTY_PROVIDER;
                if ((nonComplex = extractNonComplexFactor(to)) != null)
                    return new MinusIndexMappingProviderWrapper(createPort(opu, from, nonComplex));
                return IndexMappingProvider.Util.EMPTY_PROVIDER;
            }

            return IndexMappingProvider.Util.EMPTY_PROVIDER;
        }

        IndexMappingProviderFactory factory = map.get(from.getClass());
        if (factory == null)
            throw new RuntimeException("Unsupported tensor type: " + from.getClass());

        return factory.create(opu, from, to);
    }

    private static final Map<Class, IndexMappingProviderFactory> map;

    static {
        map = new HashMap<>();
        map.put(SimpleTensor.class, ProviderSimpleTensor.FACTORY_SIMPLETENSOR);
        map.put(TensorField.class, ProviderSimpleTensor.FACTORY_TENSORFIELD);
        map.put(Product.class, ProviderProduct.FACTORY);
        map.put(Sum.class, ProviderSum.FACTORY);
        map.put(Expression.class, ProviderSum.FACTORY);
        map.put(Complex.class, ProviderComplex.FACTORY);
        map.put(Power.class, ProviderPower.INSTANCE);

        map.put(Sin.class, ProviderFunctions.ODD_FACTORY);
        map.put(ArcSin.class, ProviderFunctions.ODD_FACTORY);
        map.put(Tan.class, ProviderFunctions.ODD_FACTORY);
        map.put(ArcTan.class, ProviderFunctions.ODD_FACTORY);

        map.put(Cos.class, ProviderFunctions.EVEN_FACTORY);
        map.put(ArcCos.class, ProviderFunctions.EVEN_FACTORY);
        map.put(Cot.class, ProviderFunctions.EVEN_FACTORY);
        map.put(ArcCot.class, ProviderFunctions.EVEN_FACTORY);

        map.put(Log.class, ProviderFunctions.FACTORY);
    }
}
TOP

Related Classes of cc.redberry.core.indexmapping.IndexMappings

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.