/*
* 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.NameManager;
import cc.redberry.core.context.ToStringMode;
import cc.redberry.core.indices.Indices;
import cc.redberry.core.indices.SimpleIndices;
import cc.redberry.core.indices.SimpleIndicesImpl;
import cc.redberry.core.tensor.iterators.EmptyTensorIterator;
/**
* This class describes the most fundamental tensor object - simple tensor, such
* as {@code A_{mn}}, etc. The class has two main fields - indices and name.
* <p/>
* <p><b>Indices</b> <br> Indices of {@code SimpleTensor} are always {@link SimpleIndicesImpl}.
* So, if you parse simple tensor {@code "A_{mnb}^{a}"}, the result tensor
* indices will be stored in that order, in witch they were in string. If we
* want to compare tensors e.g. {@code A_{mn}} and {@code A_{nm}}, the result
* will be true only if tensor {@code A_{mn}} is symmetric.
* <p/>
* <p><b>Name</b> <br>Name is an integer number, different for different
* tensors, and map between integer name and its string representation is
* keeping by
* {@link NameManager}, witch, in turn, are stored in {@code Context}. Integer
* name assignment procedure and putting it in Redberry namespace happens on
* parsing (for examples, see {@code NameManager}).
* {@code SimpleTensor} returns name value as its hash code. The specification
* is so, that two tensors are different (i.e. has different names) if their
* string names are different or their indices types structures are different.
* So, for example tensors: <BLOCKQUOTE>
* {@code A_{mn}} and {@code B_{mn}} - has different names; <br>{@code A_{mn}}
* and {@code A_{\\alpha b}} - has different names; <br>{@code A_{mn}} and {@code A_{abc}}
* - has different names; <br>{@code A_{mn}} and {@code A_{ab}} - has equals
* names; <br>{@code A_{mn}} and {@code A^{ab}} - has equals names;
* </BLOCKQUOTE> For more information about specification of name field see
* {@code NameManager}.
* <p/>
* <p> NOTE: It is highly recommended to use {@link CC#parse(java.lang.String)}
* to construct new simple tensor object, instead of using class constructors,
* witch can cause namespace conflicts or constructor exceptions.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @see Tensor
* @see Indices
* @see SimpleIndicesImpl
* @see NameManager
* @see Context
*/
public class SimpleTensor extends Tensor {
protected final SimpleIndices indices;
protected final int name;
/**
* Constructs {@code SimpleTensor} instance with given name, indices and
* parent tensor. In fact, this is the base constructor witch is using
* during parsing. Constructor invokes {@link Indices#testConsistent()}
* method and throws {@code InconsistentIndicesException} when specified
* indices are inconsistent and context regime not testing. <p> NOTE: It is
* highly recommended to use {@link CC#parse(java.lang.String)} to construct
* new simple tensor object, instead of using class constructors, witch can
* cause namespace conflicts or constructor exceptions.
*
* @param name integer tensor name representation
* @param indices indices of this tensor
* @param parent parent tensor
* @throws InconsistentIndicesException when specified indices are
* inconsistent and context regime not testing.
* @see Indices#testConsistent()
* @see Context#regim
*/
public SimpleTensor(int name, SimpleIndices indices, Tensor parent) {
this.indices = indices;
this.name = name;
this.parent = parent;
testConsistent();
this.indices.setSymmetries(CC.getNameDescriptor(name).getSymmetries());
}
private void testConsistent() {
try {
indices.testConsistentWithException();
} catch (InconsistentIndicesException ex) {
//Adding information about source tensor
throw new InconsistentIndicesException(ex, this);
}
}
/**
* Constructs {@code SimpleTensor} instance with given name, indices and
* {@link Context#getRootParentTensor()} as parent tensor. In fact, this is
* the base constructor witch is using during parsing. Constructor invokes {@link Indices#testConsistent()}
* method and throws {@code InconsistentIndicesException} when specified
* indices are inconsistent and context regime not testing <p> NOTE: It is
* highly recommended to use {@link CC#parse(java.lang.String)} to construct
* new simple tensor object, instead of using class constructors, witch can
* cause namespace conflicts or constructor exceptions.
*
* @param name integer tensor name representation
* @param indices indices of this tensor
* @throws InconsistentIndicesException when specified indices are
* inconsistent and context regime not testing.
* @see Indices#testConsistent()
* @see Context#regim
*/
public SimpleTensor(int name, SimpleIndices indices) {
this(name, indices, CC.getRootParentTensor());
}
/**
* This constructor is using in {@code clone()} method.
*
* @param name
* @param indices
* @param cloneConstructor
*/
protected SimpleTensor(int name, SimpleIndices indices, boolean cloneConstructor) {
this.name = name;
this.indices = indices;
this.parent = CC.getRootParentTensor();
}
/**
* Returns the name of this tensor.
*
* @return name of this tensor
*/
public int getName() {
return name;
}
/**
* Returns the name of this tensor
*
* @return name of this tensor
*/
@Override
protected int hash() {
return name;
// return HashFunctions.JenkinWang32shift(name);
}
/**
* Returns empty content, because {@code SimpleTensor} has no any content.
*
* @return {@link TensorContentImpl#EMPTY}
*/
@Override
public TensorContent getContent() {
return TensorContentImpl.EMPTY;
}
/**
* {@inheritDoc}
*
* @return {@inheritDoc}
*/
@Override
public SimpleIndices getIndices() {
return indices;
}
/**
* {@inheritDoc}
*
* @param mode {@inheritDoc}
* @return {@inheritDoc}
*/
@Override
public String toString(ToStringMode mode) {
StringBuilder sb = new StringBuilder();
sb.append(CC.getNameDescriptor(name).getName());
sb.append(indices.toString(mode));
return sb.toString();
}
/**
* {@inheritDoc}
*/
@Override
public SimpleTensor clone() {
return new SimpleTensor(name, indices.clone(), true);
}
/**
* Returns empty iterator instance.
*
* @return empty iterator instance
* @see EmptyTensorIterator
*/
@Override
public TensorIterator iterator() {
return EmptyTensorIterator.INSTANCE1;
}
}