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

Engage with the code in this post by downloading the Wolfram Notebook

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.

Any comments or suggestions about the new functionality are welcome.

## Acknowledgements

It is a pleasure to thank Roger Germundsson for his elegant design of the new functionality; Adam Strzebonski for his outstanding implementation of this feature; Itai Seggev and Michal Strzebonski for their creativity in preparing the documentation examples; and Tim Shedelbower for the striking illustration at the top of the blog post.

Get full access to the latest Wolfram Language functionality with a Mathematica 12.2 or Wolfram|One trial. |

## Comments