You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
7.1 KiB
248 lines
7.1 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2013-
|
|
// Authors:
|
|
// * Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// This file is part of PRISM.
|
|
//
|
|
// PRISM 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 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// PRISM 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 PRISM; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
package param;
|
|
|
|
import java.math.BigInteger;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
|
|
// TODO terms should be sorted. will become necessary if a Function is
|
|
// implemented which directly uses objects of this class to store
|
|
// rational functions
|
|
|
|
/**
|
|
* A polynomial exressed as a sum of terms.
|
|
* Once a polynomial is fully constructed, it is immutable and cannot
|
|
* be changed anymore.
|
|
*
|
|
* @author Ernst Moritz Hahn <emhahn@cs.ox.ac.uk> (University of Oxford)
|
|
*/
|
|
final class Polynomial {
|
|
/** number of variables in this polynomial */
|
|
private int numVariables;
|
|
/** coefficients of this polynomial. */
|
|
private BigInteger[] coefficients;
|
|
/** exponents of each term. for each term, there are {@code numVariables}
|
|
* entries in exponents in this array, followed by the entries for
|
|
* the next term (if any). */
|
|
private int[] exponents;
|
|
private HashMap<Point,BigRational> pointsSeen;
|
|
/** current size of the polynomial. used during its construction. */
|
|
private int size;
|
|
|
|
/**
|
|
* Constructs a new polynomial.
|
|
*
|
|
* @param numVariables number of variables the polynomial will have
|
|
* @param numTerms final number of terms after construction
|
|
*/
|
|
Polynomial(int numVariables, int numTerms)
|
|
{
|
|
coefficients = new BigInteger[numTerms];
|
|
exponents = new int[numTerms * numVariables];
|
|
this.numVariables = numVariables;
|
|
this.pointsSeen = new HashMap<Point,BigRational>();
|
|
this.size = 0;
|
|
}
|
|
|
|
/**
|
|
* Adds a term to a polynomial.
|
|
* To be used during its construction.
|
|
*
|
|
* @param coefficient
|
|
* @param monomial
|
|
*/
|
|
void addTerm(BigInteger coefficient, ArrayList<Integer> monomial)
|
|
{
|
|
coefficients[size] = coefficient;
|
|
for (int i = 0; i < monomial.size(); i++) {
|
|
exponents[numVariables * size + i] = monomial.get(i);
|
|
}
|
|
size++;
|
|
}
|
|
|
|
/**
|
|
* Checks whether this polynomial is equal to the given object.
|
|
* For this to hold, {@code obj} must be a polynomial, and it
|
|
* must be the same polynomial as this polynomial.
|
|
*
|
|
* @param obj object to compare against
|
|
* @return true iff {@code obj} is a polynomial which equals this polynomial
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (!(obj instanceof Polynomial)) {
|
|
return false;
|
|
}
|
|
|
|
Polynomial other = (Polynomial) obj;
|
|
if (this.numVariables != other.numVariables) {
|
|
return false;
|
|
}
|
|
if (this.coefficients.length != other.coefficients.length) {
|
|
return false;
|
|
}
|
|
for (int i = 0; i < this.coefficients.length; i++) {
|
|
if (!this.coefficients[i].equals(other.coefficients[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
for (int i = 0; i < this.exponents.length; i++) {
|
|
if (this.exponents[i] != other.exponents[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns a hashcode for this polynomial.
|
|
*
|
|
* @return hash code for this polynomial
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
int hash = numVariables;
|
|
|
|
for (int i = 0; i < exponents.length; i++) {
|
|
hash = exponents[i] + (hash << 6) + (hash << 16) - hash;
|
|
}
|
|
|
|
for (int i = 0; i < coefficients.length; i++) {
|
|
hash = coefficients[i].hashCode() + (hash << 6) + (hash << 16) - hash;
|
|
}
|
|
|
|
return hash;
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation of the polynomial.
|
|
*
|
|
* @return string representation of the polynomial
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder builder = new StringBuilder();
|
|
for (int term = 0; term < coefficients.length; term++) {
|
|
BigInteger coeff = coefficients[term];
|
|
|
|
if (coeff.signum() > -1) {
|
|
if (term != 0) {
|
|
builder.append(" + ");
|
|
}
|
|
builder.append(coeff);
|
|
} else {
|
|
if (term == 0) {
|
|
builder.append("-");
|
|
} else {
|
|
builder.append(" - ");
|
|
}
|
|
builder.append(coeff.negate());
|
|
}
|
|
|
|
builder.append("*");
|
|
for (int var = 0; var < numVariables; var++) {
|
|
int power = exponents[numVariables * term + var];
|
|
builder.append("x");
|
|
builder.append(var);
|
|
builder.append("^");
|
|
builder.append(power);
|
|
if (var < numVariables - 1) {
|
|
builder.append("*");
|
|
}
|
|
}
|
|
}
|
|
return builder.toString();
|
|
}
|
|
|
|
/**
|
|
* Evaluates a polynomial at a given point.
|
|
* {@code point} must have the same dimension as the number of variables
|
|
* for this to work correctly. {@code cancel} specifies whether the
|
|
* result is to be brought into coprime form.
|
|
*
|
|
* @param point point to evaluate polynomial at
|
|
* @param cancel whether to make result coprime
|
|
* @return value of polynomial at given point
|
|
*/
|
|
BigRational evaluate(Point point, boolean cancel)
|
|
{
|
|
long time = System.currentTimeMillis();
|
|
BigRational result = pointsSeen.get(point);
|
|
if (result != null) {
|
|
if (!cancel) {
|
|
time = System.currentTimeMillis() - time;
|
|
return result;
|
|
} else {
|
|
time = System.currentTimeMillis() - time;
|
|
return result.cancel();
|
|
}
|
|
}
|
|
result = BigRational.ZERO;
|
|
|
|
for (int coeffNr = 0; coeffNr < coefficients.length; coeffNr++) {
|
|
BigRational coeffVal = new BigRational(coefficients[coeffNr]);
|
|
for (int var = 0; var < numVariables; var++) {
|
|
BigRational exp = point.getDimension(var).pow(exponents[coeffNr * numVariables + var]);
|
|
coeffVal = coeffVal.multiply(exp, cancel);
|
|
}
|
|
|
|
result = result.add(coeffVal, cancel);
|
|
}
|
|
pointsSeen.put(point, result);
|
|
time = System.currentTimeMillis() - time;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Evaluates a polynomial at a given point.
|
|
* {@code point} must have the same dimension as the number of variables
|
|
* for this to work correctly. Result is brought into coprime form.
|
|
*
|
|
* @param point point to evaluate polynomial at
|
|
* @return value of polynomial at given point
|
|
*/
|
|
BigRational evaluate(Point point)
|
|
{
|
|
return evaluate(point, true);
|
|
}
|
|
|
|
/**
|
|
* Checks whether the value of this polynomial is (strictly) greater zero.
|
|
*
|
|
* @param point point to evaluate polynomial at
|
|
* @param strict true for strictly greater zero, greater or equal else
|
|
* @return true if value at given {@code point} is (strictly) greater zero
|
|
*/
|
|
boolean check(Point point, boolean strict)
|
|
{
|
|
BigRational value = evaluate(point, false);
|
|
int compare = value.signum();
|
|
return strict ? (compare > 0) : (compare >= 0);
|
|
}
|
|
}
|