{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Playing with matrices\n", "(and if you get the subliminal message about abstractions, we'll be thrilled!)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia is a dynamic language. You don't need type declarations, and can change variable types dynamically and interactively.\n", "\n", "For working with simple numbers, arrays, and strings, its syntax is *superficially* similar to Matlab, Python, and other popular languages.\n", "\n", "In order to execute the `In` cells, select the cell and press `Shift-Enter`, or press the `Play` button above. To run the entire notebook, navigate to the `Cell` menu and then `Run All`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# We tell beginners, you don't need types!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "typeof(1.0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "typeof(1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "S = \"Hello Julia Class\"\n", "typeof(S)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Exercise fix my spelling in the cell above\n", "S" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Now forget all that (for now): Julia is not so different from your favorite dynamic language" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "1 + 1 # shift + enter to run" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = rand(5, 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra # A LinearAlgebra standard package contains structured matrices\n", "A = SymTridiagonal(rand(6), rand(5))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "b = rand(6)\n", "A \\ b" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(3.15, 5, 5) # Fill a 5x5 array with 3.15's" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Let's create some addition tables" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First let's use a nested for loop to fill in a matrix that's initially zero:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = zeros(5, 5)\n", "\n", "for i in 1:5\n", " for j in 1:5\n", " A[i, j] = i+j # Square brackets for indices. Also: indices start at 1, not 0.\n", " end\n", "end\n", "\n", "A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can abbreviate this using a double `for` loop:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i in 1:5, j in 1:5\n", " A[i, j] = i+j # Square brackets for indices. Also: indices start at 1, not 0.\n", "end\n", "\n", "A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Julia way would be to use a so-called **array comprehension**:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[i+j for i in 1:5, j in 1:5]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Equivalently,\n", "[i+j for i = 1:5, j = 1:5]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Explore**: What does the following do? " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[i for i in (1:7).^2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# What happens when we remove the dot syntax?\n", "[i for i in (1:7)^2]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[i^2 for i in 1:7]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Explore**: What does the following do? " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sort(unique(x^2 + y^2 for x in 1:5, y in 1:5)) # The inner parentheses define a **generator**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we want to see $n \\times n$ multiplication tables for $n=1,2,3,4,5$:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for n in 1:5\n", " display([i*j for i=1:n, j=1:n])\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# `Interact.jl` is a Julia *package* for interacting with data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It's way more fun to **interact** with our data.\n", "We install the `Interact.jl` package as follows; this needs to be executed only once for any given Julia installation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# using Pkg; Pkg.add(\"Interact\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we load the package with the following `using` command, in each Julia session:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "using Interact" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The package contains a `@manipulate` macro, that is wrapped around a `for` loop:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for n in 1:1000\n", " n\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for n in 1:20\n", " [i*j for i in 1:n, j in 1:n]\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We use a double `for` loop to get a double slider!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for n in 3:10, i in 1:9\n", " A = fill(0, n, n)\n", " A[1:3, 1:3] .= i # fill a sub-block\n", "A\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia is built around functions: all \"commands\" or \"operations\" in Julia are functions:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# verbose form:\n", "function f(x)\n", " x^2\n", "end\n", "\n", "# one-line form:\n", "f2(x) = x^2\n", "\n", "# anonymous form:\n", "f3 = x -> x^2;" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f(10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions just work, as long as they make sense:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The square of a matrix is unambiguously defined\n", "f(rand(3, 3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# What the 'square of a vector' means is ambiguous\n", "f(rand(3))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# In the definition below, `a` and `power` are optional arguments to `f`, supplied with default values.\n", "function f(x, a=1, power=2)\n", " a*x^power\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# `a` defaults to 1 and `power` to 2\n", "f(7)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The first optional argument passed is assigned to the local variable `a`\n", "# `power` defaults to 2\n", "f(10, 3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f(10, 3, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's define a function to insert a block in a matrix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "function insert_block(A, i, j, what=7)\n", " B = A[:,:] # B is a copy of A \n", " B[i:i+2, j:j+2] = fill(what, 3, 3)\n", " \n", " return B # the `return` keyword is optional\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(0, 9, 9)\n", "insert_block(A, 3, 5) # this returns the new matrix" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(0, 9, 9)\n", "insert_block(A, 3, 5, 2) # Use 2 instead of 7" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can move the block around:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(0, 10, 10)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia can manipulate strings easily:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "S = \"Hello\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "replace(S, \"H\" => \"J\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = 3" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "string(S, \" \", S, \" \", \"Julia; a = \", a) # build a string by concatenating things" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More about strings: Julia Doc on Strings " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions in Julia try to be **generic**, i.e. to work with as many kinds of object as possible:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(\"Julia\", 5, 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Julia allows us to display objects in different ways. For example, the following code displays a matrix of strings\n", "in the notebook using an HTML representation:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "function Base.show(io::IO, ::MIME\"text/html\", M::Matrix{T}) where {T<:String}\n", " max_length = maximum(length.(M))\n", " dv=\"
\"\n", " print(io, dv*join([join(\"
\".*M[i,:].*\"
\", \" \") for i in 1:size(M, 1)]\n", " , \"
$dv\")*\"\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Remember this ????\n", "A = fill(0, 10, 10)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i,j)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's use the **same code**, but now with strings:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(\"Julia\", 10, 10)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i,j, \"[FUN]\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j, \"π\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j, \"♡\")\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "airplane = \"✈\"\n", "alien = \"👽\"\n", "rand([airplane, alien], 5, 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(airplane, 9, 9)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j, alien)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Colors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Colors` package provides objects representing colours:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# using Pkg; Pkg.add(\"Colors\")\n", "using Colors" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "distinguishable_colors(12)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "@manipulate for n in 1:80\n", " distinguishable_colors(n)\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "colors = distinguishable_colors(100)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Remember this ????\n", "A = fill(0, 10, 10)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j)\n", "end" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What happens if we use colors instead?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = fill(colors[1], 10, 10)\n", "n = size(A, 1)\n", "\n", "@manipulate for i in 1:n-2, j in 1:n-2\n", " insert_block(A, i, j, colors[4])\n", "end" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Exercise: Create Tetris Pieces, have them fall from the top" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Julia 1.0.0", "language": "julia", "name": "julia-1.0" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.0.0" }, "toc": { "colors": { "hover_highlight": "#DAA520", "running_highlight": "#FF0000", "selected_highlight": "#FFD700" }, "moveMenuLeft": true, "nav_menu": { "height": "248px", "width": "252px" }, "navigate_menu": true, "number_sections": true, "sideBar": true, "threshold": "2", "toc_cell": false, "toc_section_display": "block", "toc_window_display": false }, "widgets": { "state": { "03e03820-87b0-457b-ab42-ded0426544fd": { "views": [ { "cell_index": 69 } ] }, "112a7d1d-27a4-41ed-86dd-495c55c3cc41": { "views": [ { "cell_index": 76 } ] }, "303254d1-f92c-4694-bec9-228877cbfeaa": { "views": [ { "cell_index": 32 } ] }, "3ab85729-787a-45d8-93bc-18d160c42925": { "views": [ { "cell_index": 67 } ] }, "59018bf0-5304-420a-954c-b60b6ade41bc": { "views": [ { "cell_index": 35 } ] }, "6596be93-5ae6-44d8-9928-118f26925ca2": { "views": [ { "cell_index": 66 } ] }, "6ddddb05-e17f-4527-b346-b03c7654a9bd": { "views": [ { "cell_index": 50 } ] }, "73b7ac02-1931-45ea-bab0-a0661446f2c4": { "views": [ { "cell_index": 78 } ] }, "7fbfcf1d-2446-46b0-8c48-137bd1b04e59": { "views": [ { "cell_index": 50 } ] }, "82e70dac-395e-4e4b-99d8-7c86157baef8": { "views": [ { "cell_index": 67 } ] }, "9c1f13ea-b532-45c7-b638-4f2e0753e701": { "views": [ { "cell_index": 33 } ] }, "a01da64b-6f5f-4ec4-bfb6-0dd4b5608910": { "views": [ { "cell_index": 63 } ] }, "a0cab882-0559-4d6a-a78f-f1c28aafece6": { "views": [ { "cell_index": 35 } ] }, "a81871a0-14a4-41b1-a6c5-4fcdccafa1ab": { "views": [ { "cell_index": 69 } ] }, "b2248808-aeeb-40c7-a647-29ff9e394260": { "views": [ { "cell_index": 65 } ] }, "b59a0470-d356-4c66-9c43-a590a92e4925": { "views": [ { "cell_index": 66 } ] }, "b8661b37-c86d-484e-8225-0965da985371": { "views": [ { "cell_index": 65 } ] }, "ba049dd3-9042-4cc9-acce-f07f08746316": { "views": [ { "cell_index": 76 } ] }, "cbf99c6a-4771-4b80-a2bf-22d90cd5fb84": { "views": [ { "cell_index": 74 } ] }, "e1aeaa28-549c-4032-b84e-ef9b2ba7a74e": { "views": [ { "cell_index": 63 } ] }, "e1f5a7f1-25fe-4147-9ab0-c58a324d613a": { "views": [ { "cell_index": 78 } ] } }, "version": "1.2.0" } }, "nbformat": 4, "nbformat_minor": 2 }