use of com.sri.ai.grinder.polynomial.api.Monomial in project aic-expresso by aic-sri-international.
the class DefaultPolynomial method times.
@Override
public Polynomial times(Polynomial multiplier) throws IllegalArgumentException {
assertSameVariables(multiplier);
Polynomial result;
// Optimization: return 0 if either numeric constant factor is 0
if (isZero()) {
result = this;
} else if (multiplier.isZero()) {
result = multiplier;
} else if (isOne()) {
// Optimization, neutral element
result = multiplier;
} else if (multiplier.isOne()) {
// Optimization, neutral element
result = this;
} else {
// Base case
if (isMonomial() && multiplier.isMonomial()) {
result = makeFromMonomial(this.asMonomial().times(multiplier.asMonomial()), getVariables());
} else {
// OPTIMIZATION NOTE: Instead of incrementally adding to a result polynomial for each of the
// products from the cross product of this polynomials and the multipliers terms. We instead
// collect up the cross product computations first, then sort them based on monomial 'comes before'
// and then add like monomials together. Only then is an actual Polynomial result constructed.
// This reduces the number of additions required by the '# term in the result' and also removes
// the need for the creation of 'cross product # of terms' of intermediate polynomial objects
// in order to come up with a final result.
List<Monomial> products = new ArrayList<>(getMonomials().size() + multiplier.getMonomials().size());
for (Monomial multiplicandMonomial : getMonomials()) {
for (Monomial multiplierMonomial : multiplier.getMonomials()) {
Monomial monomialProduct = multiplicandMonomial.times(multiplierMonomial);
products.add(monomialProduct);
}
}
// Ensure we sort so that it is easy to add up like terms together for the final result
Collections.sort(products, monomialComparator);
List<Monomial> summedLikeProducts = new ArrayList<>(products.size());
for (Monomial product : products) {
int summedIdx = summedLikeProducts.size() - 1;
if (summedIdx < 0) {
summedLikeProducts.add(product);
} else {
Monomial sumOfLikeTerms = summedLikeProducts.get(summedIdx);
// are like terms, add them and track their sum
if (sumOfLikeTerms.areLikeTerms(product, getVariables())) {
sumOfLikeTerms = addMonomialsWithSameSignature(sumOfLikeTerms, product);
summedLikeProducts.set(summedIdx, sumOfLikeTerms);
} else {
summedLikeProducts.add(product);
}
}
}
summedLikeProducts.removeIf(term -> term.isZero());
result = new DefaultPolynomial(summedLikeProducts, getVariables());
}
}
return result;
}
use of com.sri.ai.grinder.polynomial.api.Monomial in project aic-expresso by aic-sri-international.
the class PolynomialSummation method sum.
/**
* Compute the sum for the summation of a polynomial.
*
* @param indexOfSummation
* the index variable of the summation.
* @param lowerBoundExclusive
* the lower bound of the summation.
* @param upperBoundInclusive
* the upper bound of the summation.
* @param summand
* the polynomial to be summed.
* @return the sum of the given summation.
*/
public static Polynomial sum(Expression indexOfSummation, Expression lowerBoundExclusive, Expression upperBoundInclusive, Polynomial summand) {
Polynomial result;
List<Expression> indexVariable = Arrays.asList(indexOfSummation);
Polynomial summandAsPolynomialOfIndex = DefaultPolynomial.make(summand, indexVariable);
int n = summandAsPolynomialOfIndex.degree();
//
// collect the t coefficients
List<Expression> tCoefficients = new ArrayList<>(n);
for (int i = 0; i <= n; i++) {
tCoefficients.add(Expressions.ZERO);
}
for (int i = 0; i < summandAsPolynomialOfIndex.numberOfTerms(); i++) {
Monomial term = summandAsPolynomialOfIndex.getMonomials().get(i);
tCoefficients.set(term.getPowerOfFactor(indexOfSummation).intValue(), term.getCoefficient(indexVariable));
}
//
// compute polynomials R_i(x) = (x + l)^i for each i
Expression indexOfSummationPlusLowerBound = new DefaultFunctionApplication(PLUS_FUNCTOR, Arrays.asList(indexOfSummation, lowerBoundExclusive));
Polynomial indexOfSummationPlusLowerBoundPolynomial = DefaultPolynomial.make(indexOfSummationPlusLowerBound, indexVariable);
List<Polynomial> rPolynomials = new ArrayList<>(n);
rPolynomials.add(DefaultPolynomial.make(Expressions.ONE, indexVariable));
rPolynomials.add(indexOfSummationPlusLowerBoundPolynomial);
for (int i = 2; i <= n; i++) {
rPolynomials.add(rPolynomials.get(i - 1).times(indexOfSummationPlusLowerBoundPolynomial));
}
Map<Pair<Integer, Integer>, Expression> indexedRCoefficient = new LinkedHashMap<>();
for (int i = 0; i <= n; i++) {
Polynomial rPolynomial = rPolynomials.get(i);
for (int q = 0; q <= i; q++) {
Pair<Integer, Integer> indexKey = new Pair<>(i, q);
Monomial rqxq = rPolynomial.getMapFromSignatureToMonomial().get(Arrays.asList(new Rational(q)));
if (rqxq == null) {
indexedRCoefficient.put(indexKey, Expressions.ZERO);
} else {
indexedRCoefficient.put(indexKey, rqxq.getCoefficient(indexVariable));
}
}
}
//
// compute "constants" (may contain variables other than x)
// s_i,q,j = t_i*R_{i,q}/(q+1) (-1)^j choose(q+1,j) B_j
// where R_{i,q}(x) is the coefficient in R_i(x) multiplying x^q.
Map<Triple<Integer, Integer, Integer>, Polynomial> sConstants = new LinkedHashMap<>();
for (int i = 0; i <= n; i++) {
Expression ti = tCoefficients.get(i);
for (int q = 0; q <= i; q++) {
Expression riq = indexedRCoefficient.get(new Pair<>(i, q));
Expression tiByriq = new DefaultFunctionApplication(TIMES_FUNCTOR, Arrays.asList(ti, riq));
for (int j = 0; j <= q; j++) {
Triple<Integer, Integer, Integer> indexKey = new Triple<>(i, q, j);
Expression qPlus1 = Expressions.makeSymbol(q + 1);
Expression minus1PowerJ = Expressions.makeSymbol(j % 2 == 0 ? 1 : -1);
Expression chooseQplus1J = Expressions.makeSymbol(Util.binomialCoefficient(q + 1, j));
Expression bernoulliJ = Expressions.makeSymbol(BernoulliNumber.computeFirst(j));
Expression sConstant = new DefaultFunctionApplication(TIMES_FUNCTOR, Arrays.asList(new DefaultFunctionApplication(DIVISION_FUNCTOR, Arrays.asList(tiByriq, qPlus1)), minus1PowerJ, chooseQplus1J, bernoulliJ));
sConstants.put(indexKey, DefaultPolynomial.make(sConstant, indexVariable));
}
}
}
//
// compute polynomials, for each q, j, V_{q + 1 -j} = (u - l)^{q + 1 - j}
Expression upperBoundMinusLowerBound = new DefaultFunctionApplication(MINUS_FUNCTOR, Arrays.asList(upperBoundInclusive, lowerBoundExclusive));
Polynomial upperBoundMinusLowerBoundPolynomial = DefaultPolynomial.make(upperBoundMinusLowerBound, indexVariable);
Map<Integer, Polynomial> vValues = new LinkedHashMap<>();
for (int q = 0; q <= n; q++) {
for (int j = 0; j <= q; j++) {
Integer exponent = q + 1 - j;
if (!vValues.containsKey(exponent)) {
vValues.put(exponent, upperBoundMinusLowerBoundPolynomial.exponentiate(exponent));
}
}
}
//
// Compute the w values and construct the final result.
Polynomial ws = DefaultPolynomial.make(Expressions.ZERO, indexVariable);
for (int i = 0; i <= n; i++) {
for (int q = 0; q <= i; q++) {
for (int j = 0; j <= q; j++) {
Triple<Integer, Integer, Integer> sConstantKey = new Triple<>(i, q, j);
Integer valueKey = q + 1 - j;
Polynomial sConstant = sConstants.get(sConstantKey);
Polynomial vValue = vValues.get(valueKey);
Polynomial w = sConstant.times(vValue);
ws = ws.add(w);
}
}
}
List<Expression> generalizedVariables = DefaultPolynomial.extractGeneralizedVariables(ws);
if (generalizedVariables.size() > 0) {
// Simplify in the context of the contained generalized variables
// and then return as a single constant factor (i.e. the index variable should not be present).
ws = DefaultPolynomial.make(ws, generalizedVariables);
}
result = DefaultPolynomial.make(ws, indexVariable);
return result;
}
Aggregations