/*
* 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.Indices;
import cc.redberry.core.indices.IndicesBuilderSorted;
import cc.redberry.core.indices.IndicesFactory;
import cc.redberry.core.parser.StringDefaults;
import cc.redberry.core.utils.ArraysUtils;
import cc.redberry.core.utils.Indicator;
import java.util.Arrays;
/**
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*/
public final class Derivative extends Tensor {
// First element is target.
private Tensor[] data;
private ProductContent content;
private Indices indices;
Derivative(Tensor[] data) {
this.parent = Context.get().getRootParentTensor();
this.data = data;
setDataParent();
}
private Derivative(Tensor target, SimpleTensor[] variations, Tensor parent) {
data = new Tensor[variations.length + 1];
data[0] = target;
System.arraycopy(variations, 0, data, 1, variations.length);
testConsistent();
this.parent = parent;
setDataParent();
}
private void setDataParent() {
for (Tensor t : data)
t.setParent(this);
}
private void testConsistent() {
IndicesBuilderSorted ib = new IndicesBuilderSorted();
ib.append(data[0].getIndices().getFreeIndices());
for (int i = 1; i < data.length; ++i)
ib.append(data[i].getIndices());
Indices indices = ib.getIndices();
if (indices.size() == 0)
return;
if (CC.getRegim() == Context.Regim.TESTING)
return;
try {
indices.testConsistentWithException();
} catch (InconsistentIndicesException ex) {
//Adding information about source tensor
throw new InconsistentIndicesException(ex, this);
}
}
@Override
public Tensor clone() {
Tensor[] newData = new Tensor[data.length];
for (int i = 0; i < data.length; ++i)
newData[i] = data[i].clone();
return new Derivative(newData);
}
public Tensor getTarget() {
return data[0];
}
public Tensor[] getVars() {
return Arrays.copyOfRange(data, 1, data.length);
}
public SimpleTensor getVariation(int index) {
return (SimpleTensor) data[index + 1];
}
public int getDerivativeOrder() {
return data.length - 1;
}
@Override
public void update() {
content = null;
indices = null;
super.update();
}
@Override
public ProductContent getContent() {
if (content == null)
content = ProductContentImpl.create(true, getIndices(), Arrays.copyOf(data, data.length));
return content;
}
@Override
public Indices getIndices() {
if (indices == null) {
IndicesBuilderSorted ib = new IndicesBuilderSorted();
for (int i = 0; i < data.length; ++i)
ib.append(data[i].getIndices());
indices = ib.getIndices();
}
return indices;
}
@Override
protected int hash() {
return 71 * data[0].hashCode() + ArraysUtils.commutativeHashCode(data, 1, data.length);
}
@Override
@SuppressWarnings("fallthrough")
public String toString(ToStringMode mode) {
StringBuilder sb = new StringBuilder();
char delta = (char) 0x03b1 + 3;
switch (mode) {
case LaTeX:
for (int i = 1; i < data.length; ++i)
sb.append("\\frac{\\delta}{\\delta ").append(toStringInv((SimpleTensor) data[i], mode)).append("}");
break;
case REDBERRY_SOUT:
case REDBERRY:
sb.append(StringDefaults.get(Derivative.class)).append("[").append(data[0].toString(mode)).append(',');
for (int i = 1; i < data.length; ++i)
sb.append(toStringInv((SimpleTensor) data[i], mode)).append(',');
sb.deleteCharAt(sb.length() - 1).append(']');
return sb.toString();
default:
for (int i = 1; i < data.length; ++i)
sb.append(delta).append("/").append(delta).append("(").append(toStringInv((SimpleTensor) data[i], mode)).append(")");
}
if (data[0] instanceof SimpleTensor)
sb.append(data[0].toString(mode));
else
sb.append("(").append(data[0].toString(mode)).append(")");
return sb.toString();
}
private static String toStringInv(SimpleTensor st, ToStringMode mode) {
StringBuilder sb = new StringBuilder();
sb.append(CC.getNameDescriptor(st.name).getName());
sb.append(st.indices.getInverseIndices().toString(mode));
return sb.toString();
}
public static Indicator<TensorIterator> DerivativeIteratorIndicator(final Indicator<Derivative> indicator) {
if (indicator == null)
return derivativeIteratorIndicator;
return new AbstractTensorIteratorIndicator() {
@Override
public boolean _is(TensorIterator object) {
return (object instanceof DerivativeIterator) && indicator.is(((DerivativeIterator) object).derivative());
}
};
}
public static final Indicator<TensorIterator> onVarsIndicator = new AbstractTensorIteratorIndicator() {
@Override
public boolean _is(TensorIterator object) {
return (object instanceof DerivativeIterator) && ((DerivativeIterator) object).isOnVars();
}
};
public static final Indicator<TensorIterator> onTargetIndicator = new AbstractTensorIteratorIndicator() {
@Override
public boolean _is(TensorIterator object) {
return (object instanceof DerivativeIterator) && ((DerivativeIterator) object).isOnTarget();
}
};
public static final Indicator<TensorIterator> derivativeIteratorIndicator = new AbstractTensorIteratorIndicator() {
@Override
public boolean _is(TensorIterator object) {
return object instanceof DerivativeIterator;
}
};
@Override
public TensorIterator iterator() {
return new DerivativeIterator();
}
private class DerivativeIterator extends AbstractTensorIterator {
private int index = -1;
boolean isOnTarget() {
return index == 0;
}
boolean isOnVars() {
return index > 0;
}
@Override
public void set(Tensor t) {
if (index > 0 && (t.getClass() != SimpleTensor.class))
throw new RuntimeException();
t.parent = Derivative.this;
data[index] = t;
update();
}
@Override
public boolean hasNext() {
return index < data.length - 1;
}
@Override
public Tensor next() {
return data[++index];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
public Derivative derivative() {
return Derivative.this;
}
}
public static Derivative create(Tensor target, SimpleTensor[] variations, Tensor parent) {
SimpleTensor[] arr = new SimpleTensor[variations.length];
for (int i = 0; i < arr.length; ++i)
//TODO make factory methods for SimpleTensor
arr[i] = new SimpleTensor(variations[i].name, IndicesFactory.createSimple(variations[i].indices.getInverseIndices()));
return new Derivative(target, arr, parent);
}
public static Derivative create(Tensor target, SimpleTensor... variations) {
return create(target, variations, CC.getRootParentTensor());
}
public static Derivative createFromInversed(Tensor target, SimpleTensor[] variations, Tensor parent) {
return new Derivative(target, variations, parent);
}
public static Derivative createFromInversed(Tensor target, SimpleTensor... variations) {
return new Derivative(target, variations, CC.getRootParentTensor());
}
}