/*
 * Redberry: symbolic tensor computations.
 *
 * Copyright (c) 2010-2015:
 *   Stanislav Poslavsky   
 *   Bolotin Dmitriy       
 *
 * 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 .
 */
package cc.redberry.core.tensor;

import cc.redberry.core.indices.Indices;
import cc.redberry.core.indices.IndicesFactory;
import cc.redberry.core.number.Complex;
import cc.redberry.core.utils.TensorHashCalculator;
import cc.redberry.core.utils.TensorUtils;
import gnu.trove.map.hash.TIntObjectHashMap;

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

import static cc.redberry.core.transformations.ToNumericTransformation.toNumeric;

/**
 * Abstract implementation of {@link TensorBuilder} for sums.
 *
 * @author Dmitry Bolotin
 * @author Stanislav Poslavsky
 * @since 1.0
 */
public abstract class AbstractSumBuilder implements TensorBuilder {

    final TIntObjectHashMap> summands;
    Complex complex = Complex.ZERO;
    Indices indices = null;
    int[] sortedFreeIndices;

    /**
     * Creates builder with default initial capacity.
     */
    public AbstractSumBuilder() {
        this(7);
    }

    /**
     * Creates builder with specified initial capacity.
     *
     * @param initialCapacity initial capacity
     */
    public AbstractSumBuilder(int initialCapacity) {
        summands = new TIntObjectHashMap<>(initialCapacity);
    }

    AbstractSumBuilder(TIntObjectHashMap> summands, Complex complex, Indices indices, int[] sortedFreeIndices) {
        this.summands = summands;
        this.complex = complex;
        this.indices = indices;
        this.sortedFreeIndices = sortedFreeIndices;
    }

    @Override
    public Tensor build() {
        if (complex.isNaN() || complex.isInfinite())
            return complex;

        List sum = new ArrayList<>();

        final boolean isNumeric = complex.isNumeric();
        for (List nodes : summands.valueCollection())
            for (FactorNode node : nodes) {
                if (isNumeric) {
                    Tensor summand = Tensors.multiply(toNumeric(node.build()), toNumeric(node.factor));
                    if (summand instanceof Complex)
                        complex = complex.add((Complex) summand);
                    else
                        sum.add(summand);
                } else {
                    Tensor summand = Tensors.multiply(node.build(), node.factor);
                    if (!TensorUtils.isZero(summand))
                        sum.add(summand);
                }
            }

        if (sum.isEmpty())
            return complex;

        if (!complex.isZero())
            sum.add(complex);

        if (sum.size() == 1)
            return sum.get(0);

        return new Sum(sum.toArray(new Tensor[sum.size()]), indices);
    }

    protected abstract Split split(Tensor tensor);

    @Override
    public void put(Tensor tensor) {
        if (complex.isNaN())
            return;
        if (complex.isNumeric())
            tensor = toNumeric(tensor);
        if (TensorUtils.isZero(tensor))
            return;
        if (TensorUtils.isIndeterminate(tensor)) {
            complex = complex.add((Complex) tensor);
            return;
        }
        if (complex.isInfinite()) {
            if (tensor instanceof Complex)
                complex.add((Complex) tensor);
            return;
        }
        if (indices == null) {
            indices = IndicesFactory.create(tensor.getIndices().getFree());
            sortedFreeIndices = indices.getAllIndices().copy();
            Arrays.sort(sortedFreeIndices);
        } else if (!indices.equalsRegardlessOrder(tensor.getIndices().getFree()))
            throw new TensorException("Inconsistent indices in sum. " +
                    "Expected: " + indices + " Actual: " + tensor.getIndices().getFree(), tensor);//TODO improve message
        if (tensor instanceof Sum) {
            for (Tensor s : tensor)
                put(s);
            return;
        }
        if (tensor instanceof Complex) {
            complex = complex.add((Complex) tensor);
            return;
        }

        Split split = split(tensor);

        Integer hash = TensorHashCalculator.hashWithIndices(split.factor, sortedFreeIndices);//=split.factor.hashCode();
        List factorNodes = summands.get(hash);
        if (factorNodes == null) {
            List fns = new ArrayList<>();
            fns.add(new FactorNode(split.factor, split.getBuilder()));
            summands.put(hash, fns);
        } else {
            Boolean b = null;
            for (FactorNode node : factorNodes)
                if ((b = compareFactors(split.factor, node.factor)) != null) {
                    if (b)
                        node.put(Tensors.negate(split.summand), split.factor);
                    else
                        node.put(split.summand, split.factor);
                    break;
                }
            if (b == null)
                factorNodes.add(new FactorNode(split.factor, split.getBuilder()));
        }
    }

    @Override
    public abstract TensorBuilder clone();

    static Boolean compareFactors(Tensor u, Tensor v) {
        return TensorUtils.compare1(u, v);
//        IndexMappingBuffer buffer;
//        if (u.getIndices().size() == 0) <- getFree() !!!
//            buffer = IndexMappings.createPort(u, v).take();
//        else {
//            int[] fromIndices = u.getIndices().getFree().getAllIndices().copy();
//            for (int i = 0; i < fromIndices.length; ++i)
//                fromIndices[i] = IndicesUtils.getNameWithType(fromIndices[i]);
//            buffer = IndexMappings.createPort(new IndexMappingBufferTester(fromIndices, false), u, v).take();
//        }
//        if (buffer == null)
//            return null;
//        assert buffer.isEmpty();
//        return buffer.getSignum();
    }

//    @Override
//    public String toString() {
//        return clone().build().toString();
//    }
}

 

Ads help maintain this website.