User guide

User guide


TaylorSeries.jl is a basic polynomial algebraic manipulator in one or more variables; these two cases are treated separately. Three new types are defined, Taylor1, HomogeneousPolynomial and TaylorN, which correspond to expansions in one independent variable, homogeneous polynomials of various variables, and the polynomial series in many independent variables, respectively. These types are subtypes of AbstractSeries, which in turn is a subtype of Number, and are defined parametrically.

The package is loaded as usual:

julia> using TaylorSeries

One independent variable

Taylor expansions in one variable are represented by the Taylor1 type, which consists of a vector of coefficients (fieldname coeffs) and the maximum order considered for the expansion (fieldname order). The coefficients are arranged in ascending order with respect to the degree of the monomial, so that coeffs[1] is the constant term, coeffs[2] gives the first order term (t^1), etc. Yet, it is possible to have the natural ordering with respect to the degree; see below. This is a dense representation of the polynomial. The order of the polynomial can be omitted in the constructor, which is then fixed by the length of the vector of coefficients. If the length of the vector does not correspond with the order, order is used, which effectively truncates polynomial to degree order.

julia> Taylor1([1, 2, 3],4) # Polynomial of order 4 with coefficients 1, 2, 3
 1 + 2 t + 3 t² + 𝒪(t⁵)

julia> Taylor1([0.0, 1im]) # Also works with complex numbers
 ( 1.0 im ) t + 𝒪(t²)

julia> Taylor1(ones(8), 2) # Polynomial truncated to order 2
 1.0 + 1.0 t + 1.0 t² + 𝒪(t³)

julia> shift_taylor(a) = a + Taylor1(typeof(a),5)  ## a + taylor-polynomial of order 5
shift_taylor (generic function with 1 method)

julia> t = shift_taylor(0.0) # Independent variable `t`
 1.0 t + 𝒪(t⁶)

Note that the information about the maximum order considered is displayed using a big-𝒪 notation. In some cases, it is desirable to not display the big-𝒪 notation. The function displayBigO allows to control whether it is displayed or not.

julia> displayBigO(false) # turn-off displaying big O notation
false

julia> t
 1.0 t

julia> displayBigO(true) # turn it on
true

julia> t
 1.0 t + 𝒪(t⁶)

The definition of shift_taylor(a) uses the method Taylor1([::Type{Float64}], [order::Int64=1]), which is a shortcut to define the independent variable of a Taylor expansion, of given type and order (defaults are Float64 and order=1). This is one of the easiest ways to work with the package.

The usual arithmetic operators (+, -, *, /, ^, ==) have been extended to work with the Taylor1 type, including promotions that involve Numbers. The operations return a valid Taylor expansion of maximum order. This is apparent in the last example below, where the answer is beyond the order of the expansion.

julia> t*(3t+2.5)
 2.5 t + 3.0 t² + 𝒪(t⁶)

julia> 1/(1-t)
 1.0 + 1.0 t + 1.0 t² + 1.0 t³ + 1.0 t⁴ + 1.0 t⁵ + 𝒪(t⁶)

julia> t*(t^2-4)/(t+2)
 - 2.0 t + 1.0 t² + 𝒪(t⁶)

julia> tI = im*t
 ( 1.0 im ) t + 𝒪(t⁶)

julia> (1-t)^3.2
 1.0 - 3.2 t + 3.5200000000000005 t² - 1.4080000000000004 t³ + 0.07040000000000009 t⁴ + 0.011264000000000012 t⁵ + 𝒪(t⁶)

julia> (1+t)^t
 1.0 + 1.0 t² - 0.5 t³ + 0.8333333333333333 t⁴ - 0.75 t⁵ + 𝒪(t⁶)

julia> t^6  # t is of order 5
 0.0 + 𝒪(t⁶)

If no valid Taylor expansion can be computed, an error is thrown, for instance when a derivative is not defined (or simply diverges):

julia> 1/t
ERROR: ArgumentError: Division does not define a Taylor1 polynomial;
order k=0 => coeff[0]=Inf.

julia> t^3.2
ERROR: ArgumentError: The 0th order Taylor1 coefficient must be non-zero
to raise the Taylor1 polynomial to a non-integer exponent.

