Package cc.redberry.core.tensor

Source Code of cc.redberry.core.tensor.PowersContainer$PowerNode

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

import cc.redberry.core.number.Complex;
import cc.redberry.core.number.NumberUtils;
import cc.redberry.core.utils.EmptyIterator;
import cc.redberry.core.utils.TensorUtils;
import gnu.trove.function.TObjectFunction;
import gnu.trove.map.hash.TIntObjectHashMap;

import java.util.ArrayList;
import java.util.Iterator;

/**
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @since 1.0
*/
public final class PowersContainer implements Iterable<Tensor> {
    private boolean sign;
    private final TIntObjectHashMap<ArrayList<PowerNode>> powers;

    public PowersContainer() {
        this.powers = new TIntObjectHashMap<>();
    }

    public PowersContainer(int initialCapacity) {
        this.powers = new TIntObjectHashMap<>(initialCapacity);
    }

    private PowersContainer(TIntObjectHashMap<ArrayList<PowerNode>> powers, boolean sign) {
        this.powers = powers;
        this.sign = sign;
    }

    public boolean isSign() {
        return sign;
    }

    public boolean isEmpty() {
        return powers.isEmpty();
    }

    public int size() {
        return powers.size();
    }

    public void put(Tensor tensor) {
        Tensor base, exponent;
        if (tensor instanceof Power) {
            //case x^y
            base = tensor.get(0);
            exponent = tensor.get(1);
        } else {
            //case x^1 (= x)
            base = tensor;
            exponent = Complex.ONE;
        }

        int hash = base.hashCode();
        ArrayList<PowerNode> nodes = powers.get(hash);
        if (nodes == null)
            powers.put(hash, nodes = new ArrayList<>());
        for (PowerNode node : nodes) {
            Boolean compare = TensorUtils.compare1(node.base, base);
            if (compare == null)
                continue;

            if (compare == false) {
                //case base == node.base
                node.putExponent(exponent);
                return;
            }

            //at this point we know, that base == - power.base
            if (TensorUtils.isInteger(exponent)) {
                //exponent = 2*n
                //e.g. node.base = (a-b) node.exponent == x
                //          base = (b-a)      exponent == 2
                //then (a-b)**x * (b-a)**2 -> (a-b)**(x+2)
                node.putExponent(exponent);
                if (TensorUtils.isIntegerOdd(exponent))
                    //exponent = 2*n + 1
                    //e.g. node.base = (a-b) node.exponent == x
                    //          base = (b-a)      exponent == 3
                    //then (a-b)**x * (b-a)**3 -> -(a-b)**(x+3)
                    sign = !sign;
                return;
            }

            //at this point we know, that exponent is not integer
            if (node.exponent == null || node.exponent.summands.isEmpty()) {
                //node.exponent is number
                Complex exponent1 = node.exponent == null ? Complex.ONE : node.exponent.complex;
                if (exponent1.isInteger()) {
                    //node.exponent = 2*n
                    //e.g. node.base = (a-b) node.exponent == 2
                    //          base = (b-a)      exponent == x
                    //then (a-b)**2 * (b-a)**x -> (b-a)**(x+2)
                    node.base = base;
                    node.putExponent(exponent);
                    if (NumberUtils.isIntegerOdd(exponent1))
                        //node.exponent = 2*n+1
                        //e.g. node.base = (a-b) node.exponent == 3
                        //          base = (b-a)      exponent == x
                        //then (a-b)**3 * (b-a)**x -> -(b-a)**(x+3)
                        sign = !sign;
                    return;
                }
            }
        }
        //no similar powers were found
        nodes.add(new PowerNode(base, exponent));
    }

    public void putNew(Tensor base, Tensor exponent) {
        ArrayList<PowerNode> newNodes = new ArrayList<>();
        ArrayList<PowerNode> nodes = powers.putIfAbsent(base.hashCode(), newNodes);
        if (nodes != null) {
            nodes.add(new PowerNode(base, exponent));
        } else {
            newNodes.add(new PowerNode(base, exponent));
        }
    }

    @Override
    public Iterator<Tensor> iterator() {
        return new It();
    }

    private class It implements Iterator<Tensor> {
        private final Iterator<ArrayList<PowerNode>> lists = powers.valueCollection().iterator();
        @SuppressWarnings("unchecked")
        private Iterator<PowerNode> nodes = EmptyIterator.INSTANCE;

        @Override
        public boolean hasNext() {
            if (nodes.hasNext())
                return true;
            else if (!lists.hasNext())
                return false;
            nodes = lists.next().iterator();
            return hasNext();
        }

        @Override
        public Tensor next() {
            return nodes.next().build();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    }

    public PowersContainer clone() {
        TIntObjectHashMap<ArrayList<PowerNode>> newPowers = new TIntObjectHashMap<>(powers);
        newPowers.transformValues(copyPowers);
        return new PowersContainer(newPowers, sign);
    }

    private static final TObjectFunction<ArrayList<PowerNode>, ArrayList<PowerNode>> copyPowers
            = new TObjectFunction<ArrayList<PowerNode>, ArrayList<PowerNode>>() {
        @Override
        public ArrayList<PowerNode> execute(ArrayList<PowerNode> value) {
            ArrayList<PowerNode> newList = new ArrayList<>(value.size());
            for (PowerNode node : value)
                newList.add(node.clone());
            return newList;
        }
    };

    static final class PowerNode {
        private Tensor base;
        private SumBuilder exponent;

        PowerNode(Tensor base, Tensor exponent) {
            this.base = base;
            if (exponent == Complex.ONE)
                this.exponent = null;
            else {
                this.exponent = new SumBuilder();
                this.exponent.put(exponent);
            }
        }


        private PowerNode(SumBuilder exponent, Tensor base) {
            this.exponent = exponent;
            this.base = base;
        }

        void putExponent(Tensor exp) {
            if (exponent == null) {
                exponent = new SumBuilder();
                exponent.put(Complex.ONE);
            }
            exponent.put(exp);
        }

        Tensor build() {
            if (exponent == null)
                return base;
            return Tensors.pow(base, exponent.build());
        }

        public PowerNode clone() {
            return new PowerNode(exponent == null ? null : (SumBuilder) exponent.clone(), base);
        }
    }
}
TOP

Related Classes of cc.redberry.core.tensor.PowersContainer$PowerNode

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.