private ProductContent calculateContent() {
if (data.length == 0) {
contentReference.resetReferent(ProductContent.EMPTY_INSTANCE);
return ProductContent.EMPTY_INSTANCE;
}
final Indices freeIndices = indices.getFree();
final int differentIndicesCount = (getIndices().size() + freeIndices.size()) / 2;
//Names (names with type, see IndicesUtils.getNameWithType() ) of all indices in this multiplication
//It will be used as index name -> index index [0,1,2,3...] mapping
final int[] upperIndices = new int[differentIndicesCount], lowerIndices = new int[differentIndicesCount];
//This is sorage for intermediate information about indices, used in the algorithm (see below)
//Structure:
//
final long[] upperInfo = new long[differentIndicesCount], lowerInfo = new long[differentIndicesCount];
//This is for generalization of algorithm
//indices[0] == lowerIndices
//indices[1] == lowerIndices
final int[][] indices = new int[][]{lowerIndices, upperIndices};
//This is for generalization of algorithm too
//info[0] == lowerInfo
//info[1] == lowerInfo
final long[][] info = new long[][]{lowerInfo, upperInfo};
//Pointers for lower and upper indices, used in algorithm
//pointer[0] - pointer to lower
//pointer[1] - pointer to upper
final int[] pointer = new int[2];
final short[] stretchIndices = calculateStretchIndices(); //for performance
//Allocating array for results, one contraction for each tensor
final TensorContraction[] contractions = new TensorContraction[data.length];
//There is one dummy tensor with index -1, it represents fake
//tensor contracting with whole Product to leave no contracting indices.
//So, all "conractions" with this dummy "contraction" looks like a scalar
//product. (sorry for English)
final TensorContraction freeContraction = new TensorContraction((short) -1, new long[freeIndices.size()]);
int state, index, i;
//Processing free indices = creating contractions for dummy tensor
for (i = 0; i < freeIndices.size(); ++i) {
index = freeIndices.get(i);
//Inverse state (because it is state of index at (??) dummy tensor,
//contracted with this free index)
state = 1 - IndicesUtils.getStateInt(index);
//Important:
info[state][pointer[state]] = dummyTensorInfo;
indices[state][pointer[state]++] = IndicesUtils.getNameWithType(index);
}
int tensorIndex;
for (tensorIndex = 0; tensorIndex < data.length; ++tensorIndex) {
//Main algorithm
Indices tInds = data[tensorIndex].getIndices();
short[] diffIds = tInds.getDiffIds();
for (i = 0; i < tInds.size(); ++i) {
index = tInds.get(i);
state = IndicesUtils.getStateInt(index);
info[state][pointer[state]] = packToLong(tensorIndex, stretchIndices[tensorIndex], diffIds[i]);
indices[state][pointer[state]++] = IndicesUtils.getNameWithType(index);
}
//Result allocation
contractions[tensorIndex] = new TensorContraction(stretchIndices[tensorIndex], new long[tInds.size()]);
}
//Here we can use unstable sorting algorithm (all indices are different)
ArraysUtils.quickSort(indices[0], info[0]);
ArraysUtils.quickSort(indices[1], info[1]);