Browse by Topic
Related Topics

# Is Your Function Continuous? Squaring Away the New Function Properties in the Wolfram Language

The Wolfram Language has several hundred built-in functions, ranging from sine to Heun. As a user, you can extend this collection in infinitely many ways by applying arithmetic operations and function composition. This could lead you to defining expressions of bewildering complexity, such as the following:

 ✕ ```f = SinhIntegral[ LogisticSigmoid[ ScorerHi[Tanh[AiryAi[HermiteH[-(1/2), x] - x + 1]]]]]; ```

You may then ask, “Is continuous?” or “Can be written as a composition of an increasing function with another function?” The powerful new tools for studying function properties in Version 12.2 provide quick answers to such questions—opening the doors for applying a network of theorems and ideas that have been developed by mathematicians during the last few centuries.

## Functions through the Ages

The ancient Babylonians constructed tables for the squares and cubes of natural numbers (nowadays, we would refer to them as functions defined on the set of natural numbers). Although more informal uses of functions were made during the centuries that followed, the systematic use of functions commenced after the discovery of analytic geometry by René Descartes. In particular, Sir Isaac Newton made extensive use of power series representations for functions in his development of calculus.

Gottfried Leibniz, the co-inventor of calculus, made the first formal use of the word “function” in 1673. Next, Leonhard Euler took a giant leap forward when he identified a function with its analytic expression (essentially, a formula). Euler’s simple characterization of a function was questioned by Joseph Fourier, who gave examples of discontinuous functions that could be represented by infinite trigonometric series—showing that analytic expressions were inadequate for describing functions that commonly arise in many practical applications.

Augustin-Louis Cauchy, Karl Weierstrass and Bernhard Riemann developed the theory of complex functions, in which the singularities of functions determine their global behavior in the complex plane. Complex functions also provided the correct setting for the magnificent theory of elliptic functions and integrals, developed by mathematical geniuses Niels Henrik Abel and Carl Jacobi.

Since then, the function concept has continued to evolve, driven by the needs of pure and applied mathematics. These days, we think of a function simply as an abstract, many-to-one relation between arbitrary sets of objects.

## Squares and Cubes

Let’s begin our exploration of the new function properties in Version 12.2 by using the Babylonian examples of the square and cube functions (denoted by and , respectively):

 ✕ `s[x_] := x^2`
 ✕ `c[x_] := x^3`

Here is a plot of the functions:

 ✕ ```GraphicsRow[{Plot[s[x], {x, -5, 5}, PlotLabel -> "Square"], Plot[ c[x], {x, -5, 5}, PlotLabel -> "Cube"]}]```

As shown in the following, a horizontal line drawn above the axis intersects the first graph at a pair of points, while any horizontal line intersects the second graph at exactly one point:

 ✕ ```GraphicsRow[{Plot[{s[x], 20}, {x, -5, 5}], Plot[{c[x], 20}, {x, -5, 5}]}]```

Thus, is not injective (one-to-one), while is injective. This can be confirmed by using FunctionInjective:

 ✕ `FunctionInjective[s[x], x]`
 ✕ `FunctionInjective[c[x], x]`

Similarly, by considering horizontal lines drawn below the axis, one can conclude that is not surjective (onto), while is surjective:

 ✕ `{FunctionSurjective[s[x], x], FunctionSurjective[c[x], x]}`

Combining these two facts, we conclude that the seemingly simple square function is not bijective (one-to-one and onto), while the less elementary cube function has this property:

 ✕ `{FunctionBijective[s[x], x], FunctionBijective[c[x], x]}`

On the other hand, the square function is non-negative everywhere, while the cube function takes on both positive and negative values. This can be expressed succinctly by using FunctionSign as follows:

 ✕ `{FunctionSign[s[x], x], FunctionSign[c[x], x]}`

The situation is reversed if strict positivity is enforced for the square function and the domain of the cube function is restricted to the positive real numbers:

 ✕ ```{FunctionSign[s[x], x, StrictInequalities -> True], FunctionSign[{c[x], x > 0}, x]}```

