if (tensors.length == 0)
return Complex.ONE;
else if (tensors.length == 1)
return tensors[0];
Complex factor = Complex.ONE;
IndexlessWrapper indexlessContainer = new IndexlessWrapper();
DataWrapper dataContainer = new DataWrapper();
Product p;
for (Tensor current : tensors) {
if (current instanceof Complex)
factor = factor.multiply((Complex) current);
else if (current instanceof Product) {
p = (Product) current;
indexlessContainer.add(p.indexlessData);
dataContainer.add(p.data, p.contentReference.getReferent(), p.indices);
factor = factor.multiply(p.factor);
} else if (current.getIndices().size() == 0)
indexlessContainer.add(current);
else
dataContainer.add(current);
if (factor.isNaN())
return factor;
}
if (NumberUtils.isZeroOrIndeterminate(factor))
return factor;
if (factor.isNumeric()) {
List<Tensor> newTensors = new ArrayList<>();
factor = Complex.ONE;
for (Tensor current : tensors) {
current = toNumeric(current);
if (current instanceof Complex)
factor = factor.multiply((Complex) current);
else newTensors.add(current);
}
if (newTensors.isEmpty())
return factor;
indexlessContainer = new IndexlessWrapper();
dataContainer = new DataWrapper();
for (Tensor current : newTensors) {
if (current instanceof Product) {
p = (Product) current;
indexlessContainer.add(p.indexlessData);
dataContainer.add(p.data, p.contentReference.getReferent(), p.indices);
factor = factor.multiply(p.factor);
} else if (current.getIndices().size() == 0)
indexlessContainer.add(current);
else
dataContainer.add(current);
}
}
//Processing data with indices
int i;
ProductContent content;
Indices indices;
Tensor[] data = dataContainer.list.toArray(new Tensor[dataContainer.list.size()]);
if (dataContainer.count == 1) {
content = dataContainer.content;
indices = dataContainer.indices;
if (indices == null) {
assert dataContainer.list.size() == 1;
indices = IndicesFactory.create(dataContainer.list.get(0).getIndices());
}
} else {
content = null;
Arrays.sort(data);
IndicesBuilder builder = new IndicesBuilder();
for (i = dataContainer.list.size() - 1; i >= 0; --i)
builder.append(dataContainer.list.get(i));
indices = builder.getIndices();
}
//Processing indexless data
Tensor[] indexless;
if (indexlessContainer.count == 0)
indexless = new Tensor[0];
else if (indexlessContainer.count == 1)
indexless = indexlessContainer.list.toArray(new Tensor[indexlessContainer.list.size()]);
else {
PowersContainer powersContainer = new PowersContainer(indexlessContainer.list.size());
ArrayList<Tensor> indexlessArray = new ArrayList<>();
Tensor tensor;
for (i = indexlessContainer.list.size() - 1; i >= 0; --i) {
tensor = indexlessContainer.list.get(i);
if (TensorUtils.isSymbolic(tensor)) {
powersContainer.put(tensor);
} else
indexlessArray.add(tensor);
}
for (Tensor t : powersContainer)
if (t instanceof Product) {
factor = factor.multiply(((Product) t).factor);
indexlessArray.ensureCapacity(t.size());
for (Tensor multiplier : ((Product) t).indexlessData)
indexlessArray.add(multiplier);
} else if (t instanceof Complex) {
factor = factor.multiply((Complex) t);
if (isZeroOrIndeterminate(factor))
return factor;
} else
indexlessArray.add(t);
if (powersContainer.isSign())
factor = factor.negate();
indexless = indexlessArray.toArray(new Tensor[indexlessArray.size()]);
Arrays.sort(indexless);
}
//Constructing result
if (data.length == 0 && indexless.length == 0)
return factor;
if (factor.isOne()) {
if (data.length == 1 && indexless.length == 0)
return data[0];
if (data.length == 0 && indexless.length == 1)
return indexless[0];
}
if (factor.isMinusOne()) {
Sum s = null;
if (indexless.length == 1 && data.length == 0 && indexless[0] instanceof Sum)
//case (-1)*(a+b) -> -a-b
s = ((Sum) indexless[0]);
if (indexless.length == 0 && data.length == 1 && data[0] instanceof Sum)