julia> abs(t)
ERROR: ArgumentError: The 0th order Taylor1 coefficient must be non-zero
(abs(x) is not differentiable at x=0).

Several elementary functions have been implemented; their coefficients are computed recursively. At the moment of this writing, these functions are exp, log, sqrt, the trigonometric functions sin, cos and tan, their inverses, as well as the hyperbolic functions sinh, cosh and tanh and their inverses; more will be added in the future. Note that this way of obtaining the Taylor coefficients is not the laziest way, in particular for many independent variables. Yet, it is quite efficient, especially for the integration of ordinary differential equations, which is among the applications we have in mind (see also TaylorIntegration.jl).

julia> exp(t)
 1.0 + 1.0 t + 0.5 t² + 0.16666666666666666 t³ + 0.041666666666666664 t⁴ + 0.008333333333333333 t⁵ + 𝒪(t⁶)

julia> log(1-t)
 - 1.0 t - 0.5 t² - 0.3333333333333333 t³ - 0.25 t⁴ - 0.2 t⁵ + 𝒪(t⁶)

julia> sqrt(1 + t)
 1.0 + 0.5 t - 0.125 t² + 0.0625 t³ - 0.0390625 t⁴ + 0.02734375 t⁵ + 𝒪(t⁶)

julia> imag(exp(tI)')
 - 1.0 t + 0.16666666666666666 t³ - 0.008333333333333333 t⁵ + 𝒪(t⁶)

julia> real(exp(Taylor1([0.0,1im],17))) - cos(Taylor1([0.0,1.0],17)) == 0.0
true

julia> convert(Taylor1{Rational{Int64}}, exp(t))
 1//1 + 1//1 t + 1//2 t² + 1//6 t³ + 1//24 t⁴ + 1//120 t⁵ + 𝒪(t⁶)

Again, errors are thrown whenever it is necessary.

julia> sqrt(t)
ERROR: ArgumentError: First non-vanishing Taylor1 coefficient must correspond
to an **even power** in order to expand `sqrt` around 0.

julia> log(t)
ERROR: ArgumentError: The 0-th order `TaylorN` coefficient must be non-zero
in order to expand `log` around 0.

To obtain a specific coefficient, getcoeff can be used. Another alternative is to request the specific degree using the vector notation, where the index corresponds to the degree of the term.

julia> expon = exp(t)
 1.0 + 1.0 t + 0.5 t² + 0.16666666666666666 t³ + 0.041666666666666664 t⁴ + 0.008333333333333333 t⁵ + 𝒪(t⁶)

julia> getcoeff(expon, 0) == expon[0]
true

julia> rationalize(expon[3])
1//6

Differentiating and integrating is straightforward for polynomial expansions in one variable, using derivative and integrate. These functions return the corresponding Taylor1 expansions. The last coefficient of a derivative is set to zero to keep the same order as the original polynomial; for the integral, an integration constant may be set by the user (the default is zero). The order of the resulting polynomial is not changed. The value of the $n$-th ($n \ge 0$) derivative is obtained using derivative(n,a), where a is a Taylor series.

julia> derivative(exp(t))
 1.0 + 1.0 t + 0.5 t² + 0.16666666666666666 t³ + 0.041666666666666664 t⁴ + 𝒪(t⁶)

julia> integrate(exp(t))
 1.0 t + 0.5 t² + 0.16666666666666666 t³ + 0.041666666666666664 t⁴ + 0.008333333333333333 t⁵ + 𝒪(t⁶)

julia> integrate( exp(t), 1.0)
 1.0 + 1.0 t + 0.5 t² + 0.16666666666666666 t³ + 0.041666666666666664 t⁴ + 0.008333333333333333 t⁵ + 𝒪(t⁶)

julia> integrate( derivative( exp(-t)), 1.0 ) == exp(-t)
true

julia> derivative(1, exp(shift_taylor(1.0))) == exp(1.0)
true

julia> derivative(5, exp(shift_taylor(1.0))) == exp(1.0) # 5-th derivative of `exp(1+t)`
true

To evaluate a Taylor series at a given point, Horner's rule is used via the function evaluate(a, dt). Here, dt is the increment from the point $t_0$ around which the Taylor expansion of a is calculated, i.e., the series is evaluated at $t = t_0 + dt$. Omitting dt corresponds to $dt = 0$; see evaluate.

julia> evaluate(exp(shift_taylor(1.0))) - e # exp(t) around t0=1 (order 5), evaluated there (dt=0)
0.0

julia> evaluate(exp(t), 1) - e # exp(t) around t0=0 (order 5), evaluated at t=1
-0.0016151617923783057

julia> evaluate(exp( Taylor1(17) ), 1) - e # exp(t) around t0=0, order 17
0.0

julia> tBig = Taylor1(BigFloat, 50) # Independent variable with BigFloats, order 50
 1.000000000000000000000000000000000000000000000000000000000000000000000000000000 t + 𝒪(t⁵¹)

julia> eBig = evaluate( exp(tBig), one(BigFloat) )
2.718281828459045235360287471352662497757247093699959574966967627723419298053556

julia> e - eBig
6.573322999985292556154129119543257102601105719980995128942636339920549561322098e-67

Another way to obtain the value of a Taylor1 polynomial p at a given value x, is to call p as if it were a function, i.e., p(x):

julia> t = Taylor1(15)
 1.0 t + 𝒪(t¹⁶)

julia> p = sin(t)
 1.0 t - 0.16666666666666666 t³ + 0.008333333333333333 t⁵ - 0.0001984126984126984 t⁷ + 2.7557319223985893e-6 t⁹ - 2.505210838544172e-8 t¹¹ + 1.6059043836821616e-10 t¹³ - 7.647163731819817e-13 t¹⁵ + 𝒪(t¹⁶)

julia> evaluate(p, pi/2) # value of p at pi/2 using `evaluate`
0.9999999999939766

julia> p(pi/2) # value of p at pi/2 by evaluating p as a function
0.9999999999939766

julia> p(pi/2) == evaluate(p, pi/2)
true

julia> p(0.0)
0.0

julia> p() == p(0.0) # p() is a shortcut to obtain the 0-th order coefficient of `p`
true

Note that the syntax p(x) is equivalent to evaluate(p, x), whereas p() is equivalent to evaluate(p). For more details about function-like behavior for a given type in Julia, see the Function-like objects section of the Julia manual.

Useful shortcuts are taylor_expand are update!. The former returns the expansion of a function around a given value t0. In turn, update! provides an in-place update of a given Taylor polynomial, that is, it shifts it further by the provided amount.

julia> p = taylor_expand( x -> sin(x), pi/2, order=16) # 16-th order expansion of sin(t) around pi/2
 1.0 + 6.123233995736766e-17 t - 0.5 t² - 1.020538999289461e-17 t³ + 0.041666666666666664 t⁴ + 5.102694996447305e-19 t⁵ - 0.001388888888888889 t⁶ - 1.2149273801065013e-20 t⁷ + 2.48015873015873e-5 t⁸ + 1.6873991390368074e-22 t⁹ - 2.7557319223985894e-7 t¹⁰ - 1.5339992173061888e-24 t¹¹ + 2.08767569878681e-9 t¹² + 9.833328316065313e-27 t¹³ - 1.1470745597729726e-11 t¹⁴ - 4.682537293364434e-29 t¹⁵ + 4.779477332387386e-14 t¹⁶ + 𝒪(t¹⁷)

julia> update!(p, 0.025) # updates the expansion given by p, by shifting it further by 0.025

julia> p
 0.9996875162757026 - 0.02499739591471227 t - 0.49984375813785126 t² + 0.004166232652452044 t³ + 0.0416536465114876 t⁴ - 0.00020831163262260228 t⁵ - 0.0013884548837162537 t⁶ + 4.959800776728625e-6 t⁷ + 2.4793837209218816e-5 t⁸ - 6.888612189900868e-8 t⁹ - 2.7548708010243125e-7 t¹⁰ + 6.262374718092001e-10 t¹¹ + 2.0870233341100357e-9 t¹² - 4.014342754938811e-12 t¹³ - 1.1467160989730436e-11 t¹⁴ + 1.9117909329549495e-14 t¹⁵ + 4.779477332387386e-14 t¹⁶ + 𝒪(t¹⁷)

Many variables

A polynomial in $N>1$ variables can be represented in (at least) two ways: As a vector whose coefficients are homogeneous polynomials of fixed degree, or as a vector whose coefficients are polynomials in $N-1$ variables. The current implementation of TaylorSeries.jl corresponds to the first option, though some infrastructure has been built that permits to develop the second one. An elegant (lazy) implementation of the second representation was discussed here.

The structure TaylorN is constructed as a vector of parameterized homogeneous polynomials defined by the type HomogeneousPolynomial, which in turn is a vector of coefficients of given order (degree). This implementation imposes the user to specify the (maximum) order considered and the number of independent variables at the beginning, which can be conveniently done using set_variables. A vector of the resulting Taylor variables is returned:

julia> x, y = set_variables("x y")
2-element Array{TaylorSeries.TaylorN{Float64},1}:
  1.0 x + 𝒪(‖x‖⁷)
  1.0 y + 𝒪(‖x‖⁷)

julia> typeof(x)
TaylorSeries.TaylorN{Float64}

julia> x.order
6

julia> x.coeffs
7-element Array{TaylorSeries.HomogeneousPolynomial{Float64},1}:
    0.0
  1.0 x
    0.0
    0.0
    0.0
    0.0
    0.0

As shown, the resulting objects are of TaylorN{Float64} type. There is an optional order keyword argument in set_variables, used to specify the maximum order of the TaylorN polynomials. Note that one can specify the variables using a vector of symbols.

julia> set_variables([:x, :y], order=10)
2-element Array{TaylorSeries.TaylorN{Float64},1}:
  1.0 x + 𝒪(‖x‖¹¹)
  1.0 y + 𝒪(‖x‖¹¹)

Similarly, numbered variables are also available by specifying a single variable name and the optional keyword argument numvars:

julia> set_variables("α", numvars=3)
3-element Array{TaylorSeries.TaylorN{Float64},1}:
  1.0 α₁ + 𝒪(‖x‖¹¹)
  1.0 α₂ + 𝒪(‖x‖¹¹)
  1.0 α₃ + 𝒪(‖x‖¹¹)

Alternatively to set_variables, get_variables can be used if one doesn't want to change internal dictionaries. get_variables returns a vector of TaylorN independent variables of a desired order (lesser than get_order so the internals doesn't have to change) with the length and variable names defined by set_variables initially.

