From 2cada13a170d832797d66616f95a62c47a0cea68 Mon Sep 17 00:00:00 2001 From: mma Date: Mon, 11 Mar 2024 14:36:04 +0100 Subject: [PATCH 1/2] I have made the notebooks more beginner-friendly --- .gitignore | 26 - .../01. Getting started-checkpoint.ipynb | 423 ------- ...ted.ipynb => 0 - Getting started_mod.ipynb | 79 +- 1 - Strings.ipynb => 1 - Strings_mod.ipynb | 64 +- 10 - Basic linear algebra.ipynb | 538 --------- 11 - Factorizations and other fun.ipynb | 1017 ----------------- ...res.ipynb => 2 - Data structures_mod.ipynb | 749 +++--------- 3 - Loops.ipynb => 3 - Loops_mod.ipynb | 29 +- ...ionals.ipynb => 4 - Conditionals_mod.ipynb | 43 +- ...Functions.ipynb => 5 - Functions_mod.ipynb | 60 +- 6 - Packages.ipynb => 6 - Packages_mod.ipynb | 20 +- 7 - Plotting.ipynb => 7 - Plotting_mod.ipynb | 25 +- ...h.ipynb => 8 - Multiple dispatch_mod.ipynb | 30 +- ... fast.ipynb => 9 - Julia is fast_mod.ipynb | 0 LICENSE.md | 20 - Project.toml | 8 - README.md | 5 +- 17 files changed, 407 insertions(+), 2729 deletions(-) delete mode 100644 .gitignore delete mode 100644 .ipynb_checkpoints/01. Getting started-checkpoint.ipynb rename 0 - Getting started.ipynb => 0 - Getting started_mod.ipynb (79%) rename 1 - Strings.ipynb => 1 - Strings_mod.ipynb (88%) delete mode 100644 10 - Basic linear algebra.ipynb delete mode 100644 11 - Factorizations and other fun.ipynb rename 2 - Data structures.ipynb => 2 - Data structures_mod.ipynb (55%) rename 3 - Loops.ipynb => 3 - Loops_mod.ipynb (86%) rename 4 - Conditionals.ipynb => 4 - Conditionals_mod.ipynb (78%) rename 5 - Functions.ipynb => 5 - Functions_mod.ipynb (92%) rename 6 - Packages.ipynb => 6 - Packages_mod.ipynb (97%) rename 7 - Plotting.ipynb => 7 - Plotting_mod.ipynb (99%) rename 8 - Multiple dispatch.ipynb => 8 - Multiple dispatch_mod.ipynb (99%) rename 9 - Julia is fast.ipynb => 9 - Julia is fast_mod.ipynb (100%) delete mode 100644 LICENSE.md delete mode 100644 Project.toml diff --git a/.gitignore b/.gitignore deleted file mode 100644 index af55afd..0000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# Files generated by invoking Julia with --code-coverage -*.jl.cov -*.jl.*.cov - -# Files generated by invoking Julia with --track-allocation -*.jl.mem - -# System-specific files and directories generated by the BinaryProvider and BinDeps packages -# They contain absolute paths specific to the host computer, and so should not be committed -deps/deps.jl -deps/build.log -deps/downloads/ -deps/usr/ -deps/src/ - -# Build artifacts for creating documentation generated by the Documenter package -docs/build/ -docs/site/ - -# File generated by Pkg, the package manager, based on a corresponding Project.toml -# It records a fixed state of all packages used by the project. As such, it should not be -# committed for packages, but should be committed for applications that require a static -# environment. -Manifest.toml - -.ipynb_checkpoints/ \ No newline at end of file diff --git a/.ipynb_checkpoints/01. Getting started-checkpoint.ipynb b/.ipynb_checkpoints/01. Getting started-checkpoint.ipynb deleted file mode 100644 index f3f43f6..0000000 --- a/.ipynb_checkpoints/01. Getting started-checkpoint.ipynb +++ /dev/null @@ -1,423 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Getting started\n", - "\n", - "Topics:\n", - "1. How to print\n", - "2. How to assign variables\n", - "3. How to comment\n", - "4. Syntax for basic math" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## How to print\n", - "\n", - "In Julia we usually use `println()` to print" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "I'm excited to learn Julia!\n" - ] - } - ], - "source": [ - "println(\"I'm excited to learn Julia!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## How to assign variables\n", - "\n", - "All we need is a variable name, value, and an equal's sign!
\n", - "Julia will figure out types for us." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Int64" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "my_answer = 42\n", - "typeof(my_answer)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Float64" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "my_pi = 3.14159\n", - "typeof(my_pi)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "String" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "😺 = \"smiley cat!\"\n", - "typeof(😺)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To type a smiley cat, use tab completion to select the emoji name and then tab again" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# \\:smi + --> select with down arrow + ---> + to complete" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After assigning a value to a variable, we can reassign a value of a different type to that variable without any issue." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "😺 = 1" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Int64" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "typeof(😺)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note: Julia allows us to write super generic code, and 😺 is an example of this. \n", - "\n", - "This allows us to write code like" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "😀 = 0\n", - "😞 = -1" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "true" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "😺 + 😞 == 😀" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## How to comment" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# You can leave comments on a single line using the pound/hash key" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#=\n", - "\n", - "For multi-line comments, \n", - "use the '#= =#' sequence.\n", - "\n", - "=#" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Syntax for basic math" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sum = 3 + 7" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "difference = 10 - 3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "product = 20 * 5" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "quotient = 100 / 10" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "power = 10 ^ 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "modulus = 101 % 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercises\n", - "\n", - "#### 1.1 \n", - "Look up docs for the `convert` function." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 1.2 \n", - "Assign `365` to a variable named `days`. Convert `days` to a float and assign it to variable `days_float`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "a2dc243275e0310c3b29a745b952f321", - "grade": true, - "grade_id": "cell-715f78016beb0489", - "locked": true, - "points": 1, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert days == 365\n", - "@assert days_float == 365.0\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 1.3 \n", - "See what happens when you execute\n", - "\n", - "```julia\n", - "convert(Int64, \"1\")\n", - "```\n", - "and\n", - "\n", - "```julia\n", - "parse(Int64, \"1\")\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "Please click on `Validate` on the top, once you are done with the exercises." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.6.0", - "language": "julia", - "name": "julia-1.6" - }, - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.6.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/0 - Getting started.ipynb b/0 - Getting started_mod.ipynb similarity index 79% rename from 0 - Getting started.ipynb rename to 0 - Getting started_mod.ipynb index 9ccba1e..fcdc0a5 100644 --- a/0 - Getting started.ipynb +++ b/0 - Getting started_mod.ipynb @@ -14,8 +14,10 @@ ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, + "outputs": [], "source": [ "## How to print\n", "\n", @@ -46,12 +48,17 @@ "## How to assign variables\n", "\n", "All we need is a variable name, value, and an equal's sign!
\n", - "Julia will figure out types for us." + "Julia will figure out types for us.\n", + "There are three important types:\n", + "\n", + "1. `Int` for integer (whole number), \n", + "2. `Float` for a floating point number (e.g. 0.5, 1/3) and a \n", + "3. `String` (character string that can consist of letters, digits and/or special characters)" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -60,7 +67,7 @@ "Int64" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -91,6 +98,14 @@ "typeof(my_pi)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "64 stands for 64 bits and is the memory unit in which information is stored. In addition to Int64 and Float64, 32-bit is also common.\n" + ] + }, { "cell_type": "code", "execution_count": 4, @@ -125,7 +140,7 @@ "metadata": {}, "outputs": [], "source": [ - "# \\:smi + --> select with down arrow + ---> + to complete" + "# \\:smi + --> complete command by writing ---> to generate Emoji" ] }, { @@ -180,6 +195,7 @@ "metadata": {}, "source": [ "Note: Julia allows us to write super generic code, and 😺 is an example of this. \n", + "Super generic codes are general and therefore reusable codes that can be applied to different data types.\n", "\n", "This allows us to write code like" ] @@ -225,6 +241,15 @@ "😺 + 😞 == 😀" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With one equals sign = a thing is assigned to a variable.\n", + "\n", + "With two equal signs == you can check whether two things are equal. The output is either true or false. " + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -389,7 +414,7 @@ "### Exercises\n", "\n", "#### 1.1 \n", - "Look up docs for the `convert` function." + "Look up documentations for the `convert` function with `help?>`" ] }, { @@ -416,7 +441,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "deletable": false, "editable": false, @@ -431,7 +456,20 @@ "solution": false } }, - "outputs": [], + "outputs": [ + { + "ename": "LoadError", + "evalue": "UndefVarError: `days` not defined", + "output_type": "error", + "traceback": [ + "UndefVarError: `days` not defined", + "", + "Stacktrace:", + " [1] top-level scope", + " @ In[4]:1" + ] + } + ], "source": [ "@assert days == 365\n", "@assert days_float == 365.0\n" @@ -446,12 +484,29 @@ "\n", "```julia\n", "convert(Int64, \"1\")\n", + "\n", "```\n", + "\n", "and\n", "\n", "```julia\n", "parse(Int64, \"1\")\n", - "```" + "\n", + "```\n", + "\n", + "
\n", + " unfold result\n", + "The convert function can be used, for example, to convert a float into an integer, or vice versa.\n", + " \n", + " \n", + " \n", + "-> convert(type, number)\n", + " \n", + "The parse function splits a string into an integer or a float\n", + "\n", + "-> parse(type, \"string\")\n", + "\n", + "
\n" ] }, { @@ -464,15 +519,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.3" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/1 - Strings.ipynb b/1 - Strings_mod.ipynb similarity index 88% rename from 1 - Strings.ipynb rename to 1 - Strings_mod.ipynb index 3675629..b669348 100644 --- a/1 - Strings.ipynb +++ b/1 - Strings_mod.ipynb @@ -18,7 +18,7 @@ "source": [ "## How to get a string\n", "\n", - "Enclose your characters in \" \" or \"\"\" \"\"\"!" + "Enclose your strings in \" \" or \"\"\" \"\"\"!" ] }, { @@ -119,7 +119,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that ' ' define a character, but NOT a string!" + "Note that ' ' define a character, but NOT a string!\n", + "\n", + "A character is a single character and can be converted into a numerical value.\n", + "Char = character and the char() function converts an integer back into a character" ] }, { @@ -173,6 +176,7 @@ "metadata": {}, "source": [ "## String interpolation\n", + "An interpolation is a later insertion or change in a text that is not marked as one.\n", "\n", "We can use the $ sign to insert existing variables into a string and to evaluate expressions within a string.
\n", "Below is an example that contains some highly sensitive personal information." @@ -242,31 +246,20 @@ "source": [ "## String concatenation\n", "\n", - "Below are three ways we can concatenate strings!

\n", + "Below are two ways we can concatenate strings!

\n", "The first way is to use the `string()` function.
\n", "`string()` converts non-string inputs to strings." ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "10" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "s3 = \"How many cats \";\n", - "s4 = \"is too many cats?\";\n", - "😺 = 10" + "s3 =\"How many cats\"\n", + "s4 = \"is too many cats?\"\n", + "😸 = 10" ] }, { @@ -289,6 +282,15 @@ "string(s3, s4)" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Or:" + ] + }, { "cell_type": "code", "execution_count": 12, @@ -306,14 +308,15 @@ } ], "source": [ - "string(\"I don't know, but \", 😺, \" is too few.\")" + "string(\"I don't know, but \", 😸, \" is too few.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can also use `*` for concatenation!" + "\n", + "And secondly we can also use `*` for concatenation!" ] }, { @@ -343,7 +346,18 @@ "### Exercises\n", "\n", "#### 2.1 \n", - "Create a string that says \"hi\" 1000 times, first with `repeat` and then with the exponentiation operator, which can call `*` under the hood. Assign it the variable `hi` below." + "Create a string that says \"hi\" 1000 times, first with `repeat` and then with the exponentiation operator `^`. \n", + "\n", + "Assign it the variable `hi` below.\n", + "\n", + "
\n", + " Tip\n", + "\n", + "for example 2^4 can also be written as 2 * 2 * 2 * 2, and therefore strings can be concatenated with the exponential operator. \n", + " \n", + "repeat(\"string\" or 'character', number of repetitions)\n", + "\n", + "\n" ] }, { @@ -447,15 +461,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.3" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/10 - Basic linear algebra.ipynb b/10 - Basic linear algebra.ipynb deleted file mode 100644 index f3e0517..0000000 --- a/10 - Basic linear algebra.ipynb +++ /dev/null @@ -1,538 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Basic linear algebra in Julia\n", - "Author: Andreas Noack Jensen (MIT & JuliaComputing) (https://twitter.com/anoackjensen?lang=en)\n", - "(with edits from Jane Herriman)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First let's define a random matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Int64}:\n", - " 3 1 3\n", - " 1 1 2\n", - " 3 2 2" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "A = rand(1:4,3,3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Define a vector of ones" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 1.0\n", - " 1.0\n", - " 1.0" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = fill(1.0, (3,)) # = fill(1.0, 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that $A$ has type Array{Int64,2} but $x$ has type Array{Float64,1}. Julia defines the aliases Vector{Type}=Array{Type,1} and Matrix{Type}=Array{Type,2}. \n", - "\n", - "Many of the basic operations are the same as in other languages\n", - "#### Multiplication" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 7.0\n", - " 4.0\n", - " 7.0" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "b = A*x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Transposition\n", - "As in other languages `A'` is the conjugate transpose, or adjoint" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 adjoint(::Matrix{Int64}) with eltype Int64:\n", - " 3 1 3\n", - " 1 1 2\n", - " 3 2 2" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "A'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and we can get the transpose with" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 transpose(::Matrix{Int64}) with eltype Int64:\n", - " 3 1 3\n", - " 1 1 2\n", - " 3 2 2" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transpose(A)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Transposed multiplication\n", - "Julia allows us to write this without *" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Int64}:\n", - " 19 10 17\n", - " 10 6 9\n", - " 17 9 17" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "A'A" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Solving linear systems \n", - "The problem $Ax=b$ for ***square*** $A$ is solved by the \\ function." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 1.0\n", - " 1.0\n", - " 1.0" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "A\\b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`A\\b` gives us the *least squares solution* if we have an overdetermined linear system (a \"tall\" matrix)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×2 Matrix{Float64}:\n", - " 0.01259 0.562346\n", - " 0.571931 0.208287\n", - " 0.0761351 0.507003" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Atall = rand(3, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Float64}:\n", - " 2.3722998636787898\n", - " 12.85556853172185" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Atall\\b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and the *minimum norm least squares solution* if we have a rank-deficient least squares problem" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×2 Matrix{Float64}:\n", - " 0.682093 0.682093\n", - " 0.745287 0.745287\n", - " 0.698837 0.698837" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v = rand(3)\n", - "rankdef = hcat(v, v)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Float64}:\n", - " 4.190527048390038\n", - " 4.190527048390039" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rankdef\\b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Julia also gives us the minimum norm solution when we have an underdetermined solution (a \"short\" matrix)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2×3 Matrix{Float64}:\n", - " 0.692218 0.193236 0.153774\n", - " 0.127852 0.0359394 0.063034" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bshort = rand(2)\n", - "Ashort = rand(2, 3)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " -4.139674407706176\n", - " -0.9797338415813472\n", - " 23.563074056363842" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Ashort\\bshort" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# The LinearAlgebra library\n", - "\n", - "While much of linear algebra is available in Julia by default (as shown above), there's a standard library named `LinearAlgebra` that brings in many more relevant names and functions. In particular, it provides factorizations and some structured matrix types. As with all packages, you can bring these additional features into your session with a `using LinearAlgebra`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercises\n", - "\n", - "#### 10.1 \n", - "Take the inner product (or \"dot\" product) of a vector `v` with itself and assign it to variable `dot_v`.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Int64}:\n", - " 1\n", - " 2\n", - " 3" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "v = [1,2,3]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "b93dad361f66498eb2460d708f674220", - "grade": true, - "grade_id": "cell-913fef9b0d19cd52", - "locked": true, - "points": 1, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert dot_v == 14" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 10.2 \n", - "Take the outer product of a vector v with itself and assign it to variable `outer_v`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "@assert outer_v == [1 2 3\n", - " 2 4 6\n", - " 3 6 9]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 10.3 \n", - "Use [LinearAlgebra.cross](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.cross) to compute the cross product of a vector v with itself and assign it to variable `cross_v`" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "01642581e27c0ac19752cd90d11ac2ae", - "grade": true, - "grade_id": "cell-e6b6970ffe104df5", - "locked": true, - "points": 1, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert cross_v == [0, 0, 0]" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.7.1", - "language": "julia", - "name": "julia-1.7" - }, - "language": "Julia", - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.7.1" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/11 - Factorizations and other fun.ipynb b/11 - Factorizations and other fun.ipynb deleted file mode 100644 index ce9be46..0000000 --- a/11 - Factorizations and other fun.ipynb +++ /dev/null @@ -1,1017 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Factorizations and other fun\n", - "Based on work by Andreas Noack\n", - "\n", - "## Outline\n", - " - Factorizations\n", - " - Special matrix structures\n", - " - Generic linear algebra" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we get started, let's set up a linear system and use `LinearAlgebra` to bring in the factorizations and special matrix structures." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 2.205296596065241\n", - " 1.8551229792583508\n", - " 0.8533886927959882" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "using LinearAlgebra\n", - "A = rand(3, 3)\n", - "x = fill(1, (3,))\n", - "b = A * x" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Factorizations\n", - "\n", - "#### LU factorizations\n", - "In Julia we can perform an LU factorization\n", - "```julia\n", - "PA = LU\n", - "``` \n", - "where `P` is a permutation matrix, `L` is lower triangular unit diagonal and `U` is upper triangular, using `lufact`.\n", - "\n", - "Julia allows computing the LU factorization and defines a composite factorization type for storing it." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "LU{Float64, Matrix{Float64}}\n", - "L factor:\n", - "3×3 Matrix{Float64}:\n", - " 1.0 0.0 0.0\n", - " 0.513615 1.0 0.0\n", - " 0.295738 0.271404 1.0\n", - "U factor:\n", - "3×3 Matrix{Float64}:\n", - " 0.83195 0.576718 0.446455\n", - " 0.0 0.687695 0.564783\n", - " 0.0 0.0 -0.0351695" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Alu = lu(A)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "LU{Float64, Matrix{Float64}}" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "typeof(Alu)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The different parts of the factorization can be extracted by accessing their special properties" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " 0.0 1.0 0.0\n", - " 1.0 0.0 0.0\n", - " 0.0 0.0 1.0" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Alu.P" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " 1.0 0.0 0.0\n", - " 0.513615 1.0 0.0\n", - " 0.295738 0.271404 1.0" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Alu.L" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " 0.83195 0.576718 0.446455\n", - " 0.0 0.687695 0.564783\n", - " 0.0 0.0 -0.0351695" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Alu.U" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Julia can dispatch methods on factorization objects.\n", - "\n", - "For example, we can solve the linear system using either the original matrix or the factorization object." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 0.9999999999999999\n", - " 1.0000000000000002\n", - " 1.0" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "A\\b" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " 0.9999999999999999\n", - " 1.0000000000000002\n", - " 1.0" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Alu\\b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarly, we can calculate the determinant of `A` using either `A` or the factorization object" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "true" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "det(A) ≈ det(Alu)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### QR factorizations\n", - "\n", - "In Julia we can perform a QR factorization\n", - "```\n", - "A=QR\n", - "``` \n", - "\n", - "where `Q` is unitary/orthogonal and `R` is upper triangular, using `qrfact`. " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}}\n", - "Q factor:\n", - "3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}:\n", - " -0.441843 0.858892 -0.258997\n", - " -0.860261 -0.487536 -0.149194\n", - " -0.254412 0.156884 0.954286\n", - "R factor:\n", - "3×3 Matrix{Float64}:\n", - " -0.96709 -1.02174 -0.798571\n", - " 0.0 0.619937 0.503618\n", - " 0.0 0.0 -0.0335617" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Aqr = qr(A)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarly to the LU factorization, the matrices `Q` and `R` can be extracted from the QR factorization object via" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}:\n", - " -0.441843 0.858892 -0.258997\n", - " -0.860261 -0.487536 -0.149194\n", - " -0.254412 0.156884 0.954286" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Aqr.Q" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " -0.96709 -1.02174 -0.798571\n", - " 0.0 0.619937 0.503618\n", - " 0.0 0.0 -0.0335617" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Aqr.R" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Eigendecompositions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The results from eigendecompositions, singular value decompositions, Hessenberg factorizations, and Schur decompositions are all stored in `Factorization` types.\n", - "\n", - "The eigendecomposition can be computed" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}}\n", - "values:\n", - "3-element Vector{Float64}:\n", - " -0.871021215213241\n", - " -0.02678184303514708\n", - " 3.406139917482376\n", - "vectors:\n", - "3×3 Matrix{Float64}:\n", - " 0.768088 -0.0906084 -0.633901\n", - " -0.596429 -0.461515 -0.656716\n", - " -0.233051 0.882493 -0.408526" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Asym = A + A'\n", - "AsymEig = eigen(Asym)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The values and the vectors can be extracted from the Eigen type by special indexing" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Float64}:\n", - " -0.871021215213241\n", - " -0.02678184303514708\n", - " 3.406139917482376" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "AsymEig.values" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " 0.768088 -0.0906084 -0.633901\n", - " -0.596429 -0.461515 -0.656716\n", - " -0.233051 0.882493 -0.408526" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "AsymEig.vectors" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once again, when the factorization is stored in a type, we can dispatch on it and write specialized methods that exploit the properties of the factorization, e.g. that $A^{-1}=(V\\Lambda V^{-1})^{-1}=V\\Lambda^{-1}V^{-1}$." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Float64}:\n", - " 1.0 5.32907e-15 4.88498e-15\n", - " 2.84217e-14 1.0 2.22045e-14\n", - " -5.68434e-14 -6.03961e-14 1.0" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "inv(AsymEig)*Asym" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Special matrix structures\n", - "Matrix structure is very important in linear algebra. To see *how* important it is, let's work with a larger linear system" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "n = 1000\n", - "A = randn(n,n);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Julia can often infer special matrix structure" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "true" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Asym = A + A'\n", - "issymmetric(Asym)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "but sometimes floating point error might get in the way." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2.9631367153816814" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Asym_noisy = copy(Asym)\n", - "Asym_noisy[1,2] += 5eps()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "false" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "issymmetric(Asym_noisy)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Luckily we can declare structure explicitly with, for example, `Diagonal`, `Triangular`, `Symmetric`, `Hermitian`, `Tridiagonal` and `SymTridiagonal`." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "Asym_explicit = Symmetric(Asym_noisy);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's compare how long it takes Julia to compute the eigenvalues of `Asym`, `Asym_noisy`, and `Asym_explicit`" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0.258496 seconds (134.03 k allocations: 15.456 MiB, 6.10% gc time, 38.03% compilation time)\n" - ] - } - ], - "source": [ - "@time eigvals(Asym);" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 1.050047 seconds (13 allocations: 7.920 MiB)\n" - ] - } - ], - "source": [ - "@time eigvals(Asym_noisy);" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0.149938 seconds (5.88 k allocations: 8.358 MiB, 2.11% compilation time)\n" - ] - } - ], - "source": [ - "@time eigvals(Asym_explicit);" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In this example, using `Symmetric()` on `Asym_noisy` made our calculations about `5x` more efficient :)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### A big problem\n", - "Using the `Tridiagonal` and `SymTridiagonal` types to store tridiagonal matrices makes it possible to work with potentially very large tridiagonal problems. The following problem would not be possible to solve on a laptop if the matrix had to be stored as a (dense) `Matrix` type." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0.669902 seconds (823.18 k allocations: 229.291 MiB, 12.15% gc time, 26.00% compilation time)\n" - ] - }, - { - "data": { - "text/plain": [ - "6.7249639294089665" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n = 1_000_000;\n", - "A = SymTridiagonal(randn(n), randn(n-1));\n", - "@time eigmax(A)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generic linear algebra\n", - "The usual way of adding support for numerical linear algebra is by wrapping BLAS and LAPACK subroutines. For matrices with elements of `Float32`, `Float64`, `Complex{Float32}` or `Complex{Float64}` this is also what Julia does.\n", - "\n", - "However, Julia also supports generic linear algebra, allowing you to, for example, work with matrices and vectors of rational numbers." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Rational numbers\n", - "Julia has rational numbers built in. To construct a rational number, use double forward slashes:" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1//2" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "1//2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Example: Rational linear system of equations\n", - "The following example shows how linear system of equations with rational elements can be solved without promoting to floating point element types. Overflow can easily become a problem when working with rational numbers so we use `BigInt`s." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3×3 Matrix{Rational{BigInt}}:\n", - " 1//10 3//5 2//5\n", - " 1//5 1//10 1//5\n", - " 1//5 1//5 3//10" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Arational = Matrix{Rational{BigInt}}(rand(1:10, 3, 3))/10" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Rational{BigInt}}:\n", - " 11//10\n", - " 1//2\n", - " 7//10" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "x = fill(1, 3)\n", - "b = Arational*x" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Rational{BigInt}}:\n", - " 1//1\n", - " 1//1\n", - " 1//1" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "Arational\\b" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "LU{Rational{BigInt}, Matrix{Rational{BigInt}}}\n", - "L factor:\n", - "3×3 Matrix{Rational{BigInt}}:\n", - " 1//1 0//1 0//1\n", - " 1//2 1//1 0//1\n", - " 1//1 2//11 1//1\n", - "U factor:\n", - "3×3 Matrix{Rational{BigInt}}:\n", - " 1//5 1//10 1//5\n", - " 0//1 11//20 3//10\n", - " 0//1 0//1 1//22" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lu(Arational)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercises\n", - "\n", - "#### 11.1\n", - "What are the eigenvalues of matrix A?\n", - "\n", - "```\n", - "A =\n", - "[\n", - " 140 97 74 168 131\n", - " 97 106 89 131 36\n", - " 74 89 152 144 71\n", - " 168 131 144 54 142\n", - " 131 36 71 142 36\n", - "]\n", - "```\n", - "and assign it a variable `A_eigv`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "using LinearAlgebra" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "f9f16fdef201ed372323a291f1dd1346", - "grade": true, - "grade_id": "cell-4d5f60c8a814c789", - "locked": true, - "points": 0, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert A_eigv == [-128.49322764802145, -55.887784553056875, 42.7521672793189, 87.16111477514521, 542.4677301466143]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 11.2 \n", - "Create a `Diagonal` matrix from the eigenvalues of `A`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "3ca676f6282c1a7c214ab2cb9f9b322d", - "grade": true, - "grade_id": "cell-3b000a3710c9c263", - "locked": true, - "points": 1, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert A_diag == [-128.493 0.0 0.0 0.0 0.0;\n", - " 0.0 -55.8878 0.0 0.0 0.0;\n", - " 0.0 0.0 42.7522 0.0 0.0;\n", - " 0.0 0.0 0.0 87.1611 0.0;\n", - " 0.0 0.0 0.0 0.0 542.468]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 11.3 \n", - "Create a `LowerTriangular` matrix from `A` and store it in `A_lowertri`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "deletable": false, - "editable": false, - "hide_input": true, - "nbgrader": { - "checksum": "b3b1a272343a05082f378a5e1aa3426d", - "grade": true, - "grade_id": "cell-b76cee2b4a8777da", - "locked": true, - "points": 0, - "schema_version": 1, - "solution": false - } - }, - "outputs": [], - "source": [ - "@assert A_lowertri == [140 0 0 0 0;\n", - " 97 106 0 0 0;\n", - " 74 89 152 0 0;\n", - " 168 131 144 54 0;\n", - " 131 36 71 142 36]" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Julia 1.6.0", - "language": "julia", - "name": "julia-1.6" - }, - "language": "Julia", - "language_info": { - "file_extension": ".jl", - "mimetype": "application/julia", - "name": "julia", - "version": "1.6.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/2 - Data structures.ipynb b/2 - Data structures_mod.ipynb similarity index 55% rename from 2 - Data structures.ipynb rename to 2 - Data structures_mod.ipynb index ba9b34b..679862d 100644 --- a/2 - Data structures.ipynb +++ b/2 - Data structures_mod.ipynb @@ -29,25 +29,15 @@ "Syntax:
\n", "```julia\n", "(item1, item2, ...)\n", + "\n", "```\n" ] }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(\"penguins\", \"cats\", \"sugargliders\")" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals = (\"penguins\", \"cats\", \"sugargliders\")" ] @@ -61,20 +51,9 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"penguins\"" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals[1]" ] @@ -88,26 +67,9 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "MethodError: no method matching setindex!(::Tuple{String, String, String}, ::String, ::Int64)", - "output_type": "error", - "traceback": [ - "MethodError: no method matching setindex!(::Tuple{String, String, String}, ::String, ::Int64)", - "", - "Stacktrace:", - " [1] top-level scope", - " @ In[3]:1", - " [2] eval", - " @ ./boot.jl:360 [inlined]", - " [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", - " @ Base ./loading.jl:1094" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals[1] = \"otters\"" ] @@ -116,31 +78,22 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "## Now in 1.6: NamedTuples\n", "\n", - "As you might guess, `NamedTuple`s are just like `Tuple`s except that each element additionally has a name! They have a special syntax using `=` inside a tuple:\n", + "As you might guess, `NamedTuple`s are just like `Tuple`s except that each element additionally has a name! They have a special syntax using `'='` inside a tuple:\n", "\n", "```julia\n", "(name1 = item1, name2 = item2, ...)\n", + "\n", "```" ] }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(bird = \"penguins\", mammal = \"cats\", marsupial = \"sugargliders\")" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals = (bird = \"penguins\", mammal = \"cats\", marsupial = \"sugargliders\")" ] @@ -154,20 +107,9 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"penguins\"" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals[1]" ] @@ -181,20 +123,9 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"penguins\"" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfavoriteanimals.bird" ] @@ -205,11 +136,13 @@ "source": [ "## Dictionaries\n", "\n", - "If we have sets of data related to one another, we may choose to store that data in a dictionary. We can create a dictionary using the `Dict()` function, which we can initialize as an empty dictionary or one storing key, value pairs.\n", + "If we have sets of data related to one another, we may choose to store that data in a dictionary. We can create a dictionary using the `Dict()` function, which we can initialize as an empty dictionary or one storing key-value pairs.\n", + "A key-value pair contains two linked data elements: a key (e.g. a name), which is a unique identifier for a data element, and the value behind the key, e.g. a phone number\n", "\n", "Syntax:\n", "```julia\n", "Dict(key1 => value1, key2 => value2, ...)\n", + "\n", "```\n", "\n", "A good example is a contacts list, where we associate names with phone numbers." @@ -217,22 +150,9 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Dict{String, String} with 2 entries:\n", - " \"Jenny\" => \"867-5309\"\n", - " \"Ghostbusters\" => \"555-2368\"" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook = Dict(\"Jenny\" => \"867-5309\", \"Ghostbusters\" => \"555-2368\")" ] @@ -246,20 +166,9 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"867-5309\"" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook[\"Jenny\"]" ] @@ -273,20 +182,9 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"555-FILK\"" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook[\"Kramer\"] = \"555-FILK\"" ] @@ -300,23 +198,9 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Dict{String, String} with 3 entries:\n", - " \"Jenny\" => \"867-5309\"\n", - " \"Kramer\" => \"555-FILK\"\n", - " \"Ghostbusters\" => \"555-2368\"" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook" ] @@ -330,42 +214,27 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"555-FILK\"" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "pop!(myphonebook, \"Kramer\")" ] }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Dict{String, String} with 2 entries:\n", - " \"Jenny\" => \"867-5309\"\n", - " \"Ghostbusters\" => \"555-2368\"" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#pop!() deletes the last entry and is output at the same time" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook" ] @@ -379,28 +248,9 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "ename": "LoadError", - "evalue": "KeyError: key 1 not found", - "output_type": "error", - "traceback": [ - "KeyError: key 1 not found", - "", - "Stacktrace:", - " [1] getindex(h::Dict{String, String}, key::Int64)", - " @ Base ./dict.jl:482", - " [2] top-level scope", - " @ In[13]:1", - " [3] eval", - " @ ./boot.jl:360 [inlined]", - " [4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)", - " @ Base ./loading.jl:1094" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myphonebook[1]" ] @@ -424,33 +274,18 @@ "Syntax:
\n", "```julia\n", "[item1, item2, ...]\n", + "\n", "```\n", "\n", "\n", - "For example, we might create an array to keep track of my friends" + "For example, we might create an array to keep track of my friends..." ] }, { "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5-element Vector{String}:\n", - " \"Ted\"\n", - " \"Robyn\"\n", - " \"Barney\"\n", - " \"Lily\"\n", - " \"Marshall\"" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfriends = [\"Ted\", \"Robyn\", \"Barney\", \"Lily\", \"Marshall\"]" ] @@ -459,65 +294,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `1` in `Array{String,1}` means this is a one dimensional vector. An `Array{String,2}` would be a 2d matrix, etc. The `String` is the type of each element." + "The `1` in `Array{String,1}` means this is a one dimensional vector. An `Array{String,2}` would be a 2d matrix, etc. The `String` is the type of each element." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "or to store a sequence of numbers" + "...or to store a sequence of numbers" ] }, { "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fibonacci = [1, 1, 2, 3, 5, 8, 13]" ] }, { "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "6-element Vector{Any}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " \"Ted\"\n", - " \"Robyn\"" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "mixture = [1, 1, 2, 3, \"Ted\", \"Robyn\"]" ] @@ -531,20 +331,9 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Barney\"" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfriends[3]" ] @@ -558,20 +347,9 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\"Baby Bop\"" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "myfriends[3] = \"Baby Bop\"" ] @@ -580,7 +358,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Yes, Julia is 1-based indexing, not 0-based like Python. Wars are fought over lesser issues. I have a friend with the wisdom of Solomon who proposes settling this once and for all with ½ 😃" + "Yes, Julia is 1-based indexing, not 0-based like Python, which means that the first element in arrays, tuples, etc. can be called with the number 1 and not with number 0 as in Python." ] }, { @@ -594,28 +372,9 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "8-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13\n", - " 21" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "push!(fibonacci, 21)" ] @@ -629,47 +388,18 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "21" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "pop!(fibonacci)" ] }, { "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fibonacci" ] @@ -685,45 +415,18 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Vector{String}}:\n", - " [\"koobideh\", \"chocolate\", \"eggs\"]\n", - " [\"penguins\", \"cats\", \"sugargliders\"]" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "favorites = [[\"koobideh\", \"chocolate\", \"eggs\"],[\"penguins\", \"cats\", \"sugargliders\"]]" ] }, { "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3-element Vector{Vector{Int64}}:\n", - " [1, 2, 3]\n", - " [4, 5]\n", - " [6, 7, 8, 9]" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "numbers = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]" ] @@ -732,60 +435,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Below are examples of 2D and 3D arrays populated with random values." + "Below are examples of 2D and 3D arrays populated with random values via the random function `rand(x, y, z)`.\n", + "\n", + " x= how many numbers are to be generated\n", + " y= how often x should be repeated\n", + " z= how often x and y should be repeated" ] }, { "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×3 Matrix{Float64}:\n", - " 0.392655 0.340897 0.736004\n", - " 0.887521 0.625563 0.225457\n", - " 0.123646 0.215211 0.435754\n", - " 0.563704 0.564539 0.0301484" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "rand(4, 3)" ] }, { "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4×3×2 Array{Float64, 3}:\n", - "[:, :, 1] =\n", - " 0.855458 0.180741 0.480692\n", - " 0.888806 0.852159 0.62636\n", - " 0.708986 0.0526796 0.779808\n", - " 0.499323 0.18727 0.0843665\n", - "\n", - "[:, :, 2] =\n", - " 0.641847 0.292116 0.0178846\n", - " 0.359826 0.9608 0.245789\n", - " 0.746938 0.389501 0.944762\n", - " 0.386954 0.391897 0.0875665" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], "source": [ "rand(4, 3, 2)" ] @@ -794,106 +466,45 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", + "\n", + "\n", + " \n", "Be careful when you want to copy arrays!" ] }, { "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fibonacci" ] }, { "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "somenumbers = fibonacci" ] }, { "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "404" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "somenumbers[1] = 404" ] }, { "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 404\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fibonacci" ] @@ -906,32 +517,14 @@ "\n", "In the above example, we didn't actually make a copy of `fibonacci`. We just created a new way to access the entries in the array bound to `fibonacci`.\n", "\n", - "If we'd like to make a copy of the array bound to `fibonacci`, we can use the `copy` function." + "If we'd like to make a copy of the array bound to `fibonacci`, we can use the `copy()` function." ] }, { "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "# First, restore fibonacci\n", "fibonacci[1] = 1\n", @@ -940,74 +533,27 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "somemorenumbers = copy(fibonacci)" ] }, { "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "404" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "somemorenumbers[1] = 404" ] }, { "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7-element Vector{Int64}:\n", - " 1\n", - " 1\n", - " 2\n", - " 3\n", - " 5\n", - " 8\n", - " 13" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "fibonacci" ] @@ -1030,6 +576,7 @@ "\n", "```julia\n", "a_ray = [1, 2, 3]\n", + "\n", "```\n", "\n", "Add the number `4` to the end of this array and then remove it." @@ -1162,6 +709,14 @@ "@assert haskey(flexible_phonebook, \"Emergency\")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "the `haskey` function indicates whether a specific key is present in the array (true) or not (false)." + ] + }, { "cell_type": "code", "execution_count": null, @@ -1189,7 +744,21 @@ "metadata": {}, "source": [ "#### 3.5 \n", - "Why can we add an integer as a value to `flexible_phonebook` but not `myphonebook`? How could we have initialized `myphonebook` so that it would accept integers as values? (hint: try using [Julia's documentation for dictionaries](https://docs.julialang.org/en/v1/base/collections/#Dictionaries))" + "Why can we add an integer as a value to `flexible_phonebook` but not `myphonebook`? How could we have initialized `myphonebook` so that it would accept integers as values? (hint: try using [Julia's documentation for dictionaries](https://docs.julialang.org/en/v1/base/collections/#Dictionaries))\n", + "\n", + "\n", + "
\n", + " unfold result\n", + "In myphonebook, only strings as values can be added to a key. If you assign \"911\" as a string to the key \"Emergency\", myphonebook can be extended.\n", + " \n", + "\n", + " \n", + "```julia \n", + "myphonebook = Dict{String, Integer}(\"Jenny\" => \"867-5309\", \"Ghostbusters\" => \"555-2368\")\n", + "``` \n", + "-> myphonebook can now also be extended with integers as values.\n", + "\n", + "
" ] }, { @@ -1202,15 +771,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.3" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/3 - Loops.ipynb b/3 - Loops_mod.ipynb similarity index 86% rename from 3 - Loops.ipynb rename to 3 - Loops_mod.ipynb index af4d019..38ec613 100644 --- a/3 - Loops.ipynb +++ b/3 - Loops_mod.ipynb @@ -13,6 +13,9 @@ "\n", "## while loops\n", "\n", + "With `while` loops, certain codes can be executed repeatedly as long as the previously defined conditions are `true`. If at some point the condition no longer applies, is `false`, the loop is terminated.\n", + "\n", + "\n", "The syntax for a `while` is\n", "\n", "```julia\n", @@ -90,7 +93,11 @@ " friend = myfriends[i]\n", " println(\"Hi $friend, it's great to see you!\")\n", " i += 1\n", - "end" + "end\n", + "\n", + "#'<=' : less than or equal to\n", + "#'+=' : for example i +=1 is equal to i = i + 1 and is used to obtain an updated version of the operand.\n", + "\n" ] }, { @@ -99,10 +106,12 @@ "source": [ "## for loops\n", "\n", + "`For` loops, like `while` loops, are used to repeatedly execute a certain code, but `for` loops are usually used when the scope of elements of a \"collection\" can be determined in advance.\n", + "\n", "The syntax for a `for` loop is\n", "\n", "```julia\n", - "for *var* in *loop iterable*\n", + "for *variable* in *loop iterable*\n", " *loop body*\n", "end\n", "```\n", @@ -167,7 +176,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now let's use `for` loops to create some addition tables, where the value of every entry is the sum of its row and column indices.
\n", + "Now let's use `for` loops to create some addition tables, where the value of every entry is the sum of its row (n) and column (m) indices.
\n", "\n", "Note that we iterate over this array via column-major loops in order to get the best performance. More information about fast indexing of multidimensional arrays inside nested loops can be found at https://docs.julialang.org/en/v1/manual/performance-tips/#Access-arrays-in-memory-order,-along-columns-1\n", "\n", @@ -329,7 +338,7 @@ "### Exercises\n", "\n", "#### 4.1 \n", - "Loop over integers between 1 and 100 and print their squares." + "Write a loop over integers between 1 and 100 and print their square number." ] }, { @@ -344,7 +353,9 @@ "metadata": {}, "source": [ "#### 4.2 \n", - "Add to the code above a bit to create a dictionary, `squares` that holds integers and their squares as key, value pairs such that\n", + "Change the previous code to a dictionary called `squares`, so that the integers are the keys and the corresponding square number is the value pair (key-value pairs)\n", + "\n", + "such that:\n", "\n", "```julia\n", "squares[10] == 100\n", @@ -386,7 +397,7 @@ "metadata": {}, "source": [ "#### 4.3 \n", - "Use an array comprehension to create an an array `squares_arr` that stores the squares for all integers between 1 and 100." + "Use an array comprehension (abbreviation) to create an array `squares_arr` that stores the squares for all integers between 1 and 100." ] }, { @@ -422,15 +433,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.3" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/4 - Conditionals.ipynb b/4 - Conditionals_mod.ipynb similarity index 78% rename from 4 - Conditionals.ipynb rename to 4 - Conditionals_mod.ipynb index 5751c00..6271c83 100644 --- a/4 - Conditionals.ipynb +++ b/4 - Conditionals_mod.ipynb @@ -6,7 +6,14 @@ "source": [ "# Conditionals\n", "\n", - "#### with the `if` keyword\n", + "#### 1. with the `if` keyword\n", + "\n", + "`If` conditions allow a code or a code block to be executed only if a certain condition is fullfild (`True` or `False`). This means that you can use `if` keywords to jump in the code and change the control flow.\n", + "\n", + "With `elseif` a second condition can be added, which is only checked if the first condition in the `if` sentence is `false`.\n", + "\n", + "`If` sentences are ended with `else` and the `else` statement is only executed if one/all of the previous `if` conditions are not fulfilled.\n", + "\n", "In Julia, the syntax\n", "\n", "```julia\n", @@ -21,7 +28,11 @@ "\n", "allows us to conditionally evaluate one of our options.\n", "

\n", - "For example, we might want to implement the FizzBuzz test: given a number, N, print \"Fizz\" if N is divisible by 3, \"Buzz\" if N is divisible by 5, and \"FizzBuzz\" if N is divisible by 3 and 5. Otherwise just print the number itself! Enter your choice for `N` here:" + "For example, we might want to implement the FizzBuzz test:\n", + "\n", + "given a number N: print \"Fizz\" if N is divisible by 3, \"Buzz\" if N is divisible by 5, and \"FizzBuzz\" if N is divisible by 3 and 5. \n", + "Otherwise just print the number itself! \n", + "Enter your choice for `N` here:" ] }, { @@ -73,9 +84,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### with ternary operators\n", + "#### 2. with ternary operators\n", "\n", - "For this last block, we could instead use the ternary operator with the syntax\n", + "For this last block, we could instead use the ternary operator with the syntax:\n", "\n", "```julia\n", "a ? b : c\n", @@ -89,7 +100,11 @@ "else\n", " c\n", "end\n", - "```" + "```\n", + "\n", + "In words: a `ternary operator` needs three arguments a, b and c.\n", + "\n", + "if a is `true`, b is executed and if a is `false`, c is executed." ] }, { @@ -182,13 +197,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "#### with short-circuit evaluation\n", + "#### 3. with short-circuit evaluation\n", "\n", - "We've already seen expressions with the syntax\n", + "There are also expressions with this syntax:\n", "```julia\n", "a && b\n", "```\n", - "to return true if both `a` and `b` are true. Of course, if `a` is false, Julia doesn't even need to know the value of `b` in order to determine that the overall result will be false. So Julia doesn't even need to check what `b` is; it can just \"short-circuit\" and immediately return `false`. The second argument `b` might be a more complicated expression like a function call with a side-effect, in which case it won't even be called:" + "\n", + "`&&` behaves the same as the logical `and` and in the expression a&&b, `b` is only executed if `a` is evaluated as `true`. \n", + "\n", + "If a&&b evaluates as `true`, both `a` and `b` are `true`. However, if `a` is false, the second argument `b` is not even checked and the overall result is returned as `false`." ] }, { @@ -277,7 +295,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Similarly, check out the `||` operator, which also uses short-circuit evaluation to perform the \"or\" operation." + "Similarly, check out the `||` operator, which also uses short-circuit evaluation to perform the logical `or` operation.\n", + "In the expression a||b, the second argument `b` is only evaluated if `a` was evaluated as `false`." ] }, { @@ -359,15 +378,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.0" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/5 - Functions.ipynb b/5 - Functions_mod.ipynb similarity index 92% rename from 5 - Functions.ipynb rename to 5 - Functions_mod.ipynb index 39f1bb9..a6eef2a 100644 --- a/5 - Functions.ipynb +++ b/5 - Functions_mod.ipynb @@ -18,12 +18,16 @@ "metadata": {}, "source": [ "## How to declare a function\n", - "Julia gives us a few different ways to write a function. The first requires the `function` and `end` keywords" + "In programming, functions represent a program construct with which the code can be structured, especially if a program code would appear several times in the program. With a function, it can be placed in one single location.\n", + "\n", + "Julia gives us a few different ways to write a function. \n", + "\n", + "Here the first line starts with the keyword \"function\" followed by the signature/unique identifier. The second line represents the function corpus and contains statements that use the variables defined in the signature. A function always ends with the second keyword \"end\":" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -32,9 +36,8 @@ "sayhi (generic function with 1 method)" ] }, - "execution_count": 1, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ @@ -45,7 +48,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -54,7 +57,7 @@ "f (generic function with 1 method)" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -69,12 +72,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", + "\n", "We can call either of these functions like this:" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -91,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -100,7 +105,7 @@ "1764" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -118,7 +123,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -127,7 +132,7 @@ "sayhi2 (generic function with 1 method)" ] }, - "execution_count": 5, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -138,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -147,7 +152,7 @@ "f2 (generic function with 1 method)" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -158,7 +163,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -175,7 +180,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -184,7 +189,7 @@ "1764" ] }, - "execution_count": 8, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -197,7 +202,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Finally, we could have declared these as \"anonymous\" functions" + "Finally, we could have declared these as \"anonymous\" functions.\n", + "\n", + "Anonymous functions are unnamed functions, i.e. they do not have a unique identifier and are often used when the desired function is only used in one place in the code and only has a limited length. Anonymous functions can then be syntactically simpler." ] }, { @@ -283,13 +290,14 @@ "source": [ "## Duck-typing in Julia\n", "*\"If it quacks like a duck, it's a duck.\"*

\n", - "Julia functions will just work on whatever inputs make sense.

\n", - "For example, `sayhi` works on the name of this minor tv character, written as an integer..." + "The principle behind duck-typing is to define objects/types by a way in which they behave and not which class they belong to.\n", + "\n", + "Julia functions will just work on whatever inputs make sense.

For example, `sayhi` works on the name of this minor tv character, written as an integer..." ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -454,7 +462,7 @@ "source": [ "## Mutating vs. non-mutating functions\n", "\n", - "By convention, functions followed by `!` alter their contents and functions lacking `!` do not.\n", + "By convention, functions followed by `!` alter their contents (mutating function) and functions lacking `!` do not (non-mutating function).\n", "\n", "For example, let's look at the difference between `sort` and `sort!`.\n" ] @@ -587,7 +595,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Some higher order functions\n", + "## Some higher-order functions\n", + "\n", + "A higher-order function must fulfill at least one of the two tasks: It must accept one or more functions as arguments and/or return a function as a result.\n", "\n", "### map\n", "\n", @@ -1066,15 +1076,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.3" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/6 - Packages.ipynb b/6 - Packages_mod.ipynb similarity index 97% rename from 6 - Packages.ipynb rename to 6 - Packages_mod.ipynb index aaa7003..ebc723a 100644 --- a/6 - Packages.ipynb +++ b/6 - Packages_mod.ipynb @@ -6,7 +6,7 @@ "source": [ "# Packages\n", "\n", - "Julia has over 2000 registered packages, making packages a huge part of the Julia ecosystem.\n", + "Julia has over 2000 registered packages, making packages is a huge part of the Julia ecosystem.\n", "\n", "Even so, the package ecosystem still has some growing to do. Notably, we have first class function calls to other languages, providing excellent foreign function interfaces. We can easily call into python or R, for example, with `PyCall` or `Rcall`.\n", "\n", @@ -56,7 +56,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Every time you use Julia (start a new session at the REPL, or open a notebook for the first time, for example), you load the package with the `using` keyword" + "Every time you use Julia (for example start a new session at the REPL, or open a notebook for the first time), you load the package with the `using` keyword" ] }, { @@ -401,7 +401,15 @@ "metadata": {}, "source": [ "#### 7.2 \n", - "Verify that you can now use the function `primes` to grab all prime numbers under 1,000,000 and store it in variable `primes_list`" + "Verify that you can now use the function `primes` to grab all prime numbers under 1,000,000 and store it in variable `primes_list`\n", + "\n", + "\n", + "```\n", + "\n", + "primes(x) = generate prime numbers up to a given limit\n", + "\n", + "primes(x, y) = generate prime numbers within a specific range\n", + "```" ] }, { @@ -436,15 +444,15 @@ ], "metadata": { "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.0" + "version": "1.10.2" } }, "nbformat": 4, diff --git a/7 - Plotting.ipynb b/7 - Plotting_mod.ipynb similarity index 99% rename from 7 - Plotting.ipynb rename to 7 - Plotting_mod.ipynb index 30e4a7e..e2f4448 100644 --- a/7 - Plotting.ipynb +++ b/7 - Plotting_mod.ipynb @@ -186,7 +186,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "One of the advantages to `Plots.jl` is that it allows you to seamlessly change backends. In this notebook, we'll try out the `gr()` and `plotlyjs()` backends.
\n", + "One of the advantages to `Plots.jl` is that it allows you to seamlessly change backends. Backends are like the substructure of software and are therefore most closely connected to the system. Backends are also used to administer the software.\n", + "\n", + "In this notebook, we'll try out the `gr()` and `plotlyjs()` backends.
\n", "\n", "In the name of scientific inquiry, let's use this notebook to examine the relationship between the global temperature and the number of pirates between roughly 1860 and 2000." ] @@ -205,7 +207,15 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Plots supports multiple backends — that is, libraries that actually do the drawing — all with the same API. To start out, let's try the GR backend. You choose it with a call to `gr()`:" + "Plots supports multiple backends — that is, libraries that actually do the drawing — all with the same API. \n", + "\n", + "-> API (Application Programming Interface) is an interface that enables independent applications to communicate with each other and exchange data. \n", + " APIs work like a mediator.\n", + "\n", + "\n", + "To start out, let's try the GR backend (default backend that works fast and contains many plot types (2D and 3D), but has limited interactivity).\n", + "\n", + "You choose it with a call to `gr()`:" ] }, { @@ -666,7 +676,8 @@ "\n", "Note: We've had some confusion about this exercise. :) This is a joke about how people often conflate correlation and causation.\n", "\n", - "**Without changing syntax, we can create this plot with the UnicodePlots backend**" + "\n", + "**Without changing the syntax, we can create this plot with the UnicodePlots backend, as \"Plots.jl\" only provides the syntax of how the plot should look, but backend creates the plot**" ] }, { @@ -763,7 +774,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "#### 8.2 \n", + "\n", "Execute the following code" ] }, @@ -798,15 +811,15 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.0" + "version": "1.10.2" }, "toc": { "nav_menu": { diff --git a/8 - Multiple dispatch.ipynb b/8 - Multiple dispatch_mod.ipynb similarity index 99% rename from 8 - Multiple dispatch.ipynb rename to 8 - Multiple dispatch_mod.ipynb index eb1ae92..b3d1789 100644 --- a/8 - Multiple dispatch.ipynb +++ b/8 - Multiple dispatch_mod.ipynb @@ -13,8 +13,11 @@ "source": [ "In this notebook we'll explore **multiple dispatch**, which is a key feature of Julia.\n", "\n", + "`Dispatch` is the selection of which method is to be executed when a function is used. `Multiple dispatch` is the use of all specified arguments and types of all arguments of a function to select which method is to be called.\n", + "\n", "Multiple dispatch makes software *generic* and *fast*!\n", "\n", + "\n", "#### Starting with the familiar\n", "\n", "To understand multiple dispatch in Julia, let's start with what we've already seen.\n", @@ -24,7 +27,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -33,7 +36,7 @@ "f (generic function with 1 method)" ] }, - "execution_count": 5, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -96,6 +99,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "#### Specifying the types of our input arguments\n", "\n", "However, we also have the *option* to tell Julia explicitly what types our input arguments are allowed to have.\n", @@ -127,7 +131,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We see here that in order to restrict the type of `x` and `y` to `String`s, we just follow the input argument name by a double colon and the keyword `String`.\n", + "We see here that in order to restrict the type of `x` and `y` to `String`s, we just follow the input argument name by a double colon '::' and the keyword 'String'.\n", "\n", "Now we'll see that `foo` works on `String`s and doesn't work on other input argument types." ] @@ -255,6 +259,7 @@ "we didn't overwrite or replace\n", "```julia\n", "foo(x::String, y::String)\n", + "\n", "```\n", "Instead, we just added an additional ***method*** to the ***generic function*** called `foo`.\n", "\n", @@ -266,7 +271,7 @@ "\n", "For example, `+` has methods that accept floating point numbers, integers, matrices, etc.\n", "\n", - "We can use the `methods` to see how many methods there are for `foo`." + "We can use the `methods()` to see how many methods there are for `foo`." ] }, { @@ -518,11 +523,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "So, we now can call `foo` on integers or strings. When you call `foo` on a particular set of arguments, Julia will infer the types of the inputs and dispatch the appropriate method. *This* is multiple dispatch.\n", + "So, we now can call `foo` on integers or strings. When you call `foo` on a particular set of arguments, Julia will infer the types of the inputs and dispatch the appropriate method. *This* is **multiple dispatch**.\n", "\n", "Multiple dispatch makes our code generic and fast. Our code can be generic and flexible because we can write code in terms of abstract operations such as addition and multiplication, rather than in terms of specific implementations. At the same time, our code runs quickly because Julia is able to call efficient methods for the relevant types.\n", "\n", - "To see which method is being dispatched when we call a generic function, we can use the @which macro:" + "To see which method is being dispatched when we call a generic function, we can use the `@which` macro:" ] }, { @@ -685,11 +690,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "### Exercises\n", "\n", "#### 9.1\n", "\n", - "Extend the function `foo`, adding a method that takes only one input argument, which is of type `Bool`, and returns \"foo with one boolean!\"" + "Extend the function `foo`, adding a method that takes only one input argument, which is of type `Bool`, and returns \"foo with one boolean!\"\n", + "\n", + "-> The Boolean (Bool) data type is used to check conditions and can only return `true` or `false`." ] }, { @@ -703,11 +711,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "\n", "#### 9.2\n", "\n", "Check that the method being dispatched when you execute \n", "```julia\n", "foo(true)\n", + "\n", "```\n", "is the one you wrote." ] @@ -745,16 +755,16 @@ "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Julia 1.6.0", + "display_name": "Julia 1.10.2", "language": "julia", - "name": "julia-1.6" + "name": "julia-1.10" }, "language": "Julia", "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", - "version": "1.6.0" + "version": "1.10.2" }, "toc": { "nav_menu": { diff --git a/9 - Julia is fast.ipynb b/9 - Julia is fast_mod.ipynb similarity index 100% rename from 9 - Julia is fast.ipynb rename to 9 - Julia is fast_mod.ipynb diff --git a/LICENSE.md b/LICENSE.md deleted file mode 100644 index 7d084c5..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,20 +0,0 @@ - Copyright (c) 2018-2020: Julia Computing, Inc. - -> Permission is hereby granted, free of charge, to any person obtaining -> a copy of this software and associated documentation files (the -> "Software"), to deal in the Software without restriction, including -> without limitation the rights to use, copy, modify, merge, publish, -> distribute, sublicense, and/or sell copies of the Software, and to -> permit persons to whom the Software is furnished to do so, subject to -> the following conditions: -> -> The above copyright notice and this permission notice shall be -> included in all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Project.toml b/Project.toml deleted file mode 100644 index 917d153..0000000 --- a/Project.toml +++ /dev/null @@ -1,8 +0,0 @@ -[deps] -BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" -Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" -Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" -Example = "7876af07-990d-54b4-ab0e-23690620f79a" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" -UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228" diff --git a/README.md b/README.md index 0b377b5..46f2874 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# Introduction-to-Julia -Learn the language basics in this 10-part course +# Introduction-to-Julia-Programming-basic-course- + +Learn the basics of the Julia programming language with this revised 10-part basic course from JuliaAcademy From c200507a131f35814579c92065c2ca7dd4b87647 Mon Sep 17 00:00:00 2001 From: mma Date: Mon, 11 Mar 2024 14:47:38 +0100 Subject: [PATCH 2/2] missing files --- .gitignore | 26 + 10 - Basic linear algebra_mod.ipynb | 538 ++++++++++ 11 - Factorizations and other fun_mod.ipynb | 1017 +++++++++++++++++++ LICENSE.md | 20 + Project.toml | 8 + 5 files changed, 1609 insertions(+) create mode 100644 .gitignore create mode 100644 10 - Basic linear algebra_mod.ipynb create mode 100644 11 - Factorizations and other fun_mod.ipynb create mode 100644 LICENSE.md create mode 100644 Project.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af55afd --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# Files generated by invoking Julia with --code-coverage +*.jl.cov +*.jl.*.cov + +# Files generated by invoking Julia with --track-allocation +*.jl.mem + +# System-specific files and directories generated by the BinaryProvider and BinDeps packages +# They contain absolute paths specific to the host computer, and so should not be committed +deps/deps.jl +deps/build.log +deps/downloads/ +deps/usr/ +deps/src/ + +# Build artifacts for creating documentation generated by the Documenter package +docs/build/ +docs/site/ + +# File generated by Pkg, the package manager, based on a corresponding Project.toml +# It records a fixed state of all packages used by the project. As such, it should not be +# committed for packages, but should be committed for applications that require a static +# environment. +Manifest.toml + +.ipynb_checkpoints/ \ No newline at end of file diff --git a/10 - Basic linear algebra_mod.ipynb b/10 - Basic linear algebra_mod.ipynb new file mode 100644 index 0000000..f3e0517 --- /dev/null +++ b/10 - Basic linear algebra_mod.ipynb @@ -0,0 +1,538 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic linear algebra in Julia\n", + "Author: Andreas Noack Jensen (MIT & JuliaComputing) (https://twitter.com/anoackjensen?lang=en)\n", + "(with edits from Jane Herriman)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First let's define a random matrix" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Int64}:\n", + " 3 1 3\n", + " 1 1 2\n", + " 3 2 2" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A = rand(1:4,3,3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define a vector of ones" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 1.0\n", + " 1.0\n", + " 1.0" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = fill(1.0, (3,)) # = fill(1.0, 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that $A$ has type Array{Int64,2} but $x$ has type Array{Float64,1}. Julia defines the aliases Vector{Type}=Array{Type,1} and Matrix{Type}=Array{Type,2}. \n", + "\n", + "Many of the basic operations are the same as in other languages\n", + "#### Multiplication" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 7.0\n", + " 4.0\n", + " 7.0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "b = A*x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Transposition\n", + "As in other languages `A'` is the conjugate transpose, or adjoint" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 adjoint(::Matrix{Int64}) with eltype Int64:\n", + " 3 1 3\n", + " 1 1 2\n", + " 3 2 2" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and we can get the transpose with" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 transpose(::Matrix{Int64}) with eltype Int64:\n", + " 3 1 3\n", + " 1 1 2\n", + " 3 2 2" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "transpose(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Transposed multiplication\n", + "Julia allows us to write this without *" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Int64}:\n", + " 19 10 17\n", + " 10 6 9\n", + " 17 9 17" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A'A" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Solving linear systems \n", + "The problem $Ax=b$ for ***square*** $A$ is solved by the \\ function." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 1.0\n", + " 1.0\n", + " 1.0" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A\\b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`A\\b` gives us the *least squares solution* if we have an overdetermined linear system (a \"tall\" matrix)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×2 Matrix{Float64}:\n", + " 0.01259 0.562346\n", + " 0.571931 0.208287\n", + " 0.0761351 0.507003" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Atall = rand(3, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2-element Vector{Float64}:\n", + " 2.3722998636787898\n", + " 12.85556853172185" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Atall\\b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and the *minimum norm least squares solution* if we have a rank-deficient least squares problem" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×2 Matrix{Float64}:\n", + " 0.682093 0.682093\n", + " 0.745287 0.745287\n", + " 0.698837 0.698837" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = rand(3)\n", + "rankdef = hcat(v, v)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2-element Vector{Float64}:\n", + " 4.190527048390038\n", + " 4.190527048390039" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rankdef\\b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Julia also gives us the minimum norm solution when we have an underdetermined solution (a \"short\" matrix)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2×3 Matrix{Float64}:\n", + " 0.692218 0.193236 0.153774\n", + " 0.127852 0.0359394 0.063034" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bshort = rand(2)\n", + "Ashort = rand(2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " -4.139674407706176\n", + " -0.9797338415813472\n", + " 23.563074056363842" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Ashort\\bshort" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The LinearAlgebra library\n", + "\n", + "While much of linear algebra is available in Julia by default (as shown above), there's a standard library named `LinearAlgebra` that brings in many more relevant names and functions. In particular, it provides factorizations and some structured matrix types. As with all packages, you can bring these additional features into your session with a `using LinearAlgebra`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercises\n", + "\n", + "#### 10.1 \n", + "Take the inner product (or \"dot\" product) of a vector `v` with itself and assign it to variable `dot_v`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Int64}:\n", + " 1\n", + " 2\n", + " 3" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "v = [1,2,3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "deletable": false, + "editable": false, + "hide_input": true, + "nbgrader": { + "checksum": "b93dad361f66498eb2460d708f674220", + "grade": true, + "grade_id": "cell-913fef9b0d19cd52", + "locked": true, + "points": 1, + "schema_version": 1, + "solution": false + } + }, + "outputs": [], + "source": [ + "@assert dot_v == 14" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 10.2 \n", + "Take the outer product of a vector v with itself and assign it to variable `outer_v`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "@assert outer_v == [1 2 3\n", + " 2 4 6\n", + " 3 6 9]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 10.3 \n", + "Use [LinearAlgebra.cross](https://docs.julialang.org/en/v1/stdlib/LinearAlgebra/#LinearAlgebra.cross) to compute the cross product of a vector v with itself and assign it to variable `cross_v`" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "deletable": false, + "editable": false, + "hide_input": true, + "nbgrader": { + "checksum": "01642581e27c0ac19752cd90d11ac2ae", + "grade": true, + "grade_id": "cell-e6b6970ffe104df5", + "locked": true, + "points": 1, + "schema_version": 1, + "solution": false + } + }, + "outputs": [], + "source": [ + "@assert cross_v == [0, 0, 0]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.7.1", + "language": "julia", + "name": "julia-1.7" + }, + "language": "Julia", + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/11 - Factorizations and other fun_mod.ipynb b/11 - Factorizations and other fun_mod.ipynb new file mode 100644 index 0000000..ce9be46 --- /dev/null +++ b/11 - Factorizations and other fun_mod.ipynb @@ -0,0 +1,1017 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Factorizations and other fun\n", + "Based on work by Andreas Noack\n", + "\n", + "## Outline\n", + " - Factorizations\n", + " - Special matrix structures\n", + " - Generic linear algebra" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before we get started, let's set up a linear system and use `LinearAlgebra` to bring in the factorizations and special matrix structures." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 2.205296596065241\n", + " 1.8551229792583508\n", + " 0.8533886927959882" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "using LinearAlgebra\n", + "A = rand(3, 3)\n", + "x = fill(1, (3,))\n", + "b = A * x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Factorizations\n", + "\n", + "#### LU factorizations\n", + "In Julia we can perform an LU factorization\n", + "```julia\n", + "PA = LU\n", + "``` \n", + "where `P` is a permutation matrix, `L` is lower triangular unit diagonal and `U` is upper triangular, using `lufact`.\n", + "\n", + "Julia allows computing the LU factorization and defines a composite factorization type for storing it." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LU{Float64, Matrix{Float64}}\n", + "L factor:\n", + "3×3 Matrix{Float64}:\n", + " 1.0 0.0 0.0\n", + " 0.513615 1.0 0.0\n", + " 0.295738 0.271404 1.0\n", + "U factor:\n", + "3×3 Matrix{Float64}:\n", + " 0.83195 0.576718 0.446455\n", + " 0.0 0.687695 0.564783\n", + " 0.0 0.0 -0.0351695" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Alu = lu(A)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LU{Float64, Matrix{Float64}}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "typeof(Alu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The different parts of the factorization can be extracted by accessing their special properties" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " 0.0 1.0 0.0\n", + " 1.0 0.0 0.0\n", + " 0.0 0.0 1.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Alu.P" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " 1.0 0.0 0.0\n", + " 0.513615 1.0 0.0\n", + " 0.295738 0.271404 1.0" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Alu.L" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " 0.83195 0.576718 0.446455\n", + " 0.0 0.687695 0.564783\n", + " 0.0 0.0 -0.0351695" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Alu.U" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Julia can dispatch methods on factorization objects.\n", + "\n", + "For example, we can solve the linear system using either the original matrix or the factorization object." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 0.9999999999999999\n", + " 1.0000000000000002\n", + " 1.0" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "A\\b" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " 0.9999999999999999\n", + " 1.0000000000000002\n", + " 1.0" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Alu\\b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly, we can calculate the determinant of `A` using either `A` or the factorization object" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "det(A) ≈ det(Alu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### QR factorizations\n", + "\n", + "In Julia we can perform a QR factorization\n", + "```\n", + "A=QR\n", + "``` \n", + "\n", + "where `Q` is unitary/orthogonal and `R` is upper triangular, using `qrfact`. " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LinearAlgebra.QRCompactWY{Float64, Matrix{Float64}}\n", + "Q factor:\n", + "3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}:\n", + " -0.441843 0.858892 -0.258997\n", + " -0.860261 -0.487536 -0.149194\n", + " -0.254412 0.156884 0.954286\n", + "R factor:\n", + "3×3 Matrix{Float64}:\n", + " -0.96709 -1.02174 -0.798571\n", + " 0.0 0.619937 0.503618\n", + " 0.0 0.0 -0.0335617" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Aqr = qr(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly to the LU factorization, the matrices `Q` and `R` can be extracted from the QR factorization object via" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}:\n", + " -0.441843 0.858892 -0.258997\n", + " -0.860261 -0.487536 -0.149194\n", + " -0.254412 0.156884 0.954286" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Aqr.Q" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " -0.96709 -1.02174 -0.798571\n", + " 0.0 0.619937 0.503618\n", + " 0.0 0.0 -0.0335617" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Aqr.R" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Eigendecompositions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The results from eigendecompositions, singular value decompositions, Hessenberg factorizations, and Schur decompositions are all stored in `Factorization` types.\n", + "\n", + "The eigendecomposition can be computed" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}}\n", + "values:\n", + "3-element Vector{Float64}:\n", + " -0.871021215213241\n", + " -0.02678184303514708\n", + " 3.406139917482376\n", + "vectors:\n", + "3×3 Matrix{Float64}:\n", + " 0.768088 -0.0906084 -0.633901\n", + " -0.596429 -0.461515 -0.656716\n", + " -0.233051 0.882493 -0.408526" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Asym = A + A'\n", + "AsymEig = eigen(Asym)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The values and the vectors can be extracted from the Eigen type by special indexing" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Float64}:\n", + " -0.871021215213241\n", + " -0.02678184303514708\n", + " 3.406139917482376" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "AsymEig.values" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " 0.768088 -0.0906084 -0.633901\n", + " -0.596429 -0.461515 -0.656716\n", + " -0.233051 0.882493 -0.408526" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "AsymEig.vectors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once again, when the factorization is stored in a type, we can dispatch on it and write specialized methods that exploit the properties of the factorization, e.g. that $A^{-1}=(V\\Lambda V^{-1})^{-1}=V\\Lambda^{-1}V^{-1}$." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Float64}:\n", + " 1.0 5.32907e-15 4.88498e-15\n", + " 2.84217e-14 1.0 2.22045e-14\n", + " -5.68434e-14 -6.03961e-14 1.0" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "inv(AsymEig)*Asym" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Special matrix structures\n", + "Matrix structure is very important in linear algebra. To see *how* important it is, let's work with a larger linear system" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "n = 1000\n", + "A = randn(n,n);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Julia can often infer special matrix structure" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Asym = A + A'\n", + "issymmetric(Asym)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "but sometimes floating point error might get in the way." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2.9631367153816814" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Asym_noisy = copy(Asym)\n", + "Asym_noisy[1,2] += 5eps()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "false" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "issymmetric(Asym_noisy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Luckily we can declare structure explicitly with, for example, `Diagonal`, `Triangular`, `Symmetric`, `Hermitian`, `Tridiagonal` and `SymTridiagonal`." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "Asym_explicit = Symmetric(Asym_noisy);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's compare how long it takes Julia to compute the eigenvalues of `Asym`, `Asym_noisy`, and `Asym_explicit`" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.258496 seconds (134.03 k allocations: 15.456 MiB, 6.10% gc time, 38.03% compilation time)\n" + ] + } + ], + "source": [ + "@time eigvals(Asym);" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 1.050047 seconds (13 allocations: 7.920 MiB)\n" + ] + } + ], + "source": [ + "@time eigvals(Asym_noisy);" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.149938 seconds (5.88 k allocations: 8.358 MiB, 2.11% compilation time)\n" + ] + } + ], + "source": [ + "@time eigvals(Asym_explicit);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, using `Symmetric()` on `Asym_noisy` made our calculations about `5x` more efficient :)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### A big problem\n", + "Using the `Tridiagonal` and `SymTridiagonal` types to store tridiagonal matrices makes it possible to work with potentially very large tridiagonal problems. The following problem would not be possible to solve on a laptop if the matrix had to be stored as a (dense) `Matrix` type." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 0.669902 seconds (823.18 k allocations: 229.291 MiB, 12.15% gc time, 26.00% compilation time)\n" + ] + }, + { + "data": { + "text/plain": [ + "6.7249639294089665" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "n = 1_000_000;\n", + "A = SymTridiagonal(randn(n), randn(n-1));\n", + "@time eigmax(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generic linear algebra\n", + "The usual way of adding support for numerical linear algebra is by wrapping BLAS and LAPACK subroutines. For matrices with elements of `Float32`, `Float64`, `Complex{Float32}` or `Complex{Float64}` this is also what Julia does.\n", + "\n", + "However, Julia also supports generic linear algebra, allowing you to, for example, work with matrices and vectors of rational numbers." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Rational numbers\n", + "Julia has rational numbers built in. To construct a rational number, use double forward slashes:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1//2" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1//2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Example: Rational linear system of equations\n", + "The following example shows how linear system of equations with rational elements can be solved without promoting to floating point element types. Overflow can easily become a problem when working with rational numbers so we use `BigInt`s." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3×3 Matrix{Rational{BigInt}}:\n", + " 1//10 3//5 2//5\n", + " 1//5 1//10 1//5\n", + " 1//5 1//5 3//10" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Arational = Matrix{Rational{BigInt}}(rand(1:10, 3, 3))/10" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Rational{BigInt}}:\n", + " 11//10\n", + " 1//2\n", + " 7//10" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = fill(1, 3)\n", + "b = Arational*x" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3-element Vector{Rational{BigInt}}:\n", + " 1//1\n", + " 1//1\n", + " 1//1" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Arational\\b" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "LU{Rational{BigInt}, Matrix{Rational{BigInt}}}\n", + "L factor:\n", + "3×3 Matrix{Rational{BigInt}}:\n", + " 1//1 0//1 0//1\n", + " 1//2 1//1 0//1\n", + " 1//1 2//11 1//1\n", + "U factor:\n", + "3×3 Matrix{Rational{BigInt}}:\n", + " 1//5 1//10 1//5\n", + " 0//1 11//20 3//10\n", + " 0//1 0//1 1//22" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "lu(Arational)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Exercises\n", + "\n", + "#### 11.1\n", + "What are the eigenvalues of matrix A?\n", + "\n", + "```\n", + "A =\n", + "[\n", + " 140 97 74 168 131\n", + " 97 106 89 131 36\n", + " 74 89 152 144 71\n", + " 168 131 144 54 142\n", + " 131 36 71 142 36\n", + "]\n", + "```\n", + "and assign it a variable `A_eigv`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using LinearAlgebra" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "deletable": false, + "editable": false, + "hide_input": true, + "nbgrader": { + "checksum": "f9f16fdef201ed372323a291f1dd1346", + "grade": true, + "grade_id": "cell-4d5f60c8a814c789", + "locked": true, + "points": 0, + "schema_version": 1, + "solution": false + } + }, + "outputs": [], + "source": [ + "@assert A_eigv == [-128.49322764802145, -55.887784553056875, 42.7521672793189, 87.16111477514521, 542.4677301466143]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 11.2 \n", + "Create a `Diagonal` matrix from the eigenvalues of `A`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "deletable": false, + "editable": false, + "hide_input": true, + "nbgrader": { + "checksum": "3ca676f6282c1a7c214ab2cb9f9b322d", + "grade": true, + "grade_id": "cell-3b000a3710c9c263", + "locked": true, + "points": 1, + "schema_version": 1, + "solution": false + } + }, + "outputs": [], + "source": [ + "@assert A_diag == [-128.493 0.0 0.0 0.0 0.0;\n", + " 0.0 -55.8878 0.0 0.0 0.0;\n", + " 0.0 0.0 42.7522 0.0 0.0;\n", + " 0.0 0.0 0.0 87.1611 0.0;\n", + " 0.0 0.0 0.0 0.0 542.468]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 11.3 \n", + "Create a `LowerTriangular` matrix from `A` and store it in `A_lowertri`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "deletable": false, + "editable": false, + "hide_input": true, + "nbgrader": { + "checksum": "b3b1a272343a05082f378a5e1aa3426d", + "grade": true, + "grade_id": "cell-b76cee2b4a8777da", + "locked": true, + "points": 0, + "schema_version": 1, + "solution": false + } + }, + "outputs": [], + "source": [ + "@assert A_lowertri == [140 0 0 0 0;\n", + " 97 106 0 0 0;\n", + " 74 89 152 0 0;\n", + " 168 131 144 54 0;\n", + " 131 36 71 142 36]" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.6.0", + "language": "julia", + "name": "julia-1.6" + }, + "language": "Julia", + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.6.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7d084c5 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,20 @@ + Copyright (c) 2018-2020: Julia Computing, Inc. + +> Permission is hereby granted, free of charge, to any person obtaining +> a copy of this software and associated documentation files (the +> "Software"), to deal in the Software without restriction, including +> without limitation the rights to use, copy, modify, merge, publish, +> distribute, sublicense, and/or sell copies of the Software, and to +> permit persons to whom the Software is furnished to do so, subject to +> the following conditions: +> +> The above copyright notice and this permission notice shall be +> included in all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +> EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +> MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +> NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +> LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +> OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +> WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..917d153 --- /dev/null +++ b/Project.toml @@ -0,0 +1,8 @@ +[deps] +BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" +Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" +Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d" +Example = "7876af07-990d-54b4-ab0e-23690620f79a" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" +UnicodePlots = "b8865327-cd53-5732-bb35-84acbb429228"