Finally, note that the square and cube functions belong to the family of polynomial functions, and therefore are both continuous:

 ✕ `{FunctionContinuous[s[x], x], FunctionContinuous[c[x], x]}`

## Trigs and Inverse Trigs

The trigonometric functions are traditionally regarded as elementary, but they provide nontrivial examples for some of the deeper function properties that are available in the latest release.

The sine function, Sin, occurs in problems such as those involving mechanical and electrical oscillations. It’s not a polynomial function, but it can be represented by a power series (a polynomial without a last term!) and is therefore an analytic function. This can be confirmed by using FunctionAnalytic:

 ✕ `FunctionAnalytic[Sin[x], x]`

Here are the first few terms of its power series expansion:

 ✕ `Asymptotic[Sin[x], {x, 0, 12}]`

The following plot shows that the approximation is valid over a limited range of :

 ✕ ```Plot[Evaluate[{Sin[x], %}], {x, -2 Pi, 2 Pi}, PlotStyle -> Thickness[0.01]]```

The tangent function, Tan, is our first example of a meromorphic function (i.e. a function that is analytic everywhere, except at isolated pole singularities):

 ✕ `FunctionMeromorphic[Tan[x], x]`

Tan inherits its singularities from the zeros of its denominator, Cos:

 ✕ `FunctionSingularities[Tan[x], x]`

Plot uses a knowledge of these singularities to provide an accurate graph of Tan:

 ✕ `Plot[Tan[x], {x, -5 Pi/2, 5 Pi/2}]`

In contrast to Tan, its inverse, ArcTan, is smooth—as is its composition with the square function:

 ✕ `FunctionAnalytic[ArcTan[x^2], x]`

A Plot of the function on the real line confirms this property:

 ✕ `Plot[ArcTan[x^2], {x, -5, 5}]`

However, the extension of this function to the complex plane results in singularities, as shown here:

 ✕ `FunctionSingularities[ArcTan[z^2], z, Complexes]`

Reduce can be used to obtain a detailed description of these singularities:

 ✕ `Reduce[%, z]`

Here is a pretty ComplexPlot of the function and its singularities:

 ✕ ```ComplexPlot[ArcTan[z^2], {z, -2 - 2 I, 2 + 2 I}, ExclusionsStyle -> Red]```

The situation described here, in which the extension of a function to the complex plane leads to singularities, is commonplace in the study of mathematical functions, and will be encountered again in the next section.

## Elliptic Functions

The elliptic functions, which arise in the study of nonlinear oscillations and many other applications, have an air of mystery about them because they are seldom discussed in undergraduate courses. They become a little less mysterious when they are studied alongside the trigonometric functions.

In order to illustrate them, consider JacobiSN (analogous to Sin in the elliptic world):

 ✕ ```Plot[JacobiSN[x, 1/4], {x, -20, 20}, PlotStyle -> {Red, Thickness[0.01]}]```

Like the sine function, JacobiSN is an analytic and periodic function of :

 ✕ `FunctionAnalytic[JacobiSN[x, 1/4], x]`
 ✕ `FunctionPeriod[JacobiSN[x, 1/4], x]`

The situation changes dramatically when this function is extended to the complex plane. This happens because JacobiSN is a quotient of EllipticTheta functions, which are themselves analytic and quasi-doubly periodic functions of .

During the division process, JacobiSN picks up singularities from the complex zeros of its denominator, while a certain phase factor miraculously cancels out to make it doubly periodic. Thus:

 ✕ `FunctionMeromorphic[JacobiSN[z, 1/4], z]`
 ✕ `FunctionPeriod[JacobiSN[z, 1/4], z, Complexes]`

Here is a plot of JacobiSN that shows the singularities of the function, as well as the tessellation of the plane that results from the double periodicity:

 ✕ ```ContourPlot[ Re[JacobiSN[x + I y, 1/2]], {x, -4, 4}, {y, -4, 4}, Sequence[ Contours -> 20, FrameTicks -> {{{(-2) EllipticK[ Rational[1, 2]], -EllipticK[ Rational[1, 2]], 0, EllipticK[ Rational[1, 2]], 2 EllipticK[ Rational[1, 2]]}, None}, {{(-2) EllipticK[ Rational[1, 2]], 0, 2 EllipticK[ Rational[1, 2]]}, None}}]]```