julia> get_variables(order=2) #vector of independent variables of order 2
3-element Array{TaylorSeries.TaylorN{Float64},1}:
  1.0 α₁ + 𝒪(‖x‖³)
  1.0 α₂ + 𝒪(‖x‖³)
  1.0 α₃ + 𝒪(‖x‖³)

The function show_params_TaylorN displays the current values of the parameters, in an info block.

julia> show_params_TaylorN()
Info: Parameters for `TaylorN` and `HomogeneousPolynomial`:
Maximum order       = 10
Number of variables = 3
Variable names      = String["α₁", "α₂", "α₃"]
Variable symbols    = Symbol[:α₁, :α₂, :α₃]

Internally, changing the parameters (maximum order and number of variables) redefines the hash-tables that translate the index of the coefficients of a HomogeneousPolynomial of given order into the corresponding multi-variable monomials, or the other way around. Fixing these values from the start is imperative; the initial (default) values are order = 6 and num_vars=2.

The easiest way to construct a TaylorN object is by defining the independent variables. This can be done using set_variables as above, or through the method TaylorN{T<:Number}(::Type{T}, nv::Int) for the nv independent TaylorN{T} variable; the order can be also specified using the optional keyword argument order.

julia> x, y = set_variables("x y", numvars=2, order=6);

