/*
* 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.tensor.SimpleTensor;
import cc.redberry.core.combinatorics.Symmetries;
import cc.redberry.core.combinatorics.Symmetry;
import cc.redberry.core.utils.ArraysUtils;
import cc.redberry.core.utils.IntArrayList;
import java.util.Arrays;
/**
* This class represents ordered indices and stores indices without sorting. It
* is the most fundamental {@code Indices} implementation. It is using to
* represent {@link SimpleTensor} indices, and in contract with, for example,
* production, witch indices array can be sorted, it stores indices array in
* order, in witch they were passed in constructor.
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @see SimpleIndices
* @see EmptyIndices
* @see AbstractIndices
* @see SortedIndices
*/
public final class SimpleIndicesImpl extends AbstractIndices implements SimpleIndices {
private IndicesSymmetries symmetries = null;
/**
* Construct {@code SimpleIndicesImpl} instance from specified indices array
* and with {@link Symmetries#EMPTY_SYMMETRIES}.
*
* @param data array of indices
*/
SimpleIndicesImpl(int... data) {
super(data);
int[] toSort = new int[data.length];
for (int i = 0; i < data.length; ++i)
toSort[i] = data[i] & 0x7F000000;
if (toSort.length > 100)
ArraysUtils.timSort(toSort, data);
else
ArraysUtils.insertionSort(toSort, data);
testConsistentWithException();
}
/**
* Construct {@code SimpleIndicesImpl} instance from specified indices and
* with identity symmetry.
*
* @param indices specified indices
*/
SimpleIndicesImpl(Indices indices) {
this(indices.getAllIndices().copy());
}
/**
* Construct {@code SimpleIndicesImpl} instance from specified indices array
* and with specified symmetries.
*
* @param data array of indices
* @param symmetries symmetries of this indices
*/
private SimpleIndicesImpl(int[] data, IndicesSymmetries symmetries) {
this(data);
this.symmetries = symmetries;
}
/**
* This method allows to set {@code Symmetries} of this {@code Indices}.
*
* @param symmetries {@code Symmetries} to be set as {@code Symmetries} of
* this {@code Indices}
*/
@Override
public void setSymmetries(IndicesSymmetries symmetries) {
if (this.symmetries != null)
throw new IllegalStateException("Symmetries are already set.");
this.symmetries = symmetries;
}
/**
* {@inheritDoc}
*
* @return {@inheritDoc}
*/
@Override
public IndicesSymmetries getSymmetries() {
if (symmetries == null)
symmetries = IndicesSymmetries.createCloneable(new IndicesTypeStructure(this));
return symmetries;
}
@Override
protected void calculateUpperLower() {
int upperCount = 0;
for (int index : data)
if (index >>> 31 == 1)
upperCount++;
lower = new int[size - upperCount];
upper = new int[upperCount];
int ui = 0, li = 0;
for (int index : data)
if (index >>> 31 == 1)
upper[ui++] = index;
else
lower[li++] = index;
}
/**
* {@inheritDoc }
*/
@Override
public SimpleIndicesImpl clone() {
return new SimpleIndicesImpl(Arrays.copyOf(data, size), symmetries == null ? null : symmetries.clone());
}
/**
* {@inheritDoc}
*/
@Override
public SimpleIndicesImpl getInverseIndices() {
int[] dataInv = new int[size];
for (int i = 0; i < size; ++i)
dataInv[i] = data[i] ^ 0x80000000;
return new SimpleIndicesImpl(dataInv, symmetries);
}
/**
* {@inheritDoc }
*/
@Override
public SimpleIndicesImpl getFreeIndices() {
IntArrayList dataList = new IntArrayList();
boolean y;
for (int i = 0; i < size; i++) {
y = true;
for (int j = 0; j < size; j++)
if (i != j && (data[i] ^ data[j]) == 0x80000000) {
y = false;
break;
}
if (y)
dataList.add(data[i]);
}
return new SimpleIndicesImpl(dataList.toArray(), symmetries);
}
@Override
protected void _update() {
sorted = null;
}
private int[] sorted = null;
@Override
protected int[] getSortedData() {
if (sorted == null) {
sorted = Arrays.copyOf(data, size);
Arrays.sort(sorted);
}
return sorted;
}
@Override
public void testConsistentWithException() {
for (int i = 0; i < size - 1; ++i)
for (int j = i + 1; j < size; ++j)
if (data[i] == data[j])
throw new InconsistentIndicesException(data[i]);
}
@Override
public boolean equalsWithSymmetries(Indices indices) {
return _equalsWithSymmetries(indices) == Boolean.FALSE;
}
/**
* More informative method, comparing indices using their symmetries lists.
* It returns
* <code>Boolean.FALSE</code> if indices are equals this,
* <code>Boolean.TRUE</code> if indices differs from this on -1 (i.e. on odd
* transposition) and
* <code>null</code> in other case.
*
* @param indices indices to compare with this
* @return
* <code>Boolean.FALSE</code> if indices are equals this,
* <code>Boolean.TRUE</code> if indices differs from this on -1 (i.e. on odd
* transposition) and
* <code>null</code> in other case.
*/
public Boolean _equalsWithSymmetries(Indices indices) {
if (indices.getClass() != this.getClass())
return null;
if (size != indices.size())
return null;
SimpleIndicesImpl _indices = (SimpleIndicesImpl) indices;
boolean sign1;
out_level_0:
for (Symmetry s1 : symmetries) {
sign1 = s1.isAntiSymmetry();
for (int i = 0; i < size; ++i)
if (data[s1.newIndexOf(i)] != (_indices).data[i])
continue;
return Boolean.valueOf(sign1);
}
return null;
}
@Override
public short[] getDiffIds() {
return symmetries.getDiffIds();
}
}