{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Variables, Control Structures & Packages" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Variables and elementary types\n", "\n", "Defining variables in Julia works like in most languages:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "int = 4 # An integer" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "str = \"Hi\" # A string" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "float = 1.2 # A floating-point number" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "bool = true # A boolean (also false)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The type is automatically inferred:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "typeof(int)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "typeof(str)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "typeof(float)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia supports a large range of integer and floating-point types out of the box, for example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = UInt8(1) # 8-bit wide unsigned integer\n", "y = Int32(-1) # 32-bit wide signed integer\n", "z = Float32(0.2) # single precision\n", "α = Float16(-1.0) # half precision\n", "β = ComplexF64(2. + 8im) # Complex number (composed of two Float64)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Operations** between these types may involve **automatic promotion**." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "println(typeof(1 + 1.2))\n", "println(typeof(x * y)) # x was Uint8, y was Int32" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = Float32(1.)\n", "4x # No \"*\" needed" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "println(5 % 2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "5^6" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "2.3^6" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "println(4 - Float32(2))\n", "println(8 / 3) # Note conversion to Float64\n", "typeof(8 / 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can be avoided using a rational:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 6 // 3\n", "println(typeof(x), \" \", Int(x))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "√2 # == sqrt(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice the `*` operation for **string concatenation** ..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\"Concatenating \" * \"strings is done \" * \"using multiplication\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Type conversion** is possible, for example using constructors:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Int(2.0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = Float32(1.0)\n", "Float64(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Int(2.3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "UInt8(-1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Float64(2.0 + 1im)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes a special conversion function or syntax exists:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "string(1.2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ceil(Int, 2.3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "round(Int32, 4.5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 1.2\n", "println(\"x is currently $x.\")\n", "println(\"two less is $(x - 2)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Arbitrary precision** is supported out of the box:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# arbitrary precision\n", "b = big\"12\"; println(b, \" is a \", typeof(b))\n", "f = big\"-1.2\"; println(f, \" is a \", typeof(f))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Or wir an explicit cast:\n", "b = BigInt(12)\n", "f = BigFloat(-1.2) # Note the difference to the above result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia is garbage-collected, meaning that memory occupied by a variable value will be freed automatically if no longer needed, e.g.:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 15\n", "println(x)\n", "x = \"abc\"; # x newly assigned, memory by the \"15\" will be freed at some point in the future" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise\n", "Compute $2^{100}$:\n", "- As fast as possible\n", "- As exact as possible" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### For more details\n", "- https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/\n", "- https://docs.julialang.org/en/v1/manual/mathematical-operations/\n", "- https://docs.julialang.org/en/v1/manual/strings/\n", "- https://docs.julialang.org/en/v1/manual/conversion-and-promotion/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic control structures\n", "\n", "Unsurprisingly Julia has the standard `for` and `while` loops and the `if` conditionals." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 3; y = 5\n", "\n", "if x < y\n", " println(\"x is less than y\")\n", "elseif x > y\n", " println(\"x is greater than y\")\n", "else\n", " println(\"x is equal to y\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 5\n", "while x > 3\n", " println(\"Now x is $x\")\n", " x -= 1\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in 1:5\n", " println(\"Hello from number $i\")\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Where the `1:5` is a `Range`-object, but it could be any iterable. There are a few syntax variations, including:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "accu = 0\n", "for j ∈ 1:0.5:3 # Note the step parameter\n", " accu += j\n", "end\n", "println(accu)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Worth mentioning are also `||`, `&&` and `?:`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "true || println(\"The RHS of || is only run\")\n", "false || println(\"if the LHS is false\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "iseven(3) && println(\"The RHS of || is only run\")\n", "isodd(3) && println(\"if the LHS is true\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = 3\n", "x < 5 ? \"smaller than 5\" : \"larger or equal 5\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generally expressions can be made one block using `begin` and `end` or `(` and `)`. The last statement determines the returned value." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "z = begin\n", " x = 5\n", " y = -3\n", " x + y\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Or equivalently\n", "z = (x = 5; y = -3; x + y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise\n", "Compute\n", "$$ 15! \\qquad 100! \\qquad \\left(\\begin{array}{c} 100 \\\\ 15 \\end{array}\\right) $$\n", "with the Julia you know so far." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### For more details\n", "- https://docs.julialang.org/en/v1/manual/control-flow/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Julia packages\n", "\n", "The Julia standard library is already surprisingly rich in functionality. Features are grouped into smaller packages according to topics (e.g. `LinearAlgebra`, `SparseArrays`, `Test`, ...). The most basic part of the standard library resides in the special package `Base` and is always automatically to the programmer. If anything beyond `Base` is needed, that is both packages of the standard library or any other third-party package, this needs to be explicitly **installed** and **imported** before use." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example. The `randn` function produces a list or array of random numbers. It is already available in `Base` and we can thus directly use it to create 4 random numbers:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "d = randn(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The returned object in `d` is an `Array`, a type from `Base`, which we will discuss later. We wish to create a diagonal Matrix with these four vaules on the diagonal. For this we need the `LinearAlgebra.Diagonal` datastructure. We make `LinearAlgebra` available to our scope with a `using` statement:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This (might) cause an error, because `LinearAlgebra` is not yet installed. We resolve this as recommended:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import Pkg; Pkg.add(\"LinearAlgebra\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, that `import` is roughly the same as `using` except the package is not brought into scope. We will neglect this detail for this course and just use `using` for all packages we use." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Having installed the package, we are able to use LinearAlgebra and make the diagonal matrix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra\n", "Diagonal(d)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Julia REPL\n", "\n", "Apart from interacting with Julia via a webbrowser and Jupyter (as we will do it in this course). There is also the alternative option to use the Julia REPL. You can get to the REPL by starting `julia` from a terminal. The result is a prompt similar to\n", "```\n", " _\n", " _ _ _(_)_ | Documentation: https://docs.julialang.org\n", " (_) | (_) (_) |\n", " _ _ _| |_ __ _ | Type \"?\" for help, \"]?\" for Pkg help.\n", " | | | | | | |/ _` | |\n", " | | |_| | | | (_| | | Version 1.3.0 (2019-11-26)\n", " _/ |\\__'_|_|_|\\__'_| | Official https://julialang.org/ release\n", "|__/ |\n", "\n", "julia> \n", "\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this prompt you can directly start typing julia expressions, which will be executed upon `[Enter]`. The REPL is very nice to prototype things and with some optional customisations becomes a very powerful tool. We will not use the REPL much in this course, but still I want to mention some basic aspects to get you started. Mostly this is for people who prefer the commandline over graphics (like me):\n", "\n", "- Exiting the shell can be achieved using `exit()` or Ctrl + D.\n", "- Inside the shell tab completion is available.\n", "- The REPL comes in multiple modes. The most useful ones are the (default) Julian mode, Pkg mode (for installing packages), shell mode (for running one-shot shell commands) and help mode. You can get from Julian mode to another by typing a magic key, see the list below. You get back to Julian mode by `[Backspace]` on an empty prompt.\n", "\n", "| Magic key | Prompt | Mode |\n", "|---------------|-------------------------|------------------------------|\n", "| `[Backspace]` | `julia>` | Julian mode (Command mode) |\n", "| `]` | `(v1.3) pkg>` | Pkg mode |\n", "| `?` | `help>` | Help mode |\n", "| `;` | `shell>` | Shell command mode |\n", "\n", "\n", "- To understand Pkg mode better, type `help` once the `(v1.3) pkg>` prompt shows.\n", "- In each mode Ctrl + R allows to search backwards in history for a previously entered command." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise\n", "External packages are installed exactly the same as standard library packages. Their data is automatically fetched from the [General](https://github.com/JuliaRegistries/General) as needed.\n", "\n", "Make sure you have an internet connection. From the REPL or from the notebook, install the following packages as we will need them later:\n", "- `Plots`\n", "- `Zygote`\n", "- `BenchmarkTools`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### For more details\n", "- https://jupyter-notebook.readthedocs.io/en/stable/\n", "- https://docs.julialang.org/en/v1/stdlib/Pkg/\n", "- https://docs.julialang.org/en/v1/stdlib/REPL/" ] } ], "metadata": { "@webio": { "lastCommId": null, "lastKernelId": null }, "kernelspec": { "display_name": "Julia 1.3.0", "language": "julia", "name": "julia-1.3" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.3.0" } }, "nbformat": 4, "nbformat_minor": 2 }