julia> x
 1.0 x + 𝒪(‖x‖⁷)

julia> TaylorN(1, order=4) # variable 1 of order 4
 1.0 x + 𝒪(‖x‖⁵)

julia> TaylorN(Int, 2)    # variable 2, type Int, order=get_order()=6
 1 y + 𝒪(‖x‖⁷)

Other ways of constructing TaylorN polynomials involve using HomogeneousPolynomial objects directly, which is uncomfortable.

julia> set_variables(:x, numvars=2); # symbols can be used

julia> HomogeneousPolynomial([1,-1])
 1 x₁ - 1 x₂

julia> TaylorN([HomogeneousPolynomial([1,0]), HomogeneousPolynomial([1,2,3])],4)
 1 x₁ + 1 x₁² + 2 x₁ x₂ + 3 x₂² + 𝒪(‖x‖⁵)

The Taylor expansions are implemented around 0 for all variables; if the expansion is needed around a different value, the trick is a simple translation of the corresponding independent variable, i.e. $x \to x+a$.

As before, the usual arithmetic operators (+, -, *, /, ^, ==) have been extended to work with TaylorN objects, including the appropriate promotions to deal with numbers. (Some of the arithmetic operations have been extended for HomogeneousPolynomial, whenever the result is a HomogeneousPolynomial; division, for instance, is not extended.)

