/*
* 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.transformation.fraction;
import java.util.ArrayList;
import java.util.List;
import cc.redberry.core.tensor.Fraction;
import cc.redberry.core.tensor.Product;
import cc.redberry.core.tensor.Sum;
import cc.redberry.core.tensor.Tensor;
import cc.redberry.core.tensor.TensorSortedContent;
import cc.redberry.core.tensor.testing.TTest;
import cc.redberry.transformation.Transformation;
/**
* The class represents reduction of fractions to a common translation.
* The transformation reduces fraction by pairs generated fraction with
* common denominator for adding it to the next summand of incoming tensor.
* For instance: we have a/b+c/d+f/e+... The first step of cycle is sums of
* a/b+c/d=(a*d+c*b)/(b*d). The next step is sum of this fraction and the next
* summand: (a*d+c*b)/(b*d)+f/e. And so on.
* The transformation also take into account the common members of fraction's
* denominators.
*
* @author Konstantin Kiselev
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
*
*/
public class ToCommonDenominatorOld implements Transformation {
private boolean isProduct(Tensor tensor) {
return (tensor instanceof Product);
}
/*
* If first and second fractions' denominators are products, find fracion with
* common denominator.
*/
private Fraction getSumWithProductDenominator(Fraction first, Fraction second) {
TensorSortedContent firstContent = ((Product) first.getDenominator()).getContent();
TensorSortedContent secondContent = ((Product) second.getDenominator()).getContent();
Tensor firstMultiplyed = first.getNumerator();
Tensor secondMultiplyed = second.getNumerator();
List<Tensor> firstProduct = new ArrayList<>();
List<Tensor> secondProduct = new ArrayList<>();
firstProduct.add(secondMultiplyed);
secondProduct.add(firstMultiplyed);
Product denominator = new Product();
int j = 0;
boolean firstIsFinish = false;
for (int i = 0; i < secondContent.size(); i++) {
if (firstIsFinish) {
secondProduct.add(secondContent.get(i));
denominator.add(secondContent.get(i));
continue;
}
if (secondContent.get(i).hashCode() < firstContent.get(j).hashCode()) {
secondProduct.add(secondContent.get(i));
denominator.add(secondContent.get(i));
continue;
} else if (secondContent.get(i).hashCode() > firstContent.get(j).hashCode()) {
firstProduct.add(firstContent.get(j));
denominator.add(firstContent.get(j));
j++;
if (j == firstContent.size())
firstIsFinish = true;
i--;
continue;
} else if (secondContent.get(i).hashCode() == firstContent.get(j).hashCode())
while (secondContent.get(i).hashCode() == firstContent.get(j).hashCode() && j < firstContent.size())
if (TTest.testParity(secondContent.get(i), firstContent.get(j))) {
denominator.add(firstContent.get(j));
j++;
if (j == firstContent.size())
firstIsFinish = true;
break;
}
}
if (!firstIsFinish)
for (int i = j; i < firstContent.size(); i++) {
firstProduct.add(firstContent.get(j));
denominator.add(firstContent.get(j));
}
Tensor summond1 = new Product(firstProduct);
Tensor summond2 = new Product(secondProduct);
return new Fraction(new Sum(summond1, summond2), denominator);
}
/*
* If first fraction's denominator is product but second isn't, find
* fraction with common denominator.
*/
private Fraction getSumWithProductAndSimpleDenominator(Fraction first, Fraction second) {
TensorSortedContent firstFracContent = ((Product) first.getDenominator()).getContent();
Product denom = new Product();
boolean is = false;
for (int i = 0; i < firstFracContent.size(); i++)
if (!is) {
if (!(firstFracContent.get(i).hashCode() == second.getDenominator().hashCode())) {
denom.add(firstFracContent.get(i));
continue;
}
if (!TTest.testParity(firstFracContent.get(i), second.getDenominator()))
denom.add(firstFracContent.get(i));
else
is = true;
} else
denom.add(firstFracContent.get(i));
Tensor denominator = is ? first.getDenominator() : new Product(denom.clone(), second.getDenominator());
Tensor summand1 = is ? first.getNumerator() : new Product(first.getNumerator(), second.getDenominator());
Tensor summand2 = new Product(second.getNumerator().clone(), denom);
return new Fraction(new Sum(summand1, summand2), denominator);
}
@Override
public Tensor transform(Tensor tensor) {
if (!(tensor instanceof Sum))
return tensor;
List<Tensor> listTensor = new ArrayList<>();
List<Fraction> listFrac = new ArrayList<>();
for (Tensor s : tensor)
if (s instanceof Fraction)
listFrac.add((Fraction) s);
else
listTensor.add(s);
if (listFrac.isEmpty())
return tensor;
Fraction resultFrac = null;
for (Fraction f : listFrac) {
if (resultFrac == null) {
resultFrac = f;
continue;
}
Tensor resultFracN = resultFrac.getNumerator();
Tensor resultFracD = resultFrac.getDenominator();
Tensor fD = f.getDenominator();
Tensor fN = f.getNumerator();
boolean resultIsProduct = isProduct(resultFracD);
boolean fIsProduct = isProduct(fD);
if (!(resultIsProduct || fIsProduct))
if (TTest.testParity(resultFracD, fD))
resultFrac = new Fraction(new Sum(resultFracN, fN), resultFracD);
else {
Tensor summond1 = new Product(resultFracN, fD);
Tensor summond2 = new Product(fN, resultFracD.clone());
Tensor newNumerator = new Sum(summond1, summond2);
Tensor newDenumerator = new Product(resultFracD.clone(), fD);
resultFrac = new Fraction(newNumerator, newDenumerator);
}
else if (resultIsProduct ^ fIsProduct)
if (resultIsProduct)
resultFrac = getSumWithProductAndSimpleDenominator(resultFrac, f);
else
resultFrac = getSumWithProductAndSimpleDenominator(f, resultFrac);
else
if (((Product) resultFracD).size() >= ((Product) fD).size())
resultFrac = getSumWithProductDenominator(resultFrac, f);
else
resultFrac = getSumWithProductDenominator(f, resultFrac);
}
if (!listTensor.isEmpty()) {
Tensor simpleSum = new Sum(listTensor);
Tensor summand1 = new Product(simpleSum, resultFrac.getDenominator().clone());
Tensor summand2 = resultFrac.getNumerator();
Tensor result = new Fraction(new Sum(summand1, summand2), resultFrac.getDenominator());
return result;
}
return resultFrac;
}
}