use of com.sri.ai.util.math.Rational in project aic-expresso by aic-sri-international.
the class DefaultMonomial method computeInnerExpression.
@Override
protected Expression computeInnerExpression() {
Expression result;
if (isNumericConstant()) {
result = numericFactorExpression;
} else {
List<Expression> arguments = makeListOfArgumentsWithRequiredSize();
boolean isNegative = getNumericFactor().isNegative();
Rational numericFactorToUse = determineNumericFactorToUse(isNegative);
gatherNumericConstantIfNotOne(numericFactorToUse, arguments);
gatherFactorsToTheirPowers(arguments);
Expression productOfFactors = Times.make(arguments);
result = makeResultWithAppropriateSign(isNegative, productOfFactors);
}
return result;
}
use of com.sri.ai.util.math.Rational in project aic-expresso by aic-sri-international.
the class DefaultMonomial method times.
@Override
public Monomial times(Monomial multiplier) {
Monomial result;
// Optimization: return 0 if either numeric factor is 0
if (isZero() || multiplier.isZero()) {
result = ZERO;
} else if (isOne()) {
// Optimization, neutral element
result = multiplier;
} else if (multiplier.isOne()) {
// Optimization, neutral element
result = this;
} else {
List<Expression> combinedNonNumericFactors = Monomial.orderedUnionOfNonNumericFactors(this, multiplier);
List<Rational> thisSignature = this.getSignature(combinedNonNumericFactors);
List<Rational> multiplierSignature = multiplier.getSignature(combinedNonNumericFactors);
Rational resultNumericFactor = getNumericFactor().multiply(multiplier.getNumericFactor());
List<Rational> resultPowers = zipWith((power1, power2) -> power1.add(power2), thisSignature, multiplierSignature);
result = make(resultNumericFactor, combinedNonNumericFactors, resultPowers);
}
return result;
}
use of com.sri.ai.util.math.Rational in project aic-expresso by aic-sri-international.
the class DefaultMonomial method make.
static DefaultMonomial make(Rational numericFactor, List<Expression> orderedNonNumericFactors, List<Rational> orderedNonNumericPowers) {
DefaultMonomial result;
// if numeric constant is 0, the whole expression is 0, so reduce to that.
if (numericFactor.equals(Rational.ZERO)) {
result = new DefaultMonomial(Rational.ZERO, Collections.emptyList(), Collections.emptyList());
} else {
List<Expression> factors = new ArrayList<>(orderedNonNumericFactors.size());
List<Rational> powers = new ArrayList<>(orderedNonNumericPowers.size());
for (int i = 0; i < orderedNonNumericPowers.size(); i++) {
Rational power = orderedNonNumericPowers.get(i);
// Power must not be negative as this is illegal for a monomial
if (power.signum() == -1) {
throw new IllegalArgumentException("Negative powers are not allowed.");
}
// 0 power means the factor is equivalent to 1 so we can just drop it.
if (power.signum() > 0) {
Expression factor = orderedNonNumericFactors.get(i);
factors.add(factor);
powers.add(power);
}
}
result = new DefaultMonomial(numericFactor, factors, powers);
}
return result;
}
use of com.sri.ai.util.math.Rational in project aic-expresso by aic-sri-international.
the class DefaultPolynomial method add.
@Override
public Polynomial add(Polynomial summand) throws IllegalArgumentException {
assertSameVariables(summand);
Polynomial result;
if (isZero()) {
result = summand;
} else if (summand.isZero()) {
result = this;
} else {
List<Monomial> summands = new ArrayList<>();
Set<List<Rational>> combinedSignatures = new LinkedHashSet<>(this.getMonomials().size() + summand.getMonomials().size());
combinedSignatures.addAll(this.getMapFromSignatureToMonomial().keySet());
combinedSignatures.addAll(summand.getMapFromSignatureToMonomial().keySet());
for (List<Rational> signature : combinedSignatures) {
// NOTE: at least one of these assignments is guaranteed to be non-null.
Monomial m1 = this.getMapFromSignatureToMonomial().get(signature);
Monomial m2 = summand.getMapFromSignatureToMonomial().get(signature);
if (m1 == null) {
if (!m2.isZero()) {
summands.add(m2);
}
} else if (m2 == null) {
if (!m1.isZero()) {
summands.add(m1);
}
} else {
Monomial sum = addMonomialsWithSameSignature(m1, m2);
if (!sum.isZero()) {
summands.add(sum);
}
}
}
// In case all the summands cancel each other out
if (summands.isEmpty()) {
result = makeFromMonomial(Expressions.ZERO, variables);
} else {
result = new DefaultPolynomial(summands, getVariables());
}
}
return result;
}
use of com.sri.ai.util.math.Rational 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