Also, the elementary functions have been implemented, again by computing their coefficients recursively:

julia> x, y = set_variables("x y", order=10);

julia> exy = exp(x+y)
 1.0 + 1.0 x + 1.0 y + 0.5 x² + 1.0 x y + 0.5 y² + 0.16666666666666666 x³ + 0.5 x² y + 0.5 x y² + 0.16666666666666666 y³ + 0.041666666666666664 x⁴ + 0.16666666666666666 x³ y + 0.25 x² y² + 0.16666666666666666 x y³ + 0.041666666666666664 y⁴ + 0.008333333333333333 x⁵ + 0.041666666666666664 x⁴ y + 0.08333333333333333 x³ y² + 0.08333333333333333 x² y³ + 0.041666666666666664 x y⁴ + 0.008333333333333333 y⁵ + 0.0013888888888888887 x⁶ + 0.008333333333333331 x⁵ y + 0.020833333333333332 x⁴ y² + 0.027777777777777776 x³ y³ + 0.020833333333333332 x² y⁴ + 0.008333333333333331 x y⁵ + 0.0013888888888888887 y⁶ + 0.00019841269841269839 x⁷ + 0.0013888888888888885 x⁶ y + 0.004166666666666666 x⁵ y² + 0.006944444444444443 x⁴ y³ + 0.006944444444444443 x³ y⁴ + 0.004166666666666666 x² y⁵ + 0.0013888888888888885 x y⁶ + 0.00019841269841269839 y⁷ + 2.4801587301587298e-5 x⁸ + 0.00019841269841269836 x⁷ y + 0.0006944444444444443 x⁶ y² + 0.0013888888888888887 x⁵ y³ + 0.0017361111111111108 x⁴ y⁴ + 0.0013888888888888887 x³ y⁵ + 0.0006944444444444443 x² y⁶ + 0.00019841269841269836 x y⁷ + 2.4801587301587298e-5 y⁸ + 2.7557319223985884e-6 x⁹ + 2.4801587301587295e-5 x⁸ y + 9.920634920634918e-5 x⁷ y² + 0.0002314814814814814 x⁶ y³ + 0.0003472222222222221 x⁵ y⁴ + 0.0003472222222222221 x⁴ y⁵ + 0.0002314814814814814 x³ y⁶ + 9.920634920634918e-5 x² y⁷ + 2.4801587301587295e-5 x y⁸ + 2.7557319223985884e-6 y⁹ + 2.7557319223985883e-7 x¹⁰ + 2.7557319223985884e-6 x⁹ y + 1.2400793650793647e-5 x⁸ y² + 3.306878306878306e-5 x⁷ y³ + 5.787037037037036e-5 x⁶ y⁴ + 6.944444444444443e-5 x⁵ y⁵ + 5.787037037037036e-5 x⁴ y⁶ + 3.306878306878306e-5 x³ y⁷ + 1.2400793650793647e-5 x² y⁸ + 2.7557319223985884e-6 x y⁹ + 2.7557319223985883e-7 y¹⁰ + 𝒪(‖x‖¹¹)

The function getcoeff gives the normalized coefficient of the polynomial that corresponds to the monomial specified by a vector v containing the powers. For instance, for the polynomial exy above, the coefficient of the monomial $x^3 y^5$ is

julia> getcoeff(exy, [3,5])
0.0013888888888888887

julia> rationalize(ans)
1//720

Similar to Taylor1, vector notation can be used to request specific coefficients of HomogeneousPolynomial or TaylorN objects. For TaylorN objects, the index refers to the degree of the HomogeneousPolynomial. In the case of HomogeneousPolynomial the index refers to the position of the hash table. The function show_monomials can be used to obtain the coefficient a specific monomial, given the degree of the HomogeneousPolynomial.

