use of com.sri.ai.grinder.polynomial.api.Polynomial in project aic-expresso by aic-sri-international.
the class DefaultPolynomial method make.
public static Polynomial make(Expression expression, List<Expression> variables) {
Expression nonSymbolVariable = getFirstSatisfyingPredicateOrNull(variables, v -> !v.getSyntacticFormType().equals("Symbol"));
if (nonSymbolVariable != null) {
throw new IllegalArgumentException("Non-symbol variables in DefaultPolynomial no longer supported, but got " + nonSymbolVariable);
}
Polynomial result = null;
if (expression.hasFunctor(PLUS_FUNCTOR)) {
// E1 + E2 --> make(E1, F).add(make(E2, F))
// Note: as + can have 0 or more arguments we start with 0 (i.e. the
// neutral element).
result = makeFromMonomial(Expressions.ZERO, variables);
for (Expression summandExpression : expression.getArguments()) {
Polynomial summand = make(summandExpression, variables);
result = result.add(summand);
}
} else if (expression.hasFunctor(MINUS_FUNCTOR)) {
// E1 - E2 --> make(E1, F).minus(make(E2, F))
if (expression.numberOfArguments() == 1) {
// is '-(something)' which is equivalent to
// -1 * (something)
Polynomial p1 = makeFromMonomial(Expressions.MINUS_ONE, variables);
Polynomial p2 = make(expression.get(0), variables);
result = p1.times(p2);
} else if (expression.numberOfArguments() == 2) {
Polynomial p1 = make(expression.get(0), variables);
Polynomial p2 = make(expression.get(1), variables);
result = p1.minus(p2);
} else {
throw new IllegalArgumentException("Not a legal minus expression: " + expression);
}
} else if (expression.hasFunctor(TIMES_FUNCTOR)) {
// E1 * E2 --> make(E1, F).times(make(E2, F))
// Note: as * can have 0 or more arguments we start with 1 (i.e. the
// neutral element).
result = makeFromMonomial(Expressions.ONE, variables);
// Note: handle case when one of the multipliers is 0 (i.e. an
// absorbing element).
Polynomial absorbingElement = makeFromMonomial(Expressions.ZERO, variables);
for (Expression multiplierExpression : expression.getArguments()) {
Polynomial multiplier = make(multiplierExpression, variables);
if (multiplier.equals(absorbingElement)) {
// * by 0 so answer is 0, no need to worry about any other
// multipliers.
result = absorbingElement;
break;
} else {
result = result.times(multiplier);
}
}
} else if (expression.hasFunctor(DIVISION_FUNCTOR)) {
// E1 / E2 --> make(E1, F).divide(make(E2, F))
Polynomial dividend = make(expression.get(0), variables);
Polynomial divisor = make(expression.get(1), variables);
Pair<Polynomial, Polynomial> quotientAndRemainder = dividend.divide(divisor);
Polynomial quotient = quotientAndRemainder.first;
Polynomial remainder = quotientAndRemainder.second;
if (!remainder.isZero()) {
// divisor(x) divisor(x)
if (containsAnyOfGivenCollectionAsSubExpression(divisor, variables)) {
throw new IllegalArgumentException(expression + " is not a polynomial because it has divisor " + divisor);
}
Expression remainderDividedByDivisor = new DefaultFunctionApplication(DIVISION_FUNCTOR, Arrays.asList(remainder, divisor));
result = quotient.add(makeFromMonomial(remainderDividedByDivisor, variables));
} else {
result = quotient;
}
} else if (expression.hasFunctor(EXPONENTIATION_FUNCTOR)) {
// E1 ^ model with model an integer constant --> make(E1).exponentiate(model)
Expression base = expression.get(0);
Expression power = simplifyExponentIfPossible(expression.get(1));
if (containsAnyOfGivenCollectionAsSubExpression(power, variables)) {
throw new IllegalArgumentException("Polynomial variables cannot appear in exponent, but some of " + join(variables) + " appear in an exponent in " + expression);
}
if (isLegalExponent(power)) {
Polynomial p1 = make(base, variables);
result = p1.exponentiate(power.intValue());
} else if (containsAnyOfGivenCollectionAsSubExpression(base, variables)) {
throw new IllegalArgumentException("Exponents of the type " + power + " not recognized yet in " + DefaultPolynomial.class);
} else {
// constant multinomial
result = makeFromMonomial(expression, variables);
}
} else if (variables.contains(expression)) {
// single variable monomial
result = makeFromMonomial(expression, variables);
} else if (containsAnyOfGivenCollectionAsSubExpression(expression, variables)) {
// contains variables but is none of recognized types of expressions
throw new IllegalArgumentException("Polynomial variables " + join(variables) + " appear in illegal positions in " + expression);
} else {
// is constant monomial
result = makeFromMonomial(expression, variables);
}
return result;
}
use of com.sri.ai.grinder.polynomial.api.Polynomial in project aic-expresso by aic-sri-international.
the class DefaultPolynomial method make.
public static Polynomial make(Expression expression) {
Polynomial result;
boolean expressionAlreadyIsPolynomial = expression instanceof Polynomial;
if (expressionAlreadyIsPolynomial) {
result = (Polynomial) expression;
} else {
List<Expression> generalizedVariables = extractGeneralizedVariables(expression);
result = make(expression, generalizedVariables);
}
return result;
}
use of com.sri.ai.grinder.polynomial.api.Polynomial 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.Polynomial in project aic-expresso by aic-sri-international.
the class PolynomialIntegration method definiteIntegral.
/**
* This method will return the polynomial equivalent to:<br>
* <pre>
* Q.replace(variable, end) - Q.replace(variable, start)
* </pre>
* where 'Q = indefiniteIntegral(polynomial, variable)'
*
* @param polynomial
* the polynomial the definite integral is to be found for.
* @param variable
* the variable integration is with respect to.
* @param start
* the starting limit of the integral.
* @param end
* the ending limit of the integral.
* @return the definite integral of the polynomial for the given limits.
*/
public static Polynomial definiteIntegral(Polynomial polynomial, Expression variable, Expression start, Expression end, Predicate<Expression> isVariable) {
Polynomial q = indefiniteIntegral(polynomial, variable);
// Note: will include variable due to calling indefiniteIntegral
Set<Expression> variableSet = new LinkedHashSet<>(q.getVariables());
variableSet.addAll(Expressions.freeVariables(start, isVariable));
variableSet.addAll(Expressions.freeVariables(end, isVariable));
// if (!isNumber(start) && !isPositiveOrNegativeInfinity(start)) {
// variableSet.add(start);
// }
// if (!isNumber(end) && !isPositiveOrNegativeInfinity(end)) {
// variableSet.add(end);
// }
List<Expression> variables = new ArrayList<>(variableSet);
Polynomial minuendPolynomial = replaceFactor(q, variable, end, variables);
Polynomial subtrahendPolynomial = replaceFactor(q, variable, start, variables);
Polynomial result = minuendPolynomial.minus(subtrahendPolynomial);
return result;
}
use of com.sri.ai.grinder.polynomial.api.Polynomial in project aic-expresso by aic-sri-international.
the class PolynomialIntegration method replaceFactor.
private static Polynomial replaceFactor(Polynomial q, Expression variable, Expression value, List<Expression> variablesToIncludeInResult) {
List<Expression> replacedTerms = replaceVariableByValueInTerms(q, variable, value);
Polynomial result = DefaultPolynomial.make(Plus.make(replacedTerms), variablesToIncludeInResult);
return result;
}
Aggregations