{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# \n", "\n", "# Functions in Julia\n", "\n", "Read more about this [here](http://mth229.github.io/functions.html).\n", "\n", "For some problems herein, you will need features made available in the\n", "add-on `MTH229` package, which is loaded with the following command:" ], "id": "bac896ae-8883-46e9-a530-aafe5f7b5160" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "using MTH229" ], "id": "2" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(When you run the cell to load the `MTH229` – and other add-on packages\n", "– an asterisk will appear in the label to the left of the cell: `[*]`.\n", "When the packages have been loaded, which can take awhile, the asterisk\n", "will turn into a number.)\n", "\n", "This command loads the `Plots` package, which we will use in these\n", "notes." ], "id": "68785d7b-dbef-4d7a-88e4-c9b9908633e0" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "using Plots" ], "id": "4" }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will typically combine these and run this command when loading a\n", "`Julia` notebook at the *start* of a session:" ], "id": "daaa94e0-71ff-4f64-9d4d-02afa37f7680" }, { "cell_type": "code", "execution_count": 0, "metadata": {}, "outputs": [], "source": [ "using MTH229\n", "using Plots\n", "plotly()" ], "id": "6" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(The last command loads a plotting backend which allows some\n", "interactivity.)\n", "\n", "------------------------------------------------------------------------\n", "\n", "A *function* in mathematics is [defined](http://tinyurl.com/c2rwqyb) as\n", "“a relation between a set of inputs and a set of permissible outputs\n", "with the property that each input is related to exactly one output.”\n", "That is a general definition. Specialized to mathematical functions of\n", "one real variable returning a real value (univariate, scalar-valued\n", "functions), we can define a function in terms of a rule—what happens to\n", "$x$ to produce $y$, such as this one which squares $x$ then subtracts\n", "$2$:\n", "\n", "$$\n", "f(x) = x^2 - 2.\n", "$$\n", "\n", "The **domain** of a function is the set of all permissible values for\n", "$x$, in this example this is all $x$, but this need not be the case\n", "either due to the rule not being defined for some $x$ or a more explicit\n", "restriction, such as $x \\geq 0$.\n", "\n", "The **range** is the set of all possible outputs. Written in set\n", "notation, this is $\\{f(x): x \\in \\text{ the domain }\\}$.\n", "\n", "Mathematically, we evaluate or **call** a function with the notation\n", "$f(2)$ or $f(3)$, say.\n", "\n", "Mathematically we might refer to the function by its name, $f$, or its\n", "values such as $f(2)$ or $f(\\pi)$.\n", "\n", "In `Julia` basic mathematical functions are defined and used with the\n", "*exact* same notation, save for accommodations in translating math to\n", "`Julia`.\n", "\n", "For example, this command creates a function `f`:" ], "id": "e184b50a-9c5e-4259-b83d-dc95b9ecd6d8" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "f (generic function with 1 method)" ] } } ], "source": [ "f(x) = x^2 - 2" ], "id": "10" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike an expression, the value `x` in the definition of `f(x)` does not\n", "need to be defined until the function is actually called. As with math,\n", "this variable name need not be `x` – it could be `t`, `y`, `theta`, or\n", "any other valid name.\n", "\n", "We *call* `f` for the given value using the same `f(x)` notation. For\n", "example, finding our `f` at the value of `2` is done with:" ], "id": "cfe76dd5-93d7-4c72-8981-74ae8b5908b9" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "2" ] } } ], "source": [ "f(2)" ], "id": "12" }, { "cell_type": "markdown", "metadata": {}, "source": [ "That is, as with typical mathematical notation, the function is “called”\n", "by passing a value to it with parentheses.\n", "\n", "Within a cell, we can evaluate one or more values by using commas to\n", "separate them:" ], "id": "17b20110-4d2b-4c48-9680-9e0f9177aa56" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "(-1, 2, 7)" ] } } ], "source": [ "f(1), f(2), f(3)" ], "id": "14" }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function name refers to the function object:" ], "id": "c8022a24-6c5d-4d29-9df0-b4973d8787da" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "f (generic function with 1 method)" ] } } ], "source": [ "f" ], "id": "16" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Don’t worry about the words “generic” and “method”, but be aware that\n", "because of this once you have defined a name as a variable it can not be\n", "re-purposed as a *generic* function name and vice versa. (In the common\n", "first case, read the error message, it will say something like:\n", "`ERROR: cannot define function a; it already has a value`.)\n", "\n", "The “domain” of a `Julia` function is similar in meaning to its\n", "mathematical counterpart. `Julia` may respond with different values,\n", "such as `Inf`, for infinity; `NaN`, when an expression is indeterminate;\n", "or it may throw an error, typically a `DomainError`:" ], "id": "254c0af3-1016-4acc-9336-4d5a7a98da54" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "(Inf, NaN)" ] } } ], "source": [ "f(x) = sqrt(x)/(x*(1-x))\n", "f(1), f(0)" ], "id": "18" }, { "cell_type": "markdown", "metadata": {}, "source": [ "and an error with:" ], "id": "01cc183d-eadc-4d02-ba24-9061b029d169" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "f(-1)" ], "id": "20" }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions can be more complicated than the “one-liners” illustrated. In\n", "that case, a multiline form is available:" ], "id": "016183da-256d-4d91-85f8-a3fa0f2d5aa4" }, { "cell_type": "code", "execution_count": 0, "metadata": {}, "outputs": [], "source": [ "function fn_name(args...)\n", " body\n", "end" ], "id": "22" }, { "cell_type": "markdown", "metadata": {}, "source": [ "The keyword `function` indicates this is a function whose name is given\n", "in the definition. Within the body, the last expression evaluated is the\n", "output, unless a `return` statement is used.\n", "\n", "------------------------------------------------------------------------\n", "\n", "For basic uses of functions—90 percent of the uses in this class—the\n", "above covers what you need to know about functions.\n", "\n", "## Cases\n", "\n", "Some functions are defined in terms of cases. For example, a cell phone\n", "plan might depend on the data used through:\n", "\n", "> The amount is 35 dollars for the first 9 Gb of data, and 10 dollars\n", "> more for each *additional* Gb of data.\n", "\n", "This function has two cases to consider: one if the data is less than 9\n", "Gb and the other when it is more.\n", "\n", "In a math class we would write this as:\n", "\n", "$$\n", "\\text{cost}(\\text{data}) = \\begin{cases}\n", "35.0, & \\text{data} \\leq 9.0 \\\\\\\\\n", "35.0+10.0\\cdot(\\text{data}-9.0), & \\text{otherwise.}\n", "\\end{cases}\n", "$$\n", "\n", "How to write this in `Julia`?\n", "\n", "The ternary operator `predicate ? expression1 : expression2` has three\n", "pieces: a predicate question, such as `x < 10` and two expressions, the\n", "first is evaluated if the predicate is `true` and the second if the\n", "predicate is `false`. Using the ternary operator, simple case-like\n", "functions can be defined in one line.\n", "\n", "For example, the above can be defined in `Julia` with:" ], "id": "9e100a8b-be93-42a3-8d83-fd0bf631c4f3" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "cost (generic function with 1 method)" ] } } ], "source": [ "cost(data) = data <= 9.0 ? 35.00 : 35.00 + 10.00 * (data - 9.0)" ], "id": "24" }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, three pieces: **First**, you ask a question. **Second**, what should\n", "the function do if the answer is ‘yes’? **Third**, what should the\n", "function do if the answer is ‘no’?\n", "\n", "## Composition\n", "\n", "Composition of functions is a useful means to break complicated problems\n", "into easier to solve ones. The math notation is typically $f(g(x))$ and\n", "in `Julia` this is no different.\n", "\n", "## Functions may need more than one argument\n", "\n", "In `Julia` some functions require more than one argument. There are two\n", "ways that a function can distinguish between arguments:\n", "\n", "**Using position**. A typical case is the function expressing the $\\log$\n", "of $x$ base $b$. The function must have both a position to pass in\n", "values for either $x$ or $b$. In `Julia` the function is written\n", "`log(b, x)`:" ], "id": "57f8581a-2b4f-48fe-9cde-00eaedf89869" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "8.526512829121202e-14" ] } } ], "source": [ "b, x = 5, 100\n", "a = log(b, x)\n", "b^a - x # verify, is this close to 0?" ], "id": "26" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(This also shows that `Julia` can have the same name for **different**\n", "functions, as `log(x)` does the logarithm base $e$ and takes only $1$\n", "argument.)\n", "\n", "**Using keyword names**. Some arguments can be designated by a\n", "“keyword”, which have default values. This is heavily used with the\n", "plotting package we use, where data is specified by position and\n", "attributes of the resulting figure are adjusted with keyword arguments.\n", "Plotting features are provided in add-on packages; we use `Plots` in\n", "these projects.\n", "\n", "Here is a mathematical example from the theory of\n", "[wavelets](https://en.wikipedia.org/wiki/Wavelet).\n", "\n", "Define `mother` by" ], "id": "13682c88-4b7b-4dff-9361-7f9a8f7606e8" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "mother (generic function with 1 method)" ] } } ], "source": [ "mother(x) = (sin(2*pi*x) - sin(pi*x))/(pi*x)" ], "id": "28" }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function is *scaled* and *shifted* in application. To keep track of\n", "the scale (by `a`) and the shift (by `b`) we might define a function\n", "that allows these to be passed as *parameters*" ], "id": "26ecd727-c425-41a1-bab0-00f556a61f7c" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "child (generic function with 1 method)" ] } } ], "source": [ "child(x, a, b) = mother((x-b)/a) / sqrt(a)" ], "id": "30" }, { "cell_type": "markdown", "metadata": {}, "source": [ "This would then be called like:" ], "id": "15981910-6856-4348-add5-1070566ce250" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "-0.6366197723675813" ] } } ], "source": [ "child(1/2, 1, 0)" ], "id": "32" }, { "cell_type": "markdown", "metadata": {}, "source": [ "or like" ], "id": "be8384d1-1ed7-4153-8dee-3306ed3c7454" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "0.2636965437895248" ] } } ], "source": [ "child(1/2, 2, 1)" ], "id": "34" }, { "cell_type": "markdown", "metadata": {}, "source": [ "(It isn’t illustrated, but there are means to make default values for\n", "the parameters.)\n", "\n", "## Functions can be used as arguments to other functions:\n", "\n", "Calculus has three main operations: The limit of a *function*, the\n", "derivative of a *function*, and the integral of a *function*. These\n", "operations take a function and compute some value. For limits this value\n", "is a number, for derivatives this value is another function. In `Julia`\n", "we will use functions to implement each.\n", "\n", "Using `Julia` operations on functions are just functions where the\n", "*arguments* are themselves functions and, *possibly*, the return value\n", "is also a function.\n", "\n", "The first example we will encounter is related to plotting. The details\n", "come later:" ], "id": "0844578e-ca51-4894-83e2-5f0eb798d9cd" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/html": [ "" ] } } ], "source": [ "f(x) = sin(x^2)\n", "plot(f, 0, pi)" ], "id": "36" }, { "cell_type": "markdown", "metadata": {}, "source": [ "The first argument to `plot` is a function object–not a function call,\n", "as in `f(x)`, the second and third describe an interval to plot over.\n", "This will be a typical pattern: `someaction(f, arguments...)`.\n", "\n", "When a function returns a function, we may simply assign it a name. For\n", "example, there is a `tangent` function in the `MTH229` package takes a\n", "function `f` and a point `c` and returns a function that computes the\n", "tangent line to `f` at `c`. Here we give it a name:" ], "id": "1aab84c3-41f4-4e05-8ec1-a532215da999" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "Function of `x` to compute the tangent line of `f` at `c`:\n", " f(c) + f'(c) * (x-c)" ] } } ], "source": [ "tl = tangent(f, pi/4)" ], "id": "38" }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is called, just like other functions:" ], "id": "874e30ab-6523-42f8-a6fa-6cc472b10570" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/plain": [ "(0.38460897507732444, 0.3772017669761397)" ] } } ], "source": [ "f(pi/5), tl(pi/5)" ], "id": "40" }, { "cell_type": "markdown", "metadata": {}, "source": [ "------------------------------------------------------------------------" ], "id": "43dd7a49-3593-4221-a94c-2ae19a521004" }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Enter your commands here\n" ], "id": "42" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernel_info": { "name": "julia" }, "kernelspec": { "name": "julia", "display_name": "Julia", "language": "julia" }, "language_info": { "name": "julia", "codemirror_mode": "julia", "version": "1.10.0" } } }