/*
* 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.context.CC;
import cc.redberry.core.context.ToStringMode;
import cc.redberry.core.indices.EmptyIndices;
import cc.redberry.core.indices.Indices;
import cc.redberry.core.number.ComplexElement;
import cc.redberry.core.number.RationalElement;
import cc.redberry.core.tensor.iterators.EmptyTensorIterator;
/**
* This class represents tensors, witch are actually numbers. Redberry allows to
* manipulate with complex rational numbers. In fact, this class contains only
* one field - value, witch is, in general, complex rational number.
* {@code TensorNumber} returns {@link EmptyIndices} instance as its indices,
* {@link EmptyTensorIterator} instance as its tensor iterator and
* {@link TensorContent#EMPTY} instance as its tensor content.
*
* <p> Complex value of this tensor is keeping in simplified form, and all common
* number operations (adding, multiplying etc.) acting on this, are automatically
* simplifies this. For example, if this equals 2/5 and we multiply this on 10/3,
* the result for this will be 4/3. For more information see
* {@code ComplexElement}.
*
* @see Tensor
* @see ComplexElement
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*/
public class TensorNumber extends Tensor {
private ComplexElement value;
/**
* Constructs {@code TensorNumber} object with specified value and specified
* parent tensor,
*
* @param value complex element, value of this tensor
* @param parent parent tensor
*/
public TensorNumber(ComplexElement value, Tensor parent) {
this.value = value;
this.parent = parent;
}
/**
* Constructs {@code TensorNumber} object with specified value and
* {@link CC#getRootParentTensor()} as parent tensor
*
* @param value complex element, value of this tensor
*/
public TensorNumber(ComplexElement value) {
this(value, CC.getRootParentTensor());
}
/**
* Returns value of this tensor.
* @return value of this tensor
*/
public ComplexElement getValue() {
return value;
}
/**
* Adds specified number to this number.
* @param t specified number to add
*/
public void add(TensorNumber t) {
value = value.add(t.value);
update();
}
/**
* Multiplies this number on specified number.
* @param t specified number to multiply this
*/
public void multiply(TensorNumber t) {
value = value.multiply(t.value);
update();
}
/**
* Subtracts specified number from this number.
* @param t specified number from subtract
*/
public void subtract(TensorNumber t) {
value = value.subtract(t.value);
update();
}
/**
* Divides this number on specified number.
* @param t specified number to divide this
* @throws ArithmeticException if t is zero
*/
public void divide(TensorNumber t) {
value = value.divide(t.value);
update();
}
/**
* Negotiates this number
*/
public void negotiate() {
value = value.negotiate();
update();
}
/**
* Returns true, if this number is one, and false if not.
* @return true, if this number is one, and false if not
*/
public boolean isOne() {
return value.isOne();
}
/**
* Returns true, if this number is zero, and false if not.
* @return true, if this number is zero, and false if not
*/
public boolean isZero() {
return value.isZero();
}
/**
* {@inheritDoc}
*
*/
@Override
public TensorNumber clone() {
//values are immutable, so we do not need clone value
return new TensorNumber(value);
}
/**
* Returns empty indices instance.
* @return empty indices instance
*/
@Override
public Indices getIndices() {
return EmptyIndices.INSTANCE;
}
/**
* Returns empty content instance.
* @return empty content instance
*/
@Override
public TensorContent getContent() {
return TensorContent.EMPTY;
}
public boolean factorOutSign() {
if (value.getReal().isNegotive()) {
value = value.negotiate();
update();
return true;
}
if (value.getReal().isZero())
if (value.getImagine().isNegotive()) {
value = value.negotiate();
update();
return true;
}
return false;
}
/**
* Returns complex element hash code.
* @return complex element hash code
*/
@Override
public int hash() {
return value.hashCode();
}
/**
* Returns empty iterator instance.
* @return empty iterator instance
*/
@Override
public TensorIterator iterator() {
return EmptyTensorIterator.INSTANCE1;
}
/**
* Returns complex element string representation.
* @return complex element string representation
*/
@Override
public String toString(ToStringMode mode) {
return value.toString();
}
@Override
String toString(ToStringMode mode, Class<? extends Tensor> clazz) {
if (clazz == Product.class
&& (value.getMode() == ComplexElement.ComplexElementMode.COMPLEX
|| (value.getMode() == ComplexElement.ComplexElementMode.REAL && value.getReal().isNegotive())))
return "(" + toString(mode) + ")";
return toString(mode);
}
public static TensorNumber createONE() {
return new TensorNumber(ComplexElement.ONE);
}
public static TensorNumber createMINUSONE() {
return new TensorNumber(ComplexElement.MINUSONE);
}
public static TensorNumber createIMAGE_MINUSONE() {
return new TensorNumber(new ComplexElement(RationalElement.ZERO, RationalElement.MINUS_ONE));
}
public static TensorNumber createZERO() {
return new TensorNumber(ComplexElement.ZERO);
}
public static TensorNumber createZERO(Tensor parent) {
return new TensorNumber(ComplexElement.ZERO, parent);
}
public static TensorNumber createIMAGE_ONE() {
return new TensorNumber(ComplexElement.IMAGE_ONE);
}
}