/*
* Redberry: symbolic tensor computations.
*
* Copyright (c) 2010-2013:
* 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.tensorgenerator;
import cc.redberry.concurrent.OutputPortUnsafe;
import cc.redberry.core.indexmapping.Mapping;
import cc.redberry.core.indices.Indices;
import cc.redberry.core.math.frobenius.FrobeniusSolver;
import cc.redberry.core.number.Complex;
import cc.redberry.core.number.Rational;
import cc.redberry.core.tensor.*;
import cc.redberry.core.transformations.symmetrization.SymmetrizeUpperLowerIndicesTransformation;
import cc.redberry.core.utils.IntArray;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Generates tensor of the most general form with specified free indices from specified tensors.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @since 1.0
*/
public class TensorGenerator {
private final Tensor[] samples;
private final int[] lowerArray, upperArray;
private final OutputPortUnsafe<Tensor> coefficientsGenerator;
private final SumBuilder result = new SumBuilder();
private final boolean symmetricForm;
private TensorGenerator(String coefficientName, Indices indices, boolean symmetricForm, Tensor... samples) {
this.samples = samples;
if (coefficientName.isEmpty())
this.coefficientsGenerator = OnePort.INSTANCE;
else
this.coefficientsGenerator = new SymbolsGeneratorWithHistory(coefficientName);
this.symmetricForm = symmetricForm;
this.lowerArray = indices.getLower().copy();
this.upperArray = indices.getUpper().copy();
Arrays.sort(lowerArray);
Arrays.sort(upperArray);
generate();
}
private void generate() {
//processing low indices
int totalLowCount = lowerArray.length, i, k;
int[] lowCounts = new int[samples.length + 1];
for (i = 0; i < samples.length; ++i)
lowCounts[i] = samples[i].getIndices().getFree().getLower().length();
lowCounts[i] = totalLowCount;
//processing up indices
int totalUpCount = upperArray.length;
int[] upCounts = new int[samples.length + 1];
for (i = 0; i < samples.length; ++i)
upCounts[i] = samples[i].getIndices().getFree().getUpper().length();
upCounts[i] = totalUpCount;
//solving Frobenius equations
FrobeniusSolver fbSolver = new FrobeniusSolver(lowCounts, upCounts);
//processing combinations
int u, l;
int[] combination;
while ((combination = fbSolver.take()) != null) {
List<Tensor> tCombination = new ArrayList<>();
u = 0;
l = 0;
for (i = 0; i < combination.length; ++i)
for (int j = 0; j < combination[i]; ++j) {
Tensor temp = samples[i];
// IndexMappingDirect im = new IndexMappingDirect();
IntArray termLow = temp.getIndices().getFree().getLower();
IntArray termUp = temp.getIndices().getFree().getUpper();
int[] oldIndices = new int[termUp.length() + termLow.length()],
newIndices = oldIndices.clone();
for (k = 0; k < termUp.length(); ++k) {
oldIndices[k] = termUp.get(k);
newIndices[k] = upperArray[u++];
}
for (k = 0; k < termLow.length(); ++k) {
oldIndices[k + termUp.length()] = termLow.get(k);
newIndices[k + termUp.length()] = lowerArray[l++];
}
temp = ApplyIndexMapping.applyIndexMapping(temp, new Mapping(oldIndices, newIndices), new int[0]);
tCombination.add(temp);
}
//creating term & processing combinatorics
Tensor term = SymmetrizeUpperLowerIndicesTransformation.symmetrizeUpperLowerIndices(Tensors.multiplyAndRenameConflictingDummies(tCombination.toArray(new Tensor[tCombination.size()])));
if (symmetricForm || !(term instanceof Sum))
term = Tensors.multiply(coefficientsGenerator.take(), term, term instanceof Sum ? new Complex(new Rational(1, term.size())) : Complex.ONE);
else
term = FastTensors.multiplySumElementsOnFactors((Sum) term, coefficientsGenerator);
result.put(term);
}
}
private Tensor result() {
return result.build();
}
/**
* Generates tensor of the most general form with specified free indices from specified tensors.
*
* @param coefficientName basic coefficients names
* @param indices free indices of the resulting tensor
* @param symmetricForm specifies whether the resulting tensor should be symmetric
* @param samples samples which used to generate tensor of the general form
* @return tensor of the most general form with specified free indices from specified tensors
*/
public static Tensor generate(String coefficientName, Indices indices, boolean symmetricForm, Tensor... samples) {
return new TensorGenerator(coefficientName, indices, symmetricForm, samples).result();
}
/**
* Generates tensor of the most general form with specified free indices from specified tensors.
*
* @param coefficientName basic coefficients names
* @param indices free indices of the resulting tensor
* @param symmetricForm specifies whether the resulting tensor should be symmetric
* @param samples samples which used to generate tensor of the general form
* @return tensor of the most general form with specified free indices from specified tensors and list of
* generated coefficients
*/
public static GeneratedTensor generateStructure(String coefficientName, Indices indices, boolean symmetricForm, Tensor... samples) {
TensorGenerator generator = new TensorGenerator(coefficientName, indices, symmetricForm, samples);
SimpleTensor[] generatedCoefficients;
if (coefficientName.isEmpty())
generatedCoefficients = new SimpleTensor[0];
else {
SymbolsGeneratorWithHistory coefficientsGenerator = (SymbolsGeneratorWithHistory) generator.coefficientsGenerator;
generatedCoefficients = coefficientsGenerator.generated.toArray(new SimpleTensor[coefficientsGenerator.generated.size()]);
}
return new GeneratedTensor(generatedCoefficients,
generator.result());
}
private static final class OnePort implements OutputPortUnsafe<Tensor> {
public static final OnePort INSTANCE = new OnePort();
private OnePort() {
}
@Override
public Tensor take() {
return Complex.ONE;
}
}
}