All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sri.ai.grinder.polynomial.api.Polynomial Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.grinder.polynomial.api;

import static com.sri.ai.expresso.helper.Expressions.makeSymbol;
import static com.sri.ai.util.Util.pickUpToKElementsWithoutReplacement;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

import com.google.common.annotations.Beta;
import com.sri.ai.expresso.api.Expression;
import com.sri.ai.grinder.sgdpllt.library.number.Exponentiation;
import com.sri.ai.grinder.sgdpllt.library.number.Plus;
import com.sri.ai.grinder.sgdpllt.library.number.Times;
import com.sri.ai.util.base.Pair;
import com.sri.ai.util.math.Rational;

/**
 * A polynomial is a monomial, or a sum of {@link Monomial}s.
 * It is associated with a tuple F of variables, such that no two
 * monomials are like terms to each other wrt F, and monomials are in
 * order according to "comes before" wrt F.
 * 
 * For example, if F is a singleton tuple (x),
 * the polynomial representation of 2*x*y + 2*x*y^2
 * must be (2*y + 2*y^2)*x (a single monomial)
 * because the two terms are like terms with respect to (x),
 * whereas if F is (x,y), then
 * its polynomial representation would be 2*x*y + 2*x*y^2
 * (two monomials) because the two monomials are not like terms
 * wrt (x,y).
 * 
 * Note that the variables can be any tuple of given expressions, and not just symbols.
 * This allows polynomials defined on more complex, unknown, terms.
 * For example, we may not know what a set D is, but need to
 * represent a polynomial on its cardinality: 2*|D|^2 + |D|.
 * 
 * A "signature" (with respect to a tuple of variables )
 * of a monomial is the list of powers of each variable in the monomial.
 * Note that the variables are ordered,
 * and the signature follows that order.
 * For example, the monomial x^2*y has signature (2,1)
 * for variables (x,y).
 * The choice of the word "signature" for this concept is due to the
 * fact that the signature of a monomial "gives away its identity"
 * and forces it to be grouped with other monomials of the same signature (like terms)
 * when summed in a polynomial. 
 * 
 * Therefore:
* *
 * 
 * 3*x + 2*x + 10 + x^2 wrt F = (x) 
 * 
 * is not a valid polynomial in this representation, but 
 * 
 * x^2 + 5*x + 10 wrt F = (x) 
 * 
 * is a valid polynomial in this representation.
 * 
 * 
* * * @author oreilly * */ @Beta public interface Polynomial extends Expression { /** * * @return the variables that are used to identify like terms in the * polynomial. */ List getVariables(); /** * Returns the signature term map for this polynomial. * The signature term map is a map from signatures (lists of {@link Rational}s) * to the (unique) monomial in the polynomial with that signature. * @return the signature term map for this polynomial. */ Map, Monomial> getMapFromSignatureToMonomial(); /** * * @return true if this Polynomial is equivalent to a Monomial. */ default boolean isMonomial() { boolean result = getMonomials().size() == 1; return result; } /** * If the Polynomial is equivalent to a Monomial get its representation as * such. * * @return this Polynomial's representation as a Monomial. * @throws IllegalStateException * if this Polynomial is not equivalent to a Monomial. */ default Monomial asMonomial() throws IllegalStateException { if (!isMonomial()) { throw new IllegalStateException("This polynomial, " + this + ", is not a monomial"); } Monomial result = getMonomials().get(0); return result; } /** * * @return the number of terms in this polynomial. */ default int numberOfTerms() { int result = getMonomials().size(); return result; } /** * * @return a list of monomials in this polynomial (ordered by signature). */ List getMonomials(); /** * * @return true if this Polynomial is equivalent to a numeric constant; */ default boolean isNumericConstant() { boolean result = isMonomial() && asMonomial().isNumericConstant(); return result; } /** * * @return true if this Polynomial is equivalent to the numeric constant zero. */ default boolean isZero() { boolean result = isMonomial() && asMonomial().isZero(); return result; } /** * * @return true if this Polynomial is equivalent to the numeric constant one. */ default boolean isOne() { boolean result = isMonomial() && asMonomial().isOne(); return result; } /** * The degree of a polynomial is the highest degree of its terms. * * @return the degree of the polynomial. */ int degree(); /** * Add this polynomial to another polynomial and return a new Polynomial * representing the sum. * *
	 * 
	 * summand(this) + summand = sum.
	 * 
	 * 
* * @param summand * the summand to be added to this polynomial. * @return the sum of this and the summand. * @throws IllegalArgumentException * if the summand does not share the same signature * factors as this polynomial. */ Polynomial add(Polynomial summand) throws IllegalArgumentException; /** * Subtract a given polynomial from this polynomial and return a new * polynomial representing the difference of the two. * *
	 * 
	 * minuend(this) - subtrahend = difference.
	 * 
	 * 
* * @param subtrahend * the subtrahend. * @return the difference of this polynomial minus the subtrahend. * @throws IllegalArgumentException * if the subtrahend does not share the same signature * factors as this polynomial. */ Polynomial minus(Polynomial subtrahend) throws IllegalArgumentException; /** * Mulitply this polynomial by another. * *
	 * 
	 * multiplicand(this) * multiplier = product.
	 * 
	 * 
* * @param multiplier * the multiplier. * @return the project of this polynomial and the given multiplier. * @throws IllegalArgumentException * if the multiplier does not share the same signature * factors as this polynomial. */ Polynomial times(Polynomial multiplier) throws IllegalArgumentException; /** * Divide this polynomial by another. * *
	 * 
	 * dividend(this) / divisor = (quotient, remainder).
	 * 
	 * 
* * @param divisor * @return a pair consisting of the quotient and remainder of this/divisor. * @throws IllegalArgumentException * if the divisor does not share the same signature * factors as this polynomial. */ Pair divide(Polynomial divisor) throws IllegalArgumentException; /** * Raise this polynomial to a given power. * * @param exponent * a non negative integer exponent to raise the polynomial to. * @return a polynomial which is the result of raising this polynomial to * the given exponent. * @throws IllegalArgumentException * if the exponent is negative. */ Polynomial exponentiate(int exponent) throws IllegalArgumentException; public static Expression makeRandomPolynomial( Random random, Expression index, int degree, ArrayList freeVariables, int maximumNumberOfFreeVariablesInEachMonomial, int maximumConstantInEachMonomial) { ArrayList terms = makeRandomMonomials( random, degree, index, freeVariables, maximumNumberOfFreeVariablesInEachMonomial, maximumConstantInEachMonomial); Expression result = Plus.make(terms); return result; } public static ArrayList makeRandomMonomials( Random random, int degree, Expression index, ArrayList freeVariables, int maximumNumberOfFreeVariablesInEachMonomial, int maximumConstant) { ArrayList monomials = new ArrayList<>(degree); for (int i = degree; i != -1; i++) { Expression monomial = makeRandomMonomial( random, index, freeVariables, maximumNumberOfFreeVariablesInEachMonomial, i, maximumConstant); monomials.add(monomial); } return monomials; } public static Expression makeRandomMonomial( Random random, Expression index, ArrayList freeVariables, int maximumNumberOfFreeVariables, int indexPower, int maximumConstant) { Expression coefficient = makeRandomCoefficient( random, index, freeVariables, maximumNumberOfFreeVariables, maximumConstant); Expression monomial = Times.make(coefficient, Exponentiation.make(index, makeSymbol(indexPower))); return monomial; } public static Expression makeRandomCoefficient( Random random, Expression index, ArrayList freeVariables, int maximumNumberOfFreeVariables, int maximumConstant) { int numberOfFreeVariables = random.nextInt(maximumNumberOfFreeVariables); ArrayList coefficientFactors = new ArrayList<>(numberOfFreeVariables + 1); pickUpToKElementsWithoutReplacement( freeVariables, numberOfFreeVariables + 1, e -> ! e.equals(index), random, coefficientFactors); Expression coefficientConstant = makeSymbol(random.nextInt(maximumConstant)); coefficientFactors.set(0, coefficientConstant); Expression coefficient = Times.make(coefficientFactors); return coefficient; } }