/*
* 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.indices;
import cc.redberry.core.combinatorics.Permutation;
import cc.redberry.core.combinatorics.Permutations;
import cc.redberry.core.combinatorics.Symmetry;
import cc.redberry.core.tensor.Tensor;
import cc.redberry.core.utils.ArraysUtils;
import cc.redberry.core.utils.IntArray;
import cc.redberry.core.utils.IntArrayList;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*/
public final class IndicesBuilderSimple extends AbstractIndicesBuilder implements IndicesBuilder {
private List<SymmetryContainer> symmetries = new ArrayList<>();
public IndicesBuilderSimple() {
super(new IntArrayList());
//adding identity symmetry
symmetries.add(new SymmetryContainer());
}
public IndicesBuilderSimple(int capacity) {
super(new IntArrayList(capacity));
//adding identity symmetry
symmetries.add(new SymmetryContainer(capacity));
}
@Override
public IndicesBuilderSimple append(int index) {
for (SymmetryContainer arrayList : symmetries)
arrayList.list.add(data.size());
data.add(index);
return this;
}
private void addSymmetriesTail(final int length) {
int[] additionSymmetrytail = new int[length];
for (int i = 0; i < length; ++i)
additionSymmetrytail[i] = data.size() + i;
for (SymmetryContainer arrayList : symmetries)
arrayList.list.addAll(additionSymmetrytail);
}
@Override
public IndicesBuilderSimple append(int[] indices) {
addSymmetriesTail(indices.length);
data.addAll(indices);
return this;
}
@Override
public IndicesBuilderSimple append(final IntArray indices) {
addSymmetriesTail(indices.length());
data.addAll(indices);
return this;
}
@Override
public IndicesBuilderSimple append(IntArrayList indices) {
addSymmetriesTail(indices.size());
data.addAll(indices);
return this;
}
@Override
public IndicesBuilderSimple append(Indices indices) {
if (indices instanceof EmptyIndices)
return this;
if (indices instanceof SortedIndices)
return append(indices.getAllIndices());
//processing symmetries
final int oldSize = data.size();
addSymmetriesTail(indices.size());
List<Symmetry> addingSymmetries = ((SimpleIndices) indices).getSymmetries().getReference().getBaseSymmetries();
int i;
for (Symmetry s : addingSymmetries) {
//without identity
if (Permutations.isIdentity(s))
continue;
IntArrayList newPermutation = new IntArrayList();
for (i = 0; i < oldSize; ++i)
newPermutation.add(i);
for (i = 0; i < indices.size(); ++i)
newPermutation.add(oldSize + s.newIndexOf(i));
symmetries.add(new SymmetryContainer(newPermutation, s.isAntiSymmetry()));
}
data.addAll(indices.getAllIndices());
return this;
}
@Override
public IndicesBuilderSimple append(IndicesBuilder ib) {
return append(ib.getIndices());
}
@Override
public IndicesBuilderSimple append(Tensor tensor) {
return append(tensor.getIndices());
}
@Override
public IndicesBuilderSimple append(Tensor... tensor) {
for (Tensor t : tensor)
append(t);
return this;
}
@Override
public SimpleIndices getIndices() {
final int[] indices = data.toArray();
int[] types = new int[indices.length];
for (int i = 0; i < indices.length; ++i)
types[i] = indices[i] & 0x7F000000;
int[] sortPermutation = Permutations.createIdentity(indices.length);
if (types.length > 100)
ArraysUtils.timSort(types, sortPermutation);
else
ArraysUtils.insertionSort(types, sortPermutation);
final int size = data.size();
Permutation sort = new Permutation(sortPermutation);
final Symmetry[] resulting = new Symmetry[symmetries.size() - 1];
int i, j;
int[] permutation;
IntArrayList current;
//0th is identity identity
for (i = 1; i < resulting.length + 1; ++i) {
current = symmetries.get(i).list;
permutation = new int[size];
for (j = 0; j < size; ++j)
permutation[j] = sort.inverse().newIndexOf(current.get(sort.newIndexOf(j)));
resulting[i - 1] = new Symmetry(permutation, symmetries.get(i).sign);
}
SimpleIndices simpleIndices = IndicesFactory.createSimple(indices);
simpleIndices.getSymmetries().addAllUnsafe(resulting);
return simpleIndices;
}
@Override
public String toString() {
return getIndices().toString();
}
private static final class SymmetryContainer {
final IntArrayList list;
boolean sign;
SymmetryContainer() {
list = new IntArrayList();
}
SymmetryContainer(int capacity) {
list = new IntArrayList(capacity);
}
SymmetryContainer(IntArrayList list, boolean sign) {
this.list = list;
this.sign = sign;
}
}
}