NAME
Math::Yapp - Perl extension for working with Polynomials. Yes, I know there are *many!* Polynomial packages. And like them, I started it for (geeky) fun, then got obsessed with it as a learning experience. Enjoy!
AUTHOR
Jacob Salomon, jakesalomon@yahoo.com
COPYRIGHT AND LICENSE
Copyright (C) 2013 by Jacob Salomon
SYNOPSIS
use Math::Complex;
# Optional but a very good idea, since solving a polynomial often yields complex numbers
use Math::Yapp;
Constructors
$yp = Math::Yapp-
>new();
# Degenerate polynomial - no terms
While the new() method is certainly available, your code will look cleaner if you use this form:
$yp = Yapp(parameter(s)); # Examples follow
Real and complex coefficiencts
$yp = Yapp(1, -2.178, 3.14, -cplx(1,-3), 5);
Yields: 5x^4 +(-1+3i)x^3 +3.14x^2 -2.178x +1
Same as above, only passed as a reference to an array:
my @coef_list = (1, -2.178, 3.14, -cplx(1,-3), 5);
$yp = Yapp(\@coef_list);
Generated from a string: Note that the sign MUST precede each term with no intervening space; a space separating the sign from the term may mess up the matching pattern. Yes, the + sign is optional for the first term in the string.
$yp = Yapp("5x^4 +(-1+3i)x^3 +3.14x^2 -2.178x +1");
The Yapp() constructor function has one additional feature that was awkward to implement in the new() constructor: An explicit copy constructor:
Copy from the above Yapp polynomial [referenced by] $yp:
$yp1 = Yapp($yp);
# Clones $yp to an identical copy at a different reference
Constructors by interpolation
$ypl = Yapp_interpolate(\@xvals, \@yvals);
# Perform Lagrange interpolation
$yph = Yapp_interpolate(\@xvals, \@yvals, \@ypvals);
# Hermite interpolation
Note that the interpolating constructors require array references; otherwise you run into the elementary error of array-mashing. The Lagrange form, just X and Y values, generates a polynomial that colocates at each of the points indicated in the X-Y pairs represented by the arrays. For The Hermite version the third array [reference] if for the desired derivative at each point.
(At this time, the author waives Hermite interpolation for more than the first derivative. :-)
Constructing a Yapp polynomial from its roots
$yp = Yapp_by_roots(\@root_list);
# Pass reference to an array of roots
$yp = Yapp_by_roots(1, 2, -4, cplx(3,4), cplx(3,-1));
# Pass a complete array to constructor
Arithmetic of Yapp Polynomials
Unary Operations
$yp2 = !$yp; # Change the signs of all coefficients
$yp2 = $yp1-
>negate();
# (The overloaded function)
$yp2 = ~$yp; # Conjugate complex coefficients
Addition and Subtraction
$yp += 13; # Add a real value to the constant term
$yp += cplx(2, -5); # Add a complex number to the constant term
$yp += $yp3; # Add another polynomial to this one
$yp = $yp1 + $yp2; # Add two polynomials, term-by-term
Subtracting polynomials: Behaved pretty much like the adds so we are not inclucing all possible examples
$yp -= $yp3; # Subtract $yp3 from $yp in place
$yp = $yp1 - $yp2; # Subtract two polynomials, term-by-term
Multiplication and division:
$yp *= 42; # Multiply each coefficient by the same number
$yp = $yp1 * 42; # Multiply as above but return a new polynomial
$yp = 42 * $yp1; # (Same idea as above)
$yp *= $yp2; # Multiply the indicated polynomial by another, in place.
$yp = $yp1 * $yp2; # Same as above, but not in-place
$yp /= 10; # Divide all coefficients by a number
Division by a polynomial is not defined in this package, although when I evaluate a polynomials at, say, x = 3, it is equivalent to dividing by the small polynomial (x - 3). Hence, for Yapp_eval (described later), you have the option of getting the quotient besides the evaluation
Documented methods and functions:
Ysprint() formats a Yapp object into a string, suitable for printing: Example: printf("My yapp is: %s\n", Ysprint($yp1));
By default, Ysprint formats the polynmial as follows:
Starting from the high-order exponent, working its way down
All coefficients are displayed with 3 decimal places
Zero coefficients are skipped.
This can be controlled by the following functions, which affect module-global variables:
Yapp_start_high(0);
# Setting FALSE: Start from low-degree termsYapp_decimals(2);
# Set number of decimal places to displayYapp_print0(1);
# Ysprint shall display 0-value coefficients
In all three cases, the newly value is returned. Oh, and if you call it without a parameter, it will just return the currently set value
my $high_expon = $yp-
>degree();
# Get the degree of the polynomial
$yp-
variable>>("Xy");
# Sets the variable used in printing a polynomial. Default: "X"
my $varname = $yp-
>variable();
# Returns that variable string
my $nterm = $yp-
>coefficient(3);
# Retrieve the coefficient on the term of degree 3 (in this example)
my $realvar = $yp-
>Yapp_eval($areal);
# Plug the parameter into the polynomial and return the value
my $cplxvar = $yp-
>Yapp_eval($acplx);
# Works identially for complex numbers, except that now it returns a reference to a Math::Complex
my ($eval, $quotient) = $yp-
>Yapp_eval($areal);
# This returns the evaluation and also a ref to a new, lower-degree polynomial that is the quotient.
my $ypr = $yp-
>Yapp_reduce(3);
# Return a reference to a new polynomial whose roots are those of of the given polynomial, reduced [in this case] by 3
my $dyp = $yp-
>Yapp_derivative(n);
# Returns [a ref to] another polynomial that is the nth derivative of this one.
my $i_ref = $yp-
>Yapp_integral();
# Returns a reference to a polynomial whose derivative is the given Yapp. Inserts a 0 for the arbitrary constant.
my $i_val = $yp-
>Yapp_integral($low, $high);
# Calculates the value of the definite integral of the given Yapp in the given interval.
Solution Set for Polynomials
my @solutions = $yp-
>Yapp_solve();
# Solve for all real and complex roots
DESCRIPTION
Man, if that synopsis don't say it all, what can I possibly add? :-)
OK, as mentioned above, this is a fun project. The plan, not necessarily all implemented at the first release, is to provide many kinds of operations on the polynomials that intimidated us in high school and even college (if you took PDE or Numerical Analysis). The usual high-school functions are ordinary arithmetic on these algebraic expressions, as well as plugging a value in there to get the result. (Horner's synthetic division saves a lot of work.)
Notes on derivatives and integrals
If n is omitted, it returns first derivative
If n is 0, it returns the same Yapp reference
All derivatives, as well as the indefinite integral, are cached in an internal array on the object. If anything mutates the object (like a += operation) the cache is cleared
Addendum: A Note on Inner products and orthogonal polynomials;
At this stage, the plan is to provide the inner product algorithms for various classes of inner-product spaces but in separate modules, for example: Math::Yapp:Tchebycheff or Math::Yapp::Laguerre. These will use the overloaded "dot" operator. A future release of this module, may include the simplest class of orthogonality, the scheme used in Gaussian quadrature, that is the inner product defined as the intergral of the product of the polynomials over the interval [-1,1]. .. But not today.
EXPORT
This package export the following functions by default. (They are few enough to be an unlikey source of name-space pollution, IMHO)
Yapp(): The constructor that is NOT a method, so you don't have to type Math::Yapp::new().
Yapp_interpolate(): The constructor by Lagrange and Hermite interpolation
Yapp_by_roots(): Construct a polynomial by its roots
Yapp_decimals(): Sets or retrives a global setting for how many decimal places to display with each %f-formatted variable.
Yapp_print0(): By default, printing a Yapp will skip any term whose coefficient is 0. This exported function sets an internal global flag to either display 0-coefficient terms (1) or to skip them (0)
Yapp_start_high(): By default, printing a Yapp will start from the highest coefficient, the way we are accustomed to writing a polynomial. For some testing purposes and, I imagine, some other applications, it may be neater to start printing from the low-degree coefficients. This functions sets an intenal global flag to print high-to-low (default: 1) or low-to-high (0).
Bugs
Note that the current release of Math::Yapp uses the default floating-point library of its host system. It was developed in a Cygwin environment running under Windows-7. I discovered some limitations to the 64 (or 80?) bit FP operations when solving polynomials of degree higher thatn 8 or using Hermite interpolation of more than 6 points. I have researched Math::MPC a bit and hope to use that in a future release of this module. However, I encountered some errors when trying to compile the required MPC, MPFR and GMP C libraries. So that plan is going on the back burner.
There is some sloppy code in method Ysprint() which produces the correct output but I would really rather figure out why I needed to add said sloppy code. The bug this covers up is that the first degree term should display without exponent, not as X^1. Similarly, the constant term should display with neither variable nor exponent, rather than as X^0.
It might be argued that my failure to include higher-order derivatives in the Hermite interpolation scheme is a bug. Perhaps by the time I publish the next release of this module I will have an understanding of Newton's Method of Divided Differences. (Sorry, no promises on that account.)
The usual disclaimers :-)
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available.
Acknowledements
Thanks to John Altom, formerly of CCM Consulting Services, for his help in some basic (but arguable forgettable) details of the EXPORT behavior.
An old debt of gratitude to [the presumably late] Professor Stanley Preisler, who taught Numerical Analysis at Polytechnic University in the late '70s. The course was quite over my head but some stuff remained, as you can see.