/*
* 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.TensorIterator;
import cc.redberry.core.tensor.testing.TTest;
import cc.redberry.transformation.Transformation;
/**
*
* @author Dmitry Bolotin
* @author Stanislav Poslavsky
* @author Konstantin Kiselev
*/
public class ToCommonDenominator implements Transformation {
@Override
public Tensor transform(Tensor tensor) {
if (!(tensor instanceof Sum))
return tensor;
Fraction result = null;
TensorIterator iterator = tensor.iterator();
Tensor current;
while (iterator.hasNext()) {
current = iterator.next();
if (current instanceof Fraction) {
if (result == null)
result = (Fraction) current;
else
result = sumPair(result, current);
iterator.remove();
}
}
if (result == null)
return tensor;
if (((Sum) tensor).isEmpty())
return result;
return sumPair(result, tensor.equivalent());
}
private Fraction sumPair(Fraction f1, Tensor f2) {
if (f2 instanceof Fraction) {
Fraction f2_ = (Fraction) f2;
Struct s = calcStruct(f1.getDenominator(), f2_.getDenominator());
return new Fraction(
new Sum(
s.firstMultiplicand == null ? f1.getNumerator() : new Product(f1.getNumerator(), s.firstMultiplicand),
s.secondMultiplicand == null ? f2_.getNumerator() : new Product(f2_.getNumerator(), s.secondMultiplicand)),
s.denominator);
}
Tensor f = new Product(f1.getDenominator().clone(), f2);
return new Fraction(new Sum(f1.getNumerator(), f), f1.getDenominator());
}
private static Struct calcStruct(Tensor t1, Tensor t2) {
if (t1 instanceof Product && !(t2 instanceof Product)) {
TensorIterator iterator = t1.iterator();
boolean commonDetected = false;
Tensor current;
while (iterator.hasNext()) {
current = iterator.next();
if (TTest.testParity(current, t2)) {
iterator.remove();
commonDetected = true;
break;
}
}
if (commonDetected)
return new Struct(null, t1.equivalent().clone(), new Product(t1, t2));
else
return new Struct(t2.clone(), t1.clone(), new Product(t1, t2));
}
if (!(t1 instanceof Product) && t2 instanceof Product)
return calcStruct(t2, t1).inverse();
if (t1 instanceof Product && t2 instanceof Product) {
Product _t1 = (Product) t1;
Product _t2 = (Product) t2;
_t1.sort();
_t2.sort();
TensorIterator iterator1 = _t1.iterator(), iterator2 = _t2.iterator();
Tensor current1 = iterator1.next(), current2 = iterator2.next();
int hash1 = current1.hashCode(), hash2 = current2.hashCode(), oldSize = 0;
boolean process = false;
List<Tensor> common = new ArrayList<>();
List<Tensor> equalsHash1 = new ArrayList<>();
while (true) {
if (hash1 < hash2) {
if (!iterator1.hasNext())
break;
current1 = iterator1.next();
} else if (hash2 < hash1) {
if (!iterator2.hasNext())
break;
current2 = iterator2.next();
hash2 = current2.hashCode();
process = process && hash2 == equalsHash1.get(0).hashCode();
if (process) {
for (int i = equalsHash1.size() - 1; i >= oldSize; --i)
if (TTest.testParity(equalsHash1.get(i), current2)) {
iterator2.remove();
// current2 = iterator2.next();
common.add(equalsHash1.remove(i));
break;
}
oldSize = equalsHash1.size();
}
} else if (TTest.testParity(current1, current2)) {
common.add(current1);
iterator1.remove();
iterator2.remove();
if (!iterator1.hasNext() || !iterator2.hasNext())
break;
current1 = iterator1.next();
current2 = iterator2.next();
} else {
process = true;
equalsHash1.add(current1);
iterator1.remove();
if (!iterator1.hasNext())
continue;
current1 = iterator1.next();
}
hash1 = current1.hashCode();
hash2 = current2.hashCode();
}
_t1.add(equalsHash1);
Product denom = new Product();
denom.add(_t1.clone());
denom.add(_t2.clone());
denom.add(common);
return new Struct(
_t2.isEmpty() ? null : _t2.equivalent(),
_t1.isEmpty() ? null : _t1.equivalent(),
denom.equivalent());
} else if (TTest.testParity(t1, t2))
return new Struct(null, null, t1);
else
return new Struct(t2.clone(), t1.clone(), new Product(t1, t2));
}
private static class Struct {
Tensor firstMultiplicand;
Tensor secondMultiplicand;
Tensor denominator;
public Struct(Tensor firstMultiplicand, Tensor secondMultiplicand, Tensor denominator) {
this.firstMultiplicand = firstMultiplicand;
this.secondMultiplicand = secondMultiplicand;
this.denominator = denominator;
}
Struct inverse() {
Tensor temp;
temp = firstMultiplicand;
firstMultiplicand = secondMultiplicand;
secondMultiplicand = temp;
return this;
}
}
}