/*
* 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.context;
import cc.redberry.core.combinatorics.Symmetry;
import cc.redberry.core.indices.*;
import cc.redberry.core.parser.Parser;
import cc.redberry.core.tensor.*;
import java.util.Arrays;
public final class Context {
private final Parser parser;
private final IndexConverterManager symbolConverter;
private final NameManager nameManager;
public static enum Regim {
TESTING,
NORMAL
}
//Bindings defaults
private final ToStringMode defaultPrintMode;
private final String imageOne;
private final String kroneckerName;
//Optional defaults
private final String metricName;
private final byte[] metricTypes;
private volatile int[] metricNames, kroneckerNames;
private volatile Regim regim;
private final String workingFolder;
private final String mapleDirectory;
public Context(ContextSettings contextSettings) {
//Bindings
imageOne = contextSettings.getImageOne();
defaultPrintMode = contextSettings.getDefaultToStringMode();
kroneckerName = contextSettings.getKronecker();
//Optional
regim = contextSettings.getRegim();
metricName = contextSettings.getMetricName();
//Creating parser
parser = new Parser(contextSettings.getParsers());
//Creating symbol converter
symbolConverter = new IndexConverterManager(contextSettings.getConverters());
metricTypes = contextSettings.getMetricTypes();
nameManager = new NameManager(this, contextSettings.getNameManagerSeed());
nameManager.registerNewNameDescriptorListener(new MetricKroneckerListener());
workingFolder = contextSettings.getWorkingFolder();
mapleDirectory = contextSettings.getMapleDirectory();
}
/**
* This method resets all tensor names.
* <p/>
* <br/><b>Any tensor created before this method call becomes invalid, and
* must not be used!</b> <br/><br/>Mainly this method used in unit tests, so
* avoid using this method in your code.
*/
public synchronized void resetTensorNames() {
nameManager.reset();
metricNames = null;
kroneckerNames = null;
}
public Regim getRegim() {
return regim;
}
public void setRegim(Regim regim) {
this.regim = regim;
}
public String getImageOne() {
return imageOne;
}
public IndexConverterManager getIndexConverterManager() {
return symbolConverter;
}
public ToStringMode getDefaultPrintMode() {
return defaultPrintMode;
}
public NameManager getNameManager() {
return nameManager;
}
public NameDescriptor getNameDescriptor(int nameId) {
return nameManager.getNameDescriptor(nameId);
}
public String getKroneckerName() {
return kroneckerName;
}
public boolean withMetric() {
return metricName != null;
}
public String getMetricName() {
return metricName;
}
public boolean isKronecker(SimpleTensor t) {
if (kroneckerNames == null)
return false;
// kroneckerNames naturally sorted
return Arrays.binarySearch(kroneckerNames, t.getName()) >= 0;
}
public boolean isMetric(SimpleTensor t) {
if (metricNames == null)
return false;
// metricNames naturally sorted
synchronized (this) {
return Arrays.binarySearch(metricNames, t.getName()) >= 0;
}
}
public SimpleTensor createKronecker(int index1, int index2) {
if (IndicesUtils.getType(index1) != IndicesUtils.getType(index2) || IndicesUtils.getRawStateInt(index1) == IndicesUtils.getRawStateInt(index2))
throw new IllegalArgumentException("This is not kronecker indices!");
SimpleIndices indices = IndicesFactory.createSimple(index1, index2);
NameDescriptor nd = new NameDescriptor(kroneckerName, new IndicesTypeStructure(indices));
int name = nameManager.mapNameDescriptor(nd);
return new SimpleTensor(name, indices);
}
public SimpleTensor createMetric(int index1, int index2) {
byte type;
if ((type = IndicesUtils.getType(index1)) != IndicesUtils.getType(index2)
|| IndicesUtils.getRawStateInt(index1) != IndicesUtils.getRawStateInt(index2)
|| Arrays.binarySearch(metricTypes, type) < 0)
throw new IllegalArgumentException("This is not metric indices!");
SimpleIndices indices = IndicesFactory.createSimple(index1, index2);
NameDescriptor nd = new NameDescriptor(metricName, new IndicesTypeStructure(indices));
int name = nameManager.mapNameDescriptor(nd);
return new SimpleTensor(name, indices);
}
public SimpleTensor createMetricOrKronecker(int index1, int index2) {
if (IndicesUtils.getRawStateInt(index1) == IndicesUtils.getRawStateInt(index2))
return createMetric(index1, index2);
return createKronecker(index1, index2);
}
public Tensor parse(String expression) {
return parser.parse(expression);
}
public SimpleTensor parseSimple(String expression) {
Tensor t = parser.parse(expression);
if (t instanceof SimpleTensor)
return (SimpleTensor) t;
throw new RuntimeException("Not simple tensor");
}
public void addSymmetry(String tensor, IndexType type, boolean sign, int... permutation) {
SimpleTensor st = (SimpleTensor) parse(tensor);
addSymmetry(st, type, sign, permutation);
}
public void addSymmetry(SimpleTensor st, IndexType type, boolean sign, int... permutation) {
addSymmetry(st, type, new Symmetry(permutation, sign));
}
public void addSymmetry(String tensor, IndexType type, Symmetry symmetry) {
addSymmetry((SimpleTensor) parse(tensor), type, symmetry);
}
public void addSymmetry(SimpleTensor st, IndexType type, Symmetry symmetry) {
st.getIndices().getSymmetries().add(type.getType(), symmetry);
}
public SimpleTensor createSimpleTensor(String name, SimpleIndices indices) {
NameDescriptor descriptor = new NameDescriptor(name, new IndicesTypeStructure(indices));
int tensorName = nameManager.mapNameDescriptor(descriptor);
//dumping symmetries
SimpleIndices nIndices = IndicesFactory.createSimple(indices);
//creating simple and binding nIndices and descriptor symmetries
SimpleTensor t = new SimpleTensor(tensorName, nIndices);
//adding additional symmetries
nIndices.getSymmetries().addAllUnsafe(indices.getSymmetries());
return t;
}
public TensorField createTensorField(int name, SimpleIndices indices, Tensor... args) {
if (!nameManager.containtsNameId(name))
throw new RuntimeException("int name does not matches any tensor in context namespace");
NameDescriptor descriptor = nameManager.getNameDescriptor(name);
int tensorName = nameManager.mapNameDescriptor(descriptor);
return new TensorField(tensorName, indices, args);
}
public static Context get() {
return ContextManager.getCurrentContext();
}
public String getMapleDirectory() {
return mapleDirectory;
}
public String getWorkingFolder() {
return workingFolder;
}
/**
* Parent for all root tensors.
*
* @return parent for all root tensors
*/
public Tensor getRootParentTensor() {
return emptyTensor.INSTANCE;
}
private class MetricKroneckerListener implements NewNameDescriptorListener {
@Override
public void newNameDescriptor(NameDescriptor descriptor) {
if (descriptor.getIndexTypeStructure().size() != 2)
return;
byte type;
if (metricName != null && descriptor.getName().equals(metricName)) {
if (Arrays.binarySearch(metricTypes, type = descriptor.getIndexTypeStructure().get(0)) < 0
|| type != descriptor.getIndexTypeStructure().get(1)
|| descriptor.getIndexTypeStructure().size() != 2)
return;
if (descriptor.getIndexTypeStructure().get(0) != descriptor.getIndexTypeStructure().get(1))
throw new IllegalArgumentException("Wrong metric.");
descriptor.addSymmetry(
type, new Symmetry(new int[]{1, 0}, false));
if (metricNames == null)
metricNames = new int[]{descriptor.getId()};
else {
metricNames = Arrays.copyOf(metricNames, metricNames.length + 1);
metricNames[metricNames.length - 1] = descriptor.getId();
Arrays.sort(metricNames);
}
} else if (descriptor.getName().equals(kroneckerName)) {
if (descriptor.getIndexTypeStructure().size() != 2
|| (type = descriptor.getIndexTypeStructure().get(0)) != descriptor.getIndexTypeStructure().get(1))
return;
if (descriptor.getIndexTypeStructure().get(0) != descriptor.getIndexTypeStructure().get(1))
throw new IllegalArgumentException("Wrong kronecker.");
descriptor.addSymmetry(type, new Symmetry(new int[]{1, 0}, false));
if (kroneckerNames == null)
kroneckerNames = new int[]{descriptor.getId()};
else {
kroneckerNames = Arrays.copyOf(kroneckerNames, kroneckerNames.length + 1);
kroneckerNames[kroneckerNames.length - 1] = descriptor.getId();
Arrays.sort(kroneckerNames);
}
}
}
}
private static class emptyTensor extends Tensor {
public static final Tensor INSTANCE = new emptyTensor();
@Override
public void update() {
}
@Override
public Tensor clone() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Indices getIndices() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
protected int hash() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public AbstractTensorIterator iterator() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String toString(ToStringMode mode) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String toString() {
return "null parent expression";
}
@Override
public TensorContentImpl getContent() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
;
}