/* * @(#)PolynomialFunction.java * * $Date: 2012-03-12 20:55:21 -0500 (Mon, 12 Mar 2012) $ * * Copyright (c) 2011 by Jeremy Wood. * All rights reserved. * * The copyright of this software is owned by Jeremy Wood. * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * Jeremy Wood. For details see accompanying license terms. * * This software is probably, but not necessarily, discussed here: * http://javagraphics.java.net/ * * That site should also contain the most recent official version * of this software. (See the SVN repository for more details.) */ package com.bric.math.function; import com.bric.math.Equations; /** This function evaluates a polynomial expression. * */ public class PolynomialFunction implements Function { /** Creates a linear <code>PolynomialFunction</code> that passes through * the two points provided. * * @param x1 the x-coordinate of the first point. * @param y1 the y-coordinate of the first point. * @param x2 the x-coordinate of the second point. * @param y2 the y-coordinate of the second point. * @return a <code>PolynomialFunction</code> that passes through the points provided. */ public static PolynomialFunction createFit(double x1,double y1,double x2,double y2) { return new PolynomialFunction(new double[] {(y2-y1)/(-x1+x2), (y1*x2-y2*x1)/(-x1+x2) }); } /** Creates a <code>PolynomialFunction</code> that uses the coordinates * provided. * * @param xs an array of x-coordinates. * @param ys an array of y-coordinates. Each element in this array * corresponds to an element of the x coordinates. * @return a function that matches the coordinates provided. */ public static PolynomialFunction createFit(double[] xs,double[] ys) { if(ys.length!=xs.length) throw new IllegalArgumentException("xs.length ("+xs.length+") != ys.length ("+ys.length+")"); double[][] coefficientsMatrix = new double[ys.length][ys.length+1]; for(int row = 0; row<coefficientsMatrix.length; row++) { //make one row focusing on the value of ys(x), for(int column = 0; column<coefficientsMatrix[row].length-1; column++) { int power = ys.length-column-1; coefficientsMatrix[row][column] = Math.pow(xs[row], power); } coefficientsMatrix[row][coefficientsMatrix[row].length-1] = ys[row]; } Equations.solve(coefficientsMatrix, true); double[] coeffs = new double[coefficientsMatrix.length]; for(int a = 0; a<coeffs.length; a++) { coeffs[a] = coefficientsMatrix[a][coefficientsMatrix[a].length-1]; } return new PolynomialFunction(coeffs); } /** Creates a <code>PolynomialFunction</code> that uses the coordinates * provided. * <br>The function returned will pass through all the points provided, with * the dy/dx values provided. * * @param xs an array of x-coordinates. * @param ys an array of y-coordinates. Each element in this array * corresponds to an element of the x coordinates. * @param yDerivatives an array of dy/dx values. Each element in this array * corresponds to an element of the x coordinates. * @return a function that matches the coordinates provided. */ public static PolynomialFunction createFit(double[] xs,double[] ys,double[] yDerivatives) { if(ys.length!=yDerivatives.length) throw new IllegalArgumentException("ys.length ("+ys.length+") != yDerivatives.length ("+yDerivatives.length+")"); if(ys.length!=xs.length) throw new IllegalArgumentException("xs.length ("+xs.length+") != ys.length ("+ys.length+")"); double[][] coefficientsMatrix = new double[ys.length*2][ys.length*2+1]; for(int row = 0; row<coefficientsMatrix.length; row+=2) { //make one row focusing on the value of ys(x), //and the next row focusing on the value of yDerivs(x) for(int column = 0; column<coefficientsMatrix[row].length-1; column++) { int power = ys.length*2-column-1; coefficientsMatrix[row][column] = Math.pow(xs[row/2], power); if(power==0) { //no derivative for this one coefficientsMatrix[row+1][column] = 0; } else { coefficientsMatrix[row+1][column] = power*Math.pow(xs[row/2], power-1); } } coefficientsMatrix[row][coefficientsMatrix[row].length-1] = ys[row/2]; coefficientsMatrix[row+1][coefficientsMatrix[row].length-1] = yDerivatives[row/2]; } Equations.solve(coefficientsMatrix, true); double[] coeffs = new double[coefficientsMatrix.length]; for(int a = 0; a<coeffs.length; a++) { coeffs[a] = coefficientsMatrix[a][coefficientsMatrix[a].length-1]; } return new PolynomialFunction(coeffs); } double[] coeffs; /** Create a new <code>PolynomialFunction</code>. * * @param coeffs the coefficients of this polynomial. The first * coefficient corresponds to the highest power of x. So * if coeffs is [2, 3, 4] then this function will * evaluate as (2*t*t+3*t+4). */ public PolynomialFunction(double[] coeffs) { this.coeffs = new double[coeffs.length]; System.arraycopy(coeffs, 0, this.coeffs, 0, coeffs.length); } public double evaluate(double x) { double result = coeffs[0]; for(int a = 1, n = coeffs.length; a<n; a++) { result = result*x+coeffs[a]; } return result; } @Override public String toString() { StringBuffer sb = new StringBuffer("y = "); for(int a = 0; a<coeffs.length; a++) { int degree = coeffs.length-a-1; if(degree==0) { sb.append( coeffs[a] ); } else { sb.append( coeffs[a]+"*(x^"+(degree)+")" ); } if(a!=coeffs.length-1) sb.append("+"); } return sb.toString(); } public double[] evaluateInverse(double y) { if(coeffs.length==2) { double x = (y-coeffs[1])/coeffs[0]; return new double[] {x}; } //TODO: implement this throw new UnsupportedOperationException(); } }