The theory of elliptic functions is unmatched in its elegance and was pursued by many outstanding nineteenth-century mathematicians—including Charles Hermite, who once remarked, “I cannot leave the elliptic domain. Where the goat is attached she must graze.” I urge you to explore this wonderful subject further using the built-in elliptic functions and integrals in the Wolfram Language.

## The Piecewise World

Piecewise-defined functions occur naturally in electrical engineering, finance and other applications. Discontinuities can arise at the boundaries where the different pieces of such a function are stitched together. FunctionDiscontinuities gives the location of these discontinuities.

For example, consider RealSign, which indicates the sign of the real number :

 ✕ `Plot[RealSign[x], {x, -1, 1}]`

FunctionDiscontinuities confirms that RealSign has a discontinuity at :

 ✕ `FunctionDiscontinuities[RealSign[x], x]`

On the other hand, this function can be approximated by a continuous Fourier sine series:

 ✕ `FourierTrigSeries[RealSign[x], x, 15]`

The overshoot (or “ringing”) of the Fourier series at the jump discontinuity in the following plot is a manifestation of the Gibbs phenomenon:

 ✕ ```Plot[Evaluate[{RealSign[x], %}], {x, -1, 1}, PlotStyle -> Thickness[0.01]]```

As another example, let’s compute the discontinuities of , where θ is the Heaviside step function:

 ✕ ```f = x + Cos[x] UnitStep[Sin[x]]; FunctionDiscontinuities[f, x]```

The discontinuity points between and can be found using Reduce as follows:

 ✕ `Solve[% && -5*Pi <= x <= 5*Pi, x, Reals]`

The function and its discontinuities are visualized here:

 ✕ ```Plot[f, {x, -5 Pi, 5 Pi}, Epilog -> {Red, Dotted, InfiniteLine[{x, 0}, {0, 1}] /. %}]```

Finally, here is an injective Piecewise function that is not monotonic:

 ✕ ```f = Piecewise[{{x, Sin[\[Pi] x] >= 0}, {2 Ceiling[x] - 1 - x, Sin[\[Pi] x] < 0}}]; Plot[f, {x, 0, 10}]```
 ✕ ```{FunctionInjective[{f, 0 < x < 10}, x], FunctionMonotonicity[{f, 0 < x < 10}, x]}```

## Special Functions

The Wolfram Language has over 250 special functions, including the classical special functions from mathematical physics as well as more modern functions that were created due to their relevance for probability and statistics or other application domains.

The new function properties are very useful for solving problems involving special functions. We use them here to find the global minimum for the example function from the introduction:

 ✕ ```f = SinhIntegral[ LogisticSigmoid[ ScorerHi[Tanh[AiryAi[HermiteH[-(1/2), x] - x + 1]]]]]; ```

To begin, define the functions and by:

 ✕ ```g = SinhIntegral[LogisticSigmoid[ScorerHi[Tanh[z]]]]; h = HermiteH[-1/2, x] - x + 1;' title='h = HermiteH[-1/2, x] - x + 1;```

The function is monotonic on the real line:

 ✕ `FunctionMonotonicity[g, z]`

Next, the function can be written as a composition of and AiryAi[h]:

 ✕ `f === (g /. z -> AiryAi[h])`

Now, as indicated by the following plot, AiryAi has infinitely many local minima:

 ✕ `Plot[AiryAi[x], {x, -30, 30}]`

Its global minimum cannot be found by computing all its local minima.

However, Minimize has built-in knowledge about global minima of special functions and quickly finds the required global minimum value:

 ✕ `Minimize[AiryAi[x], x]`

It now suffices to show that the global minimum point of AiryAi is among the values attained by . As a first step in the proof, note that:

 ✕ `{Limit[h, x -> -\[Infinity]], Limit[h, x -> \[Infinity]]}`

By the intermediate value theorem, to prove that attains all real values, it suffices to show that it is continuous, which can be done using FunctionContinuous:

 ✕ `FunctionContinuous[h, x]`

Also, is monotonic:

 ✕ `FunctionMonotonicity[h, x]`

Hence, the global minimum of is unique.

Minimize automatically uses a similar method to find the minimum value of :

 ✕ `Minimize[f, x]`

Finally, here is a plot of along with its unique global minimum value:

 ✕ ```Plot[f, {x, -30, 30}, Epilog -> { PointSize[Large], Red, Point[{ ReplaceAll[x, Part[ Out[], 2]], Part[ Out[], 1]}]}] // Quiet```

## Multivariable Functions

All the examples considered so far have used a single real or complex variable. Let’s look at a few examples for computing function properties of multivariable functions, using the spectacular visualization capabilities of the Wolfram Language to illustrate the results.

As a first example, consider the real bivariate function defined here:

 ✕ `f = (x^2 + y^2) Csc[x y];`

The singularities of are simply the zeros of its “denominator” :

 ✕ `FunctionSingularities[f, {x, y}]`

The following graphic captures the complicated nature of the singularities of :

 ✕ ```Plot3D[f, {x, -3, 3}, {y, -3, 3}, Sequence[ ExclusionsStyle -> Directive[ Opacity[0.7], Red], PlotPoints -> 50]]```

Next, multivariate rational functions such as the following are always meromorphic:

 ✕ ```{FunctionMeromorphic[(x^2 - y^2 + 1)/(x^2 - y), {x, y}], FunctionMeromorphic[(x^2 - y^2)/(x^2 + y^2 + 1), {x, y}]}```

However, unlike functions of a single variable, the singularities of such functions will typically lie along curves. For example, the singularities of the first function (shown in the previous image) lie along the parabola :

 ✕ ```Plot3D[(x^2 - y^2 + 1)/(x^2 - y), {x, -3, 3}, {y, -3, 3}, Sequence[ ClippingStyle -> None, BoxRatios -> 1, PlotPoints -> 100]]```

On the other hand, plotting the second function in the Re Im plane shows the blowup of this function along the hyperbolas :

 ✕ ```Plot3D[(x^2 + (I y)^2)/(x^2 + (y I)^2 + 1), {x, -4, 4}, {y, -4, 4}, ClippingStyle -> None, BoxRatios -> 1]```

The Beta function provides an interesting example of a meromorphic, multivariate special function:

 ✕ `FunctionMeromorphic[Beta[x, y], {x, y}]`

In fact, Beta can be considered a multivariate rational function in Gamma:

 ✕ `Beta[x, y] // FunctionExpand`

The following plot shows the singularities of the function, which arise due to the poles of the Gamma factors being at negative integer values:

 ✕ ```Plot3D[Beta[x, y], {x, -2, 2}, {y, -2, 2}, Sequence[ PlotPoints -> 150, ClippingStyle -> None]]```

Finally, here is an example of a strictly convex function:

 ✕ ```f = (x - 3 y - 7)^2 + (x + y - 5)^2 + (2 x - 3 y - 4)^2; FunctionConvexity[f, {x, y}, StrictInequalities -> True]```

Such a function has at most one local minimum, which can be found in this case by using Minimize:

 ✕ `{mval, mpoint} = Minimize[f, {x, y}]`

The following plot shows along with its unique global minimum:

 ✕ ```Show[{Plot3D[{f, mval}, {x, -5, 5}, {y, -5, 5}, PlotStyle -> Opacity[0.7]], Graphics3D[{Red, PointSize[Large], Point[ ReplaceAll[{x, y, mval}, mpoint]]}]}]```

## Documentation

You can learn more about the new function properties in the latest release by exploring their reference pages, which demonstrate the scope of each function and include applications to geometry, calculus and other areas, in the Wolfram Language & System Documentation Center.

Many of the examples in this blog post were drawn from the reference pages for FunctionDiscontinuities, FunctionConvexity, etc. I recommend exploring the new documentation for this functionality further, starting from the guide page.

Since Version 1 of the Wolfram Language was released in 1988, a variety of mathematical functions have been added. The function properties introduced in Version 12.2 will serve to unify this vast collection of functions by classifying them based on a few characteristics, such as continuity, analyticity, etc.