julia> exy[8] # get the 8th order term
 2.4801587301587298e-5 x⁸ + 0.00019841269841269836 x⁷ y + 0.0006944444444444443 x⁶ y² + 0.0013888888888888887 x⁵ y³ + 0.0017361111111111108 x⁴ y⁴ + 0.0013888888888888887 x³ y⁵ + 0.0006944444444444443 x² y⁶ + 0.00019841269841269836 x y⁷ + 2.4801587301587298e-5 y⁸

julia> show_monomials(8)
 1  -->  x⁸
 2  -->  x⁷ y
 3  -->  x⁶ y²
 4  -->  x⁵ y³
 5  -->  x⁴ y⁴
 6  -->  x³ y⁵
 7  -->  x² y⁶
 8  -->  x y⁷
 9  -->  y⁸

julia> exy[8][6] # get the 6th coeff of the 8th order term
0.0013888888888888887

Partial differentiation is also implemented for TaylorN objects, through the function derivative, specifying the number of the variable, or its symbol, as the second argument.

julia> p = x^3 + 2x^2 * y - 7x + 2
 2.0 - 7.0 x + 1.0 x³ + 2.0 x² y + 𝒪(‖x‖¹¹)

julia> q = y - x^4
 1.0 y - 1.0 x⁴ + 𝒪(‖x‖¹¹)

julia> derivative( p, 1 )   # partial derivative with respect to 1st variable
 - 7.0 + 3.0 x² + 4.0 x y + 𝒪(‖x‖¹¹)

julia> derivative( q, :y )  # partial derivative with respect to :y
 1.0 + 𝒪(‖x‖¹¹)

If we ask for the partial derivative with respect to a non-defined variable, an error is thrown.

julia> derivative( q, 3 )   # error, since we are dealing with 2 variables
ERROR: AssertionError: 1 ≤ r ≤ get_numvars()

Integration with respect to the r-th variable for HomogeneousPolynomials and TaylorN objects is obtained using integrate. Note that integrate for TaylorN objects allows to specify a constant of integration, which must be independent from the integrated variable. Again, the integration variable may be specified by its symbol.

julia> integrate( derivative( p, 1 ), 1) # integrate with respect to the first variable
 - 7.0 x + 1.0 x³ + 2.0 x² y + 𝒪(‖x‖¹¹)

julia> integrate( derivative( p, 1 ), :x, 2) # integration with respect to :x, constant of integration is 2
 2.0 - 7.0 x + 1.0 x³ + 2.0 x² y + 𝒪(‖x‖¹¹)

julia> integrate( derivative( q, 2 ), :y, -x^4) == q
true

julia> integrate( derivative( q, 2 ), 2, y)
ERROR: AssertionError: The integration constant ( 1.0 y + 𝒪(‖x‖¹¹)) must be independent of the
y variable

evaluate can also be used for TaylorN objects, using it on vectors of numbers (Real or Complex); the length of the vector must coincide with the number of independent variables. evaluate also allows to specify only one variable and a value.

julia> evaluate(exy, [.1,.02]) == exp(0.12)
true

julia> evaluate(exy, :x, 0.0) == exp(y)  # evaluate `exy` for :x -> 0
true

Analogously to Taylor1, another way to obtain the value of a TaylorN polynomial p at a given point x, is to call it as if it were a function: the syntax p(x) for p::TaylorN is equivalent to evaluate(p,x), and p() is equivalent to evaluate(p).

julia> exy([.1,.02]) == exp(0.12)
true

julia> exy(:x, 0.0)
 1.0 + 1.0 y + 0.5 y² + 0.16666666666666666 y³ + 0.041666666666666664 y⁴ + 0.008333333333333333 y⁵ + 0.0013888888888888887 y⁶ + 0.00019841269841269839 y⁷ + 2.4801587301587298e-5 y⁸ + 2.7557319223985884e-6 y⁹ + 2.7557319223985883e-7 y¹⁰ + 𝒪(‖x‖¹¹)

The functions taylor_expand and update! work as well for TaylorN.

julia> xysq = x^2 + y^2
 1.0 x² + 1.0 y² + 𝒪(‖x‖¹¹)

julia> update!(xysq, [1.0, -2.0]) # expand around (1,-2)

julia> xysq
 5.0 + 2.0 x - 4.0 y + 1.0 x² + 1.0 y² + 𝒪(‖x‖¹¹)

julia> update!(xysq, [-1.0, 2.0]) # shift-back

julia> xysq == x^2 + y^2
true

Functions to compute the gradient, Jacobian and Hessian have also been implemented. Using the polynomials $p = x^3 + 2x^2 y - 7 x + 2$ and $q = y-x^4$ defined above, we may use gradient (or ); the results are of type Array{TaylorN{T},1}. To compute the Jacobian and Hessian of a vector field evaluated at a point, we use respectively jacobian and hessian:

julia> ∇(p)
2-element Array{TaylorSeries.TaylorN{Float64},1}:
  - 7.0 + 3.0 x² + 4.0 x y + 𝒪(‖x‖¹¹)
                    2.0 x² + 𝒪(‖x‖¹¹)

julia> gradient( q )
2-element Array{TaylorSeries.TaylorN{Float64},1}:
  - 4.0 x³ + 𝒪(‖x‖¹¹)
       1.0 + 𝒪(‖x‖¹¹)

julia> r = p-q-2*p*q
 2.0 - 7.0 x - 5.0 y + 14.0 x y + 1.0 x³ + 2.0 x² y + 5.0 x⁴ - 2.0 x³ y - 4.0 x² y² - 14.0 x⁵ + 2.0 x⁷ + 4.0 x⁶ y + 𝒪(‖x‖¹¹)

julia> hessian(ans)
2×2 Array{Float64,2}:
  0.0  14.0
 14.0   0.0

julia> jacobian([p,q], [2,1])
2×2 Array{Float64,2}:
  13.0  8.0
 -32.0  1.0

julia> hessian(r, [1.0,1.0])
2×2 Array{Float64,2}:
 -26.0  20.0
  20.0  -8.0

Other specific applications are described in the Examples.

Mixtures

As mentioned above, Taylor1{T}, HomogeneousPolynomial{T} and TaylorN{T} are parameterized structures such that T<:AbstractSeries, the latter is a subtype of Number. Then, we may actually define Taylor expansions in $N+1$ variables, where one of the variables (the Taylor1 variable) is somewhat special.

julia> x, y = set_variables("x y", order=3)
2-element Array{TaylorSeries.TaylorN{Float64},1}:
  1.0 x + 𝒪(‖x‖⁴)
  1.0 y + 𝒪(‖x‖⁴)

julia> t1N = Taylor1([zero(x), one(x)], 5)
 ( 1.0 + 𝒪(‖x‖⁴)) t + 𝒪(t⁶)

The last line defines a Taylor1{TaylorN{Float64}} variable, which is of order 5 in t and order 3 in x and y. Then, we can evaluate functions involving such polynomials:

julia> cos(2.1+x+t1N)
  - 0.5048461045998576 - 0.8632093666488737 x + 0.2524230522999288 x² + 0.14386822777481229 x³ + 𝒪(‖x‖⁴) + ( - 0.8632093666488737 + 0.5048461045998576 x + 0.43160468332443686 x² - 0.0841410174333096 x³ + 𝒪(‖x‖⁴)) t + ( 0.2524230522999288 + 0.43160468332443686 x - 0.1262115261499644 x² - 0.07193411388740614 x³ + 𝒪(‖x‖⁴)) t² + ( 0.14386822777481229 - 0.0841410174333096 x - 0.07193411388740614 x² + 0.0140235029055516 x³ + 𝒪(‖x‖⁴)) t³ + ( - 0.0210352543583274 - 0.03596705694370307 x + 0.0105176271791637 x² + 0.005994509490617178 x³ + 𝒪(‖x‖⁴)) t⁴ + ( - 0.007193411388740615 + 0.00420705087166548 x + 0.0035967056943703073 x² - 0.00070117514527758 x³ + 𝒪(‖x‖⁴)) t⁵ + 𝒪(t⁶)

This kind of expansions are of interest when studying the dependence of parameters, for instance in the context of bifurcation theory or when considering the dependence of the solution of a differential equation on the initial conditions, around a given solution. In this case, x and y represent small variations around a given value of the parameters, or around some specific initial condition. Such constructions are exploited in the package TaylorIntegration.jl.