/*
* 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.indices.InconsistentIndicesException;
import cc.redberry.core.context.CC;
import cc.redberry.core.context.Context;
import cc.redberry.core.context.ToStringMode;
import cc.redberry.core.indices.IndicesBuilderSorted;
import java.util.Collection;
/**
* This class is a representation of product.
*
* @see Tensor
* @see MultiTensor
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*/
public final class Product extends MultiTensor {
private ProductContent content = null;
/**
* Constructs empty product with specified parent tensor.
*
* @param parent parent tensor
*/
public Product(Tensor parent) {
this.parent = parent;
}
/**
* Constructs empty product with {@link CC#getRootParentTensor() } as parent
* tensor.
*
*/
public Product() {
this(CC.getRootParentTensor());
}
/**
* Constructs product from specified collection and with specified parent
* tensor
*
* @param tensors specified collection of tensors
* @param parent parent tensor
*/
public Product(Collection<? extends Tensor> tensors, Tensor parent) {
this.parent = parent;
for (Tensor tensor : tensors)
add(tensor);
}
/**
* Constructs product from specified collection and with
* {@link CC#getRootParentTensor() } as parent tensor.
*
* @param tensors specified collection of tensors
*/
public Product(Collection<? extends Tensor> tensors) {
this(tensors, Context.get().getRootParentTensor());
}
/**
* Constructs product of specified tensors with specified parent tensor.
*
* @param tensors multipliers
* @param parent tensor
*/
public Product(Tensor[] tensors, Tensor parent) {
this.parent = parent;
for (Tensor t : tensors)
add(t);
}
/**
* Constructs product of two specified tensors with
* {@link CC#getRootParentTensor() } as parent tensor.
*
* @param tensors multipliers
*/
public Product(Tensor... tensors) {
this(tensors, Context.get().getRootParentTensor());
}
@Override
public ProductContent getContent() {
if (content == null)
content = ProductContentImpl.create(false, getIndices(), getElements().toArray(new Tensor[size()]));
return content;
}
@Override
public void update() {
content = null;
super.update();
}
@Override
protected void calculateHash() {
hash = 0;
int numbers = 0;
for (Tensor t : getElements())
if ((t instanceof TensorNumber))
++numbers;
else//TODO comment
hash ^= t.hash();
hashUptodate = true;
if (size() - numbers <= 1)
return;
hash = hash * 31 ^ getContent().getContractionStructure().hashCode();
}
@Override
String toString(ToStringMode mode, Class<? extends Tensor> clazz) {
if (clazz == Fraction.class)
return "(" + toString(mode) + ")";
return toString(mode);
}
/**
* Returns {@code getElements().get(0)} if size of this product equals one,
* throws {@code IllegalStateException} if size of this product equals zero,
* and returns this in other case.
*
* @return {@code getElements().get(0)} if size of this product equals one,
* throws {@code IllegalStateException} if size of this product equals zero,
* and this in other case
*
* @throws IllegalStateException if size == 0
*/
@Override
public Tensor equivalent() {
switch (getElements().size()) {
case 0:
throw new IllegalStateException();
case 1:
return getElements().get(0);
}
return this;
}
/**
* {@inheritDoc}
*/
@Override
public Product clone() {
Product p = new Product();
for (Tensor t : this)
p.add(t.clone());
if (this.indices != null)
p.indices = this.indices.clone();
p.hashUptodate = hashUptodate;
if (hashUptodate)
p.hash = this.hash;
return p;
}
/**
* {@inheritDoc}
*/
@Override
protected char getSymbol() {
return '*';
}
/**
* {@inheritDoc}
*/
@Override
protected void updateIndices() {
IndicesBuilderSorted ib = new IndicesBuilderSorted();
for (Tensor t : this)
ib.append(t.getIndices());
try {
indices = ib.getIndices();
} catch (InconsistentIndicesException ex) {
//Adding information about source tensor
throw new InconsistentIndicesException(ex, this);
}
}
}