/*
* 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 java.util.Collection;
import cc.redberry.core.context.CC;
import cc.redberry.core.context.Context;
import cc.redberry.core.context.ToStringMode;
import cc.redberry.core.indices.EmptyIndices;
import cc.redberry.core.indices.Indices;
import cc.redberry.core.indices.IndicesFactory;
import cc.redberry.core.utils.HashFunctions;
/**
* This class is the representation of sum.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @see Tensor
* @see MultiTensor
*/
public final class Sum extends MultiTensor {
private TensorSortedContent content;
/**
* Constructs empty sum with specified parent tensor.
*
* @param parent parent tensor
*/
public Sum(Tensor parent) {
this.parent = parent;
}
/**
* Constructs empty sum with {@link CC#getRootParentTensor() } as parent
* tensor.
*/
public Sum() {
this(Context.get().getRootParentTensor());
}
/**
* Constructs sum from specified collection and with specified parent tensor
*
* @param tensors specified collection of tensors
* @param parent parent tensor
*/
public Sum(Collection<? extends Tensor> tensors, Tensor parent) {
this.parent = parent;
for (Tensor tensor : tensors)
add(tensor);
}
/**
* Constructs sum from specified collection and with
* {@link CC#getRootParentTensor() } as parent tensor.
*
* @param tensors specified collection of tensors
*/
public Sum(Collection<? extends Tensor> tensors) {
this(tensors, Context.get().getRootParentTensor());
}
/**
* Constructs sum of two specified tensors with
* {@link CC#getRootParentTensor() } as parent tensor.
*
* @param tensor1 first summand
* @param tensor2 second summand
*/
public Sum(Tensor tensor1, Tensor tensor2) {
this.parent = CC.getRootParentTensor();
add(tensor1);
add(tensor2);
}
/**
* {@inheritDoc}
*/
@Override
protected char getSymbol() {
return '+';
}
@Override
protected void calculateHash() {
hash = 0;
for (Tensor t : getElements())
hash ^= t.hash();
hash = HashFunctions.JenkinWang32shift(hash);
hashUptodate = true;
}
@Override
String toString(ToStringMode mode, Class<? extends Tensor> clazz) {
if (clazz == Product.class || clazz == Fraction.class)
return "(" + toString(mode) + ")";
return toString(mode);
}
/**
* Returns implementation of {@code TensorSortedContentWithDataImpl}.
*
* @return implementation of {@code TensorSortedContentWithDataImpl}
* @see TensorSortedContentWithDataImpl
*/
@Override
public TensorSortedContent getContent() {
if (content == null)
content = new TensorSortedContentImpl(false, getElements().toArray(new Tensor[size()]));
return content;
}
@Override
public void update() {
content = null;
super.update();
}
/**
* {@inheritDoc}
*/
@Override
public Sum clone() {
Sum s = new Sum();
for (Tensor t : this)
s.add(t.clone());
if (this.indices != null)
s.indices = this.indices.clone();
s.hashUptodate = hashUptodate;
if (hashUptodate)
s.hash = this.hash;
return s;
}
/**
* Returns zero if size of this sum equals zero, {@code getElements().get(0)}
* if size of this sum equals one, and returns this in other case.
*
* @return zero if size of this sum equals zero, {@code getElements().get(0)}
* if size of this sum equals one, and returns this in other case
*/
@Override
public Tensor equivalent() {
switch (getElements().size()) {
case 0:
return TensorNumber.createZERO(parent);
case 1:
return getElements().get(0);
}
return this;
}
@Override
protected void updateIndices() {
indices = IndicesFactory.createSorted(getElements().get(0).getIndices().getFreeIndices());
testConsistent();
}
private void testConsistent() {
boolean isSymbol = (indices instanceof EmptyIndices);
boolean b = true;
for (Tensor t : this) {
Indices ind = t.getIndices().getFreeIndices();
if (!indices.equalsIgnoreOrder(ind))
b = false;
// Take care if sum e.g. a+h^i_i that indices will not be EmptyIndices (sum is not symbol)
if (isSymbol && !(ind instanceof EmptyIndices)) {
isSymbol = false;
indices = ind;
}
}
if (!b)
throw new TensorException("Different free indices of summands", this);
}
}