Consider a function $f: R^n \rightarrow R$. It has multiple arguments for its input (an $x_1, x_2, \dots, x_n$) and only one, *scalar*, value for an output. Some simple examples might be:

\[ ~ \begin{align} f(x,y) &= x^2 + y^2\\ g(x,y) &= x \cdot y\\ h(x,y) &= \sin(x) \cdot \sin(y) \end{align} ~ \]

For two examples from real life consider the elevation Point Query Service (of the USGS) returns the elevation in international feet or meters for a specific latitude/longitude within the United States. The longitude can be associated to an $x$ coordinate, the latitude to a $y$ coordinate, and the elevation a $z$ coordinate, and as long as the region is small enough, the $x$-$y$ coordinates can be thought to lie on a plane. (A flat earth assumption.)

Similarly, a weather map, say of the United States, may show the maximum predicted temperature for a given day. This describes a function that take a position ($x$, $y$) and returns a predicted temperature ($z$).

Mathematically, we may describe the values $(x,y)$ in terms of a point, $P=(x,y)$ or a vector $\vec{v} = \langle x, y \rangle$ using the identification of a point with a vector. As convenient, we may write any of $f(x,y)$, $f(P)$, or $f(\vec{v})$ to describe the evaluation of $f$ at the value $x$ and $y$

Before proceeding with how to define such functions in `Julia`

, we load our package:

using CalculusWithJulia using Plots

Returning to the task at hand, in `Julia`

, defining a scalar function is straightforward, the syntax following mathematical notation:

f(x,y) = x^2 + y^2 g(x,y) = x * y h(x,y) = sin(x) * sin(y)

h (generic function with 1 method)

To call a scalar function for specific values of $x$ and $y$ is also similar to the mathematical case:

f(1,2), g(2, 3), h(3,4)

(5, 6, -0.10679997423758245)

It may be advantageous to have the values as a vector or a point, as in `v=[x,y]`

. Splatting can be used to turn a vector or tuple into two arguments:

v = [1,2] f(v...)

5

Alternatively, the function may be defined using a vector argument:

f(v) = v[1]^2 + v[2]^2

f (generic function with 2 methods)

A style required for other packages within the `Julia`

ecosystem.

More verbosely, but avoiding index notation, we can use multiline functions:

function g(v) x, y = v x * y end

g (generic function with 2 methods)

Then we have

f(v), g([2,3])

(5, 6)

More elegantly, and the approach we will use, is to mirror the mathematical notation through multiple dispatch. If we define `f`

for multiple variables, say with:

f(x,y) = x^2 - 2x*y^2

f (generic function with 2 methods)

The we can define an alternative method with just a single variable and use splatting to turn it into multiple variables:

f(v) = f(v...)

f (generic function with 2 methods)

The we can call `f`

with a vector or point:

f([1,2])

-7

or by passing in the individual components:

f(1,2)

-7

Following a calculus perspective, we take up the question of how to visualize scalar functions within `Julia`

? Further, how to describe the change in the function between nearby values?

Suppose for the moment that $f:R^2 \rightarrow R$. The equation $z = f(x,y)$ may be visualized by the set of points in 3-dimensions $\{(x,y,z): z = f(x,y)\}$. This will render as a surface, and that surface will pass a "vertical line test", in that each $(x,y)$ value corresponds to at most one $z$ value. We will see alternatives for describing surfaces beyond through a function of the form $z=f(x,y)$. These are similar to how a curve in the $x$-$y$ plane can be described by a function of the form $y=f(x)$ but also through an equation of the form $F(x,y) = c$ or through a parametric description, such as is used for planar curves. For now though we focus on the case where $z=f(x,y)$.

In `Julia`

, plotting such a surface requires a generalization to plotting a univariate function where, typically, a grid of evenly spaced values is given between some $a$ and $b$, the corresponding $y$ or $f(x)$ values are found, and then the points are connected in a dot-to-dot manner.

Here, a two-dimensional grid of $x$-$y$ values needs specifying, and the corresponding $z$ values found. As the grid will be assumed to be regular only the $x$ and $y$ values need specifying, the set of pairs can be computed. The $z$ values, it will be seen, are easily computed. This cloud of points is plotted and each cell in the $x$-$y$ plane is plotted with a surface giving the $x$-$y$-$z$, 3-dimensional, view. One way to plot such a surface is to tessalate the cell and then for each triangle, represent a plane made up of the 3 boundary points.

Here is an example:

f(x, y) = x^2 + y^2 xs = range(-2, 2, length=100) ys = range(-2, 2, length=100) surface(xs, ys, f)

The `surface`

function will generate the surface.

Using `surface`

as a function name is equivalent to `plot(xs, ys, f, seriestype=:surface)`

.

We can also use `surface(xs, ys, zs)`

where `zs`

is not a vector, but rather a *matrix* of values corresponding to a grid described by the `xs`

and `ys`

. A matrix is a rectangular collection of values indexed by row and column through indices `i`

and `j`

. Here the values in `zs`

should satisfy: the $i$th row and $j$th column entry should be $z_{ij} = f(x_i, y_j)$ where $x_i$ is the $i$th entry from the `xs`

and $y_j$ the $j$th entry from the `ys`

.

We can generate this using a comprehension:

zs = [f(x,y) for y in ys, x in xs] surface(xs, ys, zs)

If remembering that the $y$ values go first, and then the $x$ values in the above is too hard, then an alternative can be used. Broadcasting `f.(xs,ys)`

may not make sense, were the `xs`

and `ys`

not of commensurate lengths, and when it does, this call pairs off `xs`

and `ys`

values and passes them to `f`

. What is desired here is different, where for each `xs`

value there are pairs for each of the `ys`

values. The syntax `xs'`

can ve viewed as creating a *row* vector, where `xs`

is a *column* vector. Broadcasting will create a *matrix* of values in this case. So the following is identical to the above:

surface(xs, ys, f.(xs', ys))