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

org.ddogleg.solver.PolynomialOps Maven / Gradle / Ivy

Go to download

DDogleg Numerics is a high performance Java library for non-linear optimization, robust model fitting, polynomial root finding, sorting, and more.

There is a newer version: 0.23.4
Show newest version
/*
 * Copyright (c) 2012-2015, Peter Abeles. All Rights Reserved.
 *
 * This file is part of DDogleg (http://ddogleg.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ddogleg.solver;

import org.ddogleg.solver.impl.FindRealRootsSturm;
import org.ddogleg.solver.impl.RootFinderCompanion;
import org.ddogleg.solver.impl.SturmSequence;
import org.ddogleg.solver.impl.WrapRealRootsSturm;

/**
 * @author Peter Abeles
 */
public class PolynomialOps {

	/**
	 * Given the coefficients compute the vertex (minimum/maximum) of the quadratic.
	 *
	 * y = a*x2 + b*x + c
	 *
	 * @param a quadratic coefficient.
	 * @param b quadratic coefficient.
	 * @return The quadratic's vertex.
	 */
	public static double quadraticVertex( double a, double b ) {
		return -b/(2.0*a);
	}

	public static Polynomial derivative( Polynomial poly , Polynomial deriv ) {
		if( deriv == null ) {
			deriv = new Polynomial(poly.size-1);
		} else {
			deriv.size = poly.size - 1;
		}

		for( int i = 1; i < poly.size; i++ ) {
			deriv.c[i-1] = poly.c[i]*i;
		}

		return deriv;
	}

	// TODO try using a linear search alg here
	public static double refineRoot( Polynomial poly, double root , int maxIterations ) {

//		for( int i = 0; i < maxIterations; i++ ) {
//
//			double v = poly.c[poly.size-1];
//			double d = v*(poly.size-1);
//
//			for( int j = poly.size-1; j > 0; j-- ) {
//				v = poly.c[j] + v*root;
//				d = poly.c[j]*j + d*root;
//			}
//			v = poly.c[0] + v*root;
//
//			if( d == 0 )
//				return root;
//
//			root -= v/d;
//		}
//
//		return root;

		Polynomial deriv = new Polynomial(poly.size());
		derivative(poly,deriv);

		for( int i = 0; i < maxIterations; i++ ) {

			double v = poly.evaluate(root);
			double d = deriv.evaluate(root);

			if( d == 0 )
				return root;

			root -= v/d;
		}

		return root;
	}


	/**
	 * 

* Polynomial division. Computes both the quotient and the remainder.
*
* quotient = numerator/denominator
* remainder = numerator % denominator *

* * @param numerator Numerator in the division. Not modified. * @param denominator Denominator in the division. Not modified. * @param quotient Output quotient, Modified. * @param remainder Output remainder. Modified. */ public static void divide( Polynomial numerator , Polynomial denominator , Polynomial quotient , Polynomial remainder ) { if( denominator.size <= 0 ) throw new IllegalArgumentException("Trying to device by a polynomial of size 0"); int nn = numerator.size-1; int nd = denominator.size-1; while( nd >= 0 && denominator.c[nd] == 0 ) nd -= 1; // divide by zero error if( nd < 0 ) { throw new IllegalArgumentException("Divide by zero error"); } quotient.size = nn-nd+1; remainder.setTo(numerator); for( int k = nn-nd; k >= 0; k-- ) { if( nd < 0 || k < 0 ) System.out.println("EGADS"); double c = quotient.c[k] = remainder.c[nd+k]/denominator.c[nd]; for( int j = k+nd; j >= k; j-- ) { remainder.c[j] -= c*denominator.c[j-k]; } } // The remainder can't be larger than the denominator remainder.size = nd; } /** * Multiplies the two polynomials together. * @param a Polynomial * @param b Polynomial * @param result Optional storage parameter for the results. Must be have enough coefficients to store the results. * If null a new instance is declared. * @return Results of the multiplication */ public static Polynomial multiply( Polynomial a , Polynomial b , Polynomial result ) { int N = Math.max(0,a.size() + b.size() - 1); if( result == null ) { result = new Polynomial(N); } else { if( result.size < N ) throw new IllegalArgumentException("Unexpected length of 'result'"); result.zero(); } for( int i = 0; i < a.size; i++ ) { double coef = a.c[i]; int index = i; for( int j = 0; j < b.size; j++ ) { result.c[index++] += coef*b.c[j]; } } return result; } /** * Adds two polynomials together. The lengths of the polynomials do not need to be the zero, but the 'missing' * coefficients are assumed to be zero. * * @param a Polynomial * @param b Polynomial * @param results Optional storage for resulting polynomial. If null a new instance is declared. If not null * its length must be the same as the largest polynomial 'a' or 'b'. * @return Polynomial 'a' and 'b' added together. */ public static Polynomial add( Polynomial a , Polynomial b , Polynomial results ) { int N = Math.max(a.size,b.size); if( results == null ) { results = new Polynomial(N); } else if( results.size < N ) { throw new IllegalArgumentException("storage for results must be at least as large as the the largest polynomial"); } else { for( int i = N; i < results.size; i++ ) { results.c[i] = 0; } } int M = Math.min(a.size,b.size); for( int i = 0; i < M; i++ ) { results.c[i] = a.c[i] + b.c[i]; } // copy the non-overlapping coefficients for the larger polynomial if( a.size > b.size ) { for( int i = b.size; i < N; i++ ) results.c[i] = a.c[i]; } else { for( int i = a.size; i < N; i++ ) results.c[i] = b.c[i]; } return results; } public static int countRealRoots( Polynomial poly ) { SturmSequence sturm = new SturmSequence(poly.size); sturm.initialize(poly); return sturm.countRealRoots(Double.NEGATIVE_INFINITY,Double.POSITIVE_INFINITY); } /** * Creates different polynomial root finders. * * @param maxCoefficients The maximum number of coefficients that will be processed. This is the order + 1 * @param which 0 = Sturm and 1 = companion matrix. * @return PolynomialRoots */ public static PolynomialRoots createRootFinder( int maxCoefficients , RootFinderType which ) { switch( which ) { case STURM: FindRealRootsSturm sturm = new FindRealRootsSturm(maxCoefficients,-1,1e-10,200,200); return new WrapRealRootsSturm(sturm); case EVD: return new RootFinderCompanion(); default: throw new IllegalArgumentException("Unknown algorithm: "+which); } } /** * Returns a real root to the cubic polynomial: 0 = c0 + c1*x + c2*x^2 + c3*c^3. There can be other * real roots. * * WARNING: This technique is much less stable than using one of the RootFinder algorithms * * @param c0 Polynomial coefficient for power 0 * @param c1 Polynomial coefficient for power 1 * @param c2 Polynomial coefficient for power 2 * @param c3 Polynomial coefficient for power 3 * @return A real root of the polynomial */ public static double cubicRealRoot( double c0 , double c1 , double c2 , double c3 ) { // convert it into this format: r + q*x + p*x^2 + x^3 = 0 double p = c2/c3; double q = c1/c3; double r = c0/c3; // reduce by substitution x = y - p/3 which results in y^3 + a*y + b = 0 double a = (3*q - p*p)/3.0; double b = (2*p*p*p - 9*p*q + 27*r)/27.0; double left = -b/2.0; double right = Math.sqrt(b*b/4.0 + a*a*a/27.0); double inner1 = left+right; double inner2 = left-right; double A,B; if( inner1 < 0 ) A = -Math.pow(-inner1,1.0/3.0); else A = Math.pow(inner1,1.0/3.0); if( inner2 < 0 ) B = -Math.pow(-inner2,1.0/3.0); else B = Math.pow(inner2,1.0/3.0); return (A + B) - p/3.0; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy