{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to Julia" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Contents:\n", "\n", "- [Introduction to Julia](#Introduction-to-Julia) \n", " - [GitHub](#GitHub) \n", " - [Work Environment](#Work-Environment) \n", " - [Jupyter Basics](#Jupyter-Basics) \n", " - [Julia Basics](#Julia-Basics) \n", "\n", "\n", "In this lab we will: \n", "\n", "(1) Load the lab GitHub repository locally;\n", "\n", "(2) Set up our work environment by installing Julia and Jupyter; \n", "\n", "(3) Cover Jupyter basics; \n", "\n", "(4) Go over some Julia basics.\n", "\n", "The goal is to set up a stable work environment for the rest of the quarter while getting a taste of the Julia language.\n", "\n", "Today's material borrows quite a lot from [Quantitative Economics with Julia by QuantEcon](https://julia.quantecon.org/), so I encourage everyone to check it out for more details." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## GitHub" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you might have already noticed, all lab materials for this quarter live on GitHub. I've done so to allow for easy version control and replicability.\n", "\n", "Here I will guide you through the bare minimum of the necessary GitHub functionality required to maintain up-to-date access to lab materials. \n", "\n", "Go to the [GitHub website](https://github.com/) to create an account and register for a [student/educator discount](https://education.github.com/pack/offers) (this last part isn't necessary, but can't hurt).\n", "\n", "After finishing the above step, download and install [GitHub Desktop](https://desktop.github.com/). Open it and log into your GitHub account locally.\n", "\n", "In the GitHub Desktop interface, go to `File > Clone Repository`:\n", "\n", "![](images/github_clone_repo.png)\n", "\n", "The following box should pop up, in which we need to navigate to the `URL` tab:\n", "\n", "![](images/github_clone_url.png)\n", "\n", "Paste `https://github.com/gionikola/spring2021_core_macro_lab.git` into the URL, and then choose a folder in which you would like to keep the lab materials.\n", "\n", "Once this is done, make sure that the `Current repository` is set to `spring2021_core_macro_lab`:\n", "\n", "![](images/github_current_repo.png)\n", "\n", "Now we can automatically keep all lab documents up-to-date by periodically opening up GitHub Desktop and going to `Repository > Pull`:\n", "\n", "![](images/github_pull.png)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Work Environment" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To set up the necessary work environment for these labs, we need to do the following three things:\n", "\n", "- Download and install Julia;\n", "- Download and install Jupyter;\n", "- \"Connect\" Jupyter with Julia.\n", "\n", "We will first need to download and install the current stable version of Julia by visiting [this page](https://julialang.org/downloads/) and following the instructions for the appropriate operating system. \n", "\n", "Then we will need to visit [this page](https://www.anaconda.com/products/individual) to download and install Anaconda, which essentially a package management tool that includes Jupyter. To learn more about Anaconda, read the [Wikipedia page](https://en.wikipedia.org/wiki/Anaconda_(Python_distribution)). \n", "\n", "Once both Julia and Anaconda are installed, we can perform the final step of linking Jupyter with Julia. Open Julia -- we should see the following window pop up:\n", "\n", "![](images/repl.png)\n", "\n", "This is the Julia REPL (Read-Evaluate-Print Loop). \n", "\n", "Now type `]` to enter package mode, then type `add IJulia`.\n", "\n", "![](images/repl_package_mode.png)\n", "\n", "We then click `Enter` on the keyboard to run the command. This will install the IJulia kernel, which should automatically link Julia with Jupyter. After the installation is complete, we click `Backspace` on the keyboard to leave package mode.\n", "\n", "We can now type `using IJulia; notebook()` into the REPL to launch Jupyter Notebook. If this running this command leads to an error or the prompt `install Jupyter via Conda, y/n? [y]:`, then we can alternatively launch Jupyter Notebook by finding where it lives on our machine and/or typing `jupyter notebook` into the Anaconda Prompt. In any case, we should see something similar to the following tab open in our web browser (but in a different directory):\n", "\n", "![](images/jupyter_repository.png)\n", "\n", "We can now manually navigate to our preferred directory (folder) and create new notebooks, along with other types of documents. When we open a document, it will open as a new tab in our web browser.\n", "\n", "At this point we are all set-up and ready to code!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Jupyter Basics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The keyboard shortcuts window says it best: \"The Jupyter Notebook has two different keyboard input modes. Edit mode allows you to type code or text into a cell and is indicated by a green cell border. Command mode binds the keyboard to notebook level commands and is indicated by a grey cell border with a blue left margin.\"\n", "\n", "At any given point in time in the Jupyter interface we are either in edit mode or command mode. We can tell which mode we are in using two indicators: (1) the color of the outline around a selected cell, and (2) the presence/absence of a pencil symbol next to the active kernel name at the upper-right corner of the notebook.\n", "\n", "If we are in edit mode, then we should see the following:\n", "\n", "![](images/jupyter_edit_mode.png)\n", "\n", "Otherwise we should see the following:\n", "\n", "![](images/jupyter_cmd_mode.png)\n", "\n", "The following is a list of some very useful shortcuts:\n", "\n", "- `Esc` triggers command mode if currently in edit mode;\n", "- `Enter` triggers edit mode if currently in command mode;\n", "- `Ctrl-Enter` runs selected cell;\n", "- `Shift-Enter` runs selected cell and selects the next cell below;\n", "- `Alt-Enter` runs selected cell and creates a new cell below;\n", "- `D, D` deletes selected cell.\n", "\n", "Check out more shortcuts by going into command mode and clicking the `H` key.\n", "\n", "There are three types of cells (1) code, (2) Markdown, and (3) raw. We will mostly be interested in code and Markdown cells, so we disregard the final category. We can tell what type of cell we are dealing with by either (1) looking up at our toolbar \n", "\n", "![](images/jupyter_toolbar.png)\n", "\n", "or by (2) looking to the left of the cell to check whether there is a `In [ ]:` present -- if so, then we have ourselves a code cell, otherwise it is a Markdown cell.\n", "\n", "A couple more useful shortcuts:\n", "\n", "- `M` changes a selected cell type to Markdown if in command mode;\n", "- `Y` changes a selected cell type to code if in command mode.\n", "\n", "Jupyter is simple and intuitive enough that the above should be enough to get us going." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## Julia Basics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Packages" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us start by loading Julia packages." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "using LinearAlgebra # Load LinearAlgebra package\n", "using Statistics # Load Statistics package" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we do not have the `LinearAlgebra` package available in our environment. \n", "\n", "In this case, loading LinearAlgebra with `using` will not work, since we first need to install the package using the following code: " ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", "\u001b[32m\u001b[1mNo Changes\u001b[22m\u001b[39m to `C:\\Users\\gioni\\Project.toml`\n", "\u001b[32m\u001b[1mNo Changes\u001b[22m\u001b[39m to `C:\\Users\\gioni\\Manifest.toml`\n" ] } ], "source": [ "using Pkg # Load `Pkg`, which can be used to install packages\n", "Pkg.add(\"LinearAlgebra\") # Install `LinearAlgebra` package\n", "using LinearAlgebra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We could have alternatively opened the REPL, entered package mode by clicking `]`, and ran `add LinearAlgebra`.\n", "\n", "![](images/repl_linearalgebra.png)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simple Data Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that basic package management is out of the way, we can start talking about data types." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we have randomly-generated variables $x$ and $y$, and would like to check whether $x > y$. Let's call this condition A. We can store the status of condition A as a Boolean variable $z$. " ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"x = -1.1073262538888373 and y = -1.7756952833062138, therefore condition A is true.\"" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = randn() # Generate random value `x`\n", "y = randn() # Generate random value `y`\n", "z = x > y # Store status of condition A as variable `z`\n", "message = \"x = $(x) and y = $(y), \" * \"therefore condition A is $(z).\"\n", "message" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that we used the `randn()` function to generate a random $x,y \\in \\mathbb{R}$. \n", "Furthermore, we generated a string called `message` by concatenating two separate strings using `*`.\n", "We print the values of variable `x`, `y`, and `z` in `message` using `$`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's confirm that `message` is indeed a string:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "String" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(message)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's also check the data type of `x` (and equivalently `y`):" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Array{Int64,1}" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's check the data type of `z`:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Bool" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "typeof(z)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far we've seen strings, floats, and booleans, but we also have integers:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Int64" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y = 5\n", "typeof(y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since we have a float `x` and an integer `y`, let's test out some basic arithmetic operations with them:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Int64)\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Base.CoreLogging.LogLevel\u001b[39m, ::Integer) at logging.jl:116\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Int64)\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Base.CoreLogging.LogLevel\u001b[39m, ::Integer) at logging.jl:116\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "", "Stacktrace:", " [1] top-level scope at show.jl:641", " [2] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091" ] } ], "source": [ "@show x + y\n", "@show x - y\n", "@show x * y\n", "@show x / y\n", "@show x - (-y)\n", "@show 3x - 4y\n", "@show x^(-1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that we used the `@show` macro the print out equations.\n", "Furthermore, we ended the last line of the cell with a `;` to supress the redundant printing of the output of `x^(-1)`. \n", "See what happens when you construct a similar cell without `;` at the end." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But did you know we can also apply arithmetic operations to booleans?" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "z1 + 0 = 1\n", "z2 + 0 = 0\n", "z1 + z2 = 1\n" ] }, { "ename": "LoadError", "evalue": "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Bool)\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Bool\u001b[39m, ::Bool) at bool.jl:96\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Bool)\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Bool\u001b[39m, ::Bool) at bool.jl:96\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "", "Stacktrace:", " [1] top-level scope at show.jl:641", " [2] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091" ] } ], "source": [ "z1 = true # define a true boolean \n", "z2 = false # define a false boolean\n", "@show z1 + 0\n", "@show z2 + 0\n", "@show z1 + z2 \n", "@show x + z1\n", "@show x * z1;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's give `x` and `y` imaginary components, and play around with the resulting imaginary numbers." ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Complex{Int64})\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Bool\u001b[39m, ::Complex) at complex.jl:293\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mMethodError: no method matching +(::Array{Int64,1}, ::Complex{Int64})\u001b[39m\n\u001b[91mFor element-wise addition, use broadcasting with dot syntax: array .+ scalar\u001b[39m\n\u001b[91m\u001b[0mClosest candidates are:\u001b[39m\n\u001b[91m\u001b[0m +(::Any, ::Any, \u001b[91m::Any\u001b[39m, \u001b[91m::Any...\u001b[39m) at operators.jl:538\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Missing\u001b[39m, ::Number) at missing.jl:115\u001b[39m\n\u001b[91m\u001b[0m +(\u001b[91m::Bool\u001b[39m, ::Complex) at complex.jl:293\u001b[39m\n\u001b[91m\u001b[0m ...\u001b[39m", "", "Stacktrace:", " [1] top-level scope at show.jl:641", " [2] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091" ] } ], "source": [ "@show x = x + 3im\n", "@show y = y + 2im\n", "@show x + y\n", "@show x - y\n", "@show x * y\n", "@show x / y\n", "@show x - (-y)\n", "@show 3x - 4y\n", "@show x^(-1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Introduction to Arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also collect data into arrays." ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 10\n", " 20\n", " 30" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = [10, 20, 30]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The output here tells us that `a` is a one-dimensional array containing `Int64` data. " ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Float64,1}:\n", " 1.0\n", " 2.0\n", " 3.0" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = [1.0, 2.0, 3.0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`b` seems to have the same dimensions as `a`, but it contains `Float64` data instead of integer data." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Suppose we try to include multiple data types in a single array:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4-element Array{Any,1}:\n", " 1\n", " 1.0\n", " true\n", " \"text\"" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = [1, 1.0, true, \"text\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is undesirable, but as we can see -- it works." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check out the dimensions and size of array/vector `b`:" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ndims(b) = 1\n", "size(b) = (3,)\n" ] } ], "source": [ "@show ndims(b) # Show dimensions of vector `b`\n", "@show size(b); # Show size of vector `b`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The above output essentially tells us that `b` is a vector with 3 entries. \n", "\n", "I say that `b` is a vector since a one-dimensional array is equivalent to a vector, while a two-dimensional array is equivalent to a matrix. \n", "\n", "We confirm this in the following cell:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Array{Float64, 1} == Vector{Float64} = true\n", "Array{Float64, 2} == Matrix{Float64} = true\n" ] } ], "source": [ "@show Array{Float64, 1} == Vector{Float64}\n", "@show Array{Float64, 2} == Matrix{Float64};" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are two different ways we can create a column vector:" ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "col1 = [1, 2, 3]\n", "col2 = [1; 2; 3]\n", "col1 == col2 # Test if both are column vectors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also create row vectors in the following manner:" ] }, { "cell_type": "code", "execution_count": 82, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×3 Array{Int64,2}:\n", " 1 2 3" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "row1 = [1 2 3]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check the dimensions and size of the row vector `row1`:" ] }, { "cell_type": "code", "execution_count": 85, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ndims(row1) = 2\n", "size(row1) = (1, 3)\n" ] } ], "source": [ "@show ndims(row1)\n", "@show size(row1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "According to the above output, row vectors are 2-dimensional -- in other words, they are matrices.\n", "\n", "Furthermore, unlike column vectors, row vectors are not flat. The above output shows that `row1` has one row and three columns." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create a more traditional-looking matrix `A`:" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Array{Int64,2}:\n", " 1 2\n", " 3 4" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = [1 2; 3 4]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's transpose `A`:" ] }, { "cell_type": "code", "execution_count": 91, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Adjoint{Int64,Array{Int64,2}}:\n", " 1 3\n", " 2 4" ] }, "execution_count": 91, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can access the second column of `A` in the following manner:" ] }, { "cell_type": "code", "execution_count": 94, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element Array{Int64,1}:\n", " 2\n", " 4" ] }, "execution_count": 94, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[:,2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Analogously, we may access the second row of `A` in the following manner:" ] }, { "cell_type": "code", "execution_count": 97, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element Array{Int64,1}:\n", " 3\n", " 4" ] }, "execution_count": 97, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[2,:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that when we accessed the second row of `A`, the output was a flat array (column vector).\n", "\n", "To may simply transpose it to obtain it in row vector form:" ] }, { "cell_type": "code", "execution_count": 100, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1×2 Adjoint{Int64,Array{Int64,1}}:\n", " 3 4" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A[2,:]'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we want to access the $(2,2)$ entry of `A`?" ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A'[2,2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's talk briefly about array creation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A nice way of creating zero vectors is using the `zeros()` function:" ] }, { "cell_type": "code", "execution_count": 103, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element Array{Float64,1}:\n", " 0.0\n", " 0.0" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "zeros(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, we can use `zeros()` to create matrices:" ] }, { "cell_type": "code", "execution_count": 105, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Array{Float64,2}:\n", " 0.0 0.0\n", " 0.0 0.0" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "zeros(2,2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More generally, we may use the `fill()` function to create arrays with customized uniform entries:" ] }, { "cell_type": "code", "execution_count": 107, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×4 Array{Int64,2}:\n", " 3 3 3 3\n", " 3 3 3 3" ] }, "execution_count": 107, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fill(3, 2, 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How do we copy an array? Let's try simply using an equality:" ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 1\n", " 0\n", " 1" ] }, "execution_count": 109, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fill(1, 3) # create vector `x`\n", "y = x # bind `y` to vector `x`\n", "y[2] = 0 # change second entry of `y` to zero\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What we did in the above cell is create a vector `x`, bind a new variable `y` to `x`, and then change the second entry of `y`. \n", "\n", "We would expect this to alter `y` and not `x`, but it turns out this is not the case!\n", "\n", "So we can't quite \"copy\" arrays using a simple equality. Instead we may use the `copy()` function:" ] }, { "cell_type": "code", "execution_count": 111, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 1\n", " 1\n", " 1" ] }, "execution_count": 111, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fill(1, 3)\n", "y = copy(x) \n", "y[2] = 0\n", "x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that `x` didn't change, as desired." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What if we don't want to copy an array exactly, but instead create an array of the same data type and size?\n", "\n", "For this we can use the `similar()` function:" ] }, { "cell_type": "code", "execution_count": 113, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 230286480\n", " 387663984\n", " 387664016" ] }, "execution_count": 113, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fill(1, 3)\n", "y = similar(x)\n", "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may also use `similar()` to change the size while keeping the same data type:" ] }, { "cell_type": "code", "execution_count": 115, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4-element Array{Int64,1}:\n", " 1\n", " 0\n", " 0\n", " 0" ] }, "execution_count": 115, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fill(1, 3)\n", "y = similar(x, 4)\n", "y " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may also create a matrix similar to a vector:" ] }, { "cell_type": "code", "execution_count": 117, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Array{Int64,2}:\n", " 230286480 399933536\n", " 399900928 165547088" ] }, "execution_count": 117, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fill(1, 3)\n", "y = similar(x, 2, 2)\n", "y" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Array Operations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's create a random vector and then check out some of its properties:" ] }, { "cell_type": "code", "execution_count": 119, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "length(v) = 3\n", "sum(v) = 0\n", "mean(v) = 0.0\n", "std(v) = 1.0\n", "var(v) = 1.0\n", "maximum(v) = 1\n", "minimum(v) = -1\n", "extrema(v) = (-1, 1)\n" ] } ], "source": [ "v = [-1, 0, 1] # create vector `v` w/ 100 draws from N(0,1) distribution\n", "\n", "@show length(v)\n", "@show sum(v)\n", "@show mean(v)\n", "@show std(v)\n", "@show var(v)\n", "@show maximum(v)\n", "@show minimum(v)\n", "@show extrema(v);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can sort the values in vector `v`:" ] }, { "cell_type": "code", "execution_count": 121, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3-element Array{Int64,1}:\n", " 1\n", " 0\n", " -1" ] }, "execution_count": 121, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w = sort(v, rev = true)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The way in which we sorted vector `v` above does not modify `v` itself. \n", "\n", "We can, however, also modify the original vector using the `sort()` function:" ] }, { "cell_type": "code", "execution_count": 123, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 123, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w = sort!(v, rev = true) \n", "v == w" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that in the above cell we tested whether vectors `w` and `v` have the same values, and found that they do! This means that the original vector `v` was successfully modified." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How to do matrix multiplication?" ] }, { "cell_type": "code", "execution_count": 125, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A * B = [3.0 3.0; 3.0 3.0]\n", "A * B' = [3.0 3.0; 3.0 3.0]\n", "A * c = [7, 5]\n", "c' * A = [7 5]\n" ] } ], "source": [ "A = [1 2; 2 1]\n", "B = ones(2,2)\n", "c = [1, 3]\n", "\n", "@show A*B\n", "@show A*B'\n", "@show A*c \n", "@show c'*A;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's solve $A \\, x = c$:" ] }, { "cell_type": "code", "execution_count": 127, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "true" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x1 = A \\ c # the best approach\n", "x2 = inv(A) * c # alternative\n", "x1 ≈ x2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the above cell I show two equivalent ways of solving for $x$.\n", "\n", "I check their equivalence by testing whether `x1` is approximately equal to `x2` using the $\\approx$ operator.\n", "\n", "You may write $\\approx$ in a code cell by typing \"\\approx\" ($\\LaTeX$ syntax) and hitting 'Tab' on your keyboard. \n", "\n", "In fact, you can write many other characters this way:" ] }, { "cell_type": "code", "execution_count": 129, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "α = 1 # \\alpha + Tab\n", "β = 2 # \\beta + Tab\n", "γ = α + β # \\gamma + Tab\n", "γ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also easily do elementwise operations. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, suppose we would like add 1 to every element of a vector or a matrix.\n", "\n", "To do so, we **broadcast** the addition (`+`) operator by also including a period (`.+`):" ] }, { "cell_type": "code", "execution_count": 131, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A .+ 1 = [2.0 2.0; 2.0 2.0]\n", "x .+ 1 = [2.0, 2.0]\n" ] } ], "source": [ "A = ones(2,2)\n", "x = ones(2) \n", "@show A .+ 1\n", "@show x .+ 1;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, we can squared every entry of a vector/matrix:" ] }, { "cell_type": "code", "execution_count": 133, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(A .+ 1) .^ 2 = [4.0 4.0; 4.0 4.0]\n", "(x .+ 1) .^ 2 = [4.0, 4.0]\n" ] }, { "data": { "text/plain": [ "2-element Array{Float64,1}:\n", " 4.0\n", " 4.0" ] }, "execution_count": 133, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@show (A .+ 1).^2\n", "@show (x .+ 1).^2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In fact, we can broadcast pretty much any function. Here's another example:" ] }, { "cell_type": "code", "execution_count": 135, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "log.(A .+ 1) = [0.6931471805599453 0.6931471805599453; 0.6931471805599453 0.6931471805599453]\n", "log.(x .+ 1) = [0.6931471805599453, 0.6931471805599453]\n" ] }, { "data": { "text/plain": [ "2-element Array{Float64,1}:\n", " 0.6931471805599453\n", " 0.6931471805599453" ] }, "execution_count": 135, "metadata": {}, "output_type": "execute_result" } ], "source": [ "@show log.(A .+ 1)\n", "@show log.(x .+ 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Broadcasting is a very handy tool that you should end up using a lot to write efficient code." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lastly, some basic linear algebra tools:" ] }, { "cell_type": "code", "execution_count": 137, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2×2 Array{Int64,2}:\n", " 1 2\n", " 2 1" ] }, "execution_count": 137, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = [1 2; 2 1]" ] }, { "cell_type": "code", "execution_count": 139, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-3.0" ] }, "execution_count": 139, "metadata": {}, "output_type": "execute_result" } ], "source": [ "det(A)" ] }, { "cell_type": "code", "execution_count": 141, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 141, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tr(A)" ] }, { "cell_type": "code", "execution_count": 143, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2-element Array{Float64,1}:\n", " -1.0\n", " 3.0" ] }, "execution_count": 143, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eigvals(A)" ] }, { "cell_type": "code", "execution_count": 145, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 145, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rank(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tuples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tuples are essentially **immutable** data containers.\n", "\n", "Let's create one:" ] }, { "cell_type": "code", "execution_count": 147, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(\"macro\", 3.0, 2021)" ] }, "execution_count": 147, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tup = (\"macro\", 3.0, 2021)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's try to change the second entry of `tup` to `1.0` (something that we often do with arrays):" ] }, { "cell_type": "code", "execution_count": 148, "metadata": {}, "outputs": [ { "ename": "LoadError", "evalue": "\u001b[91mMethodError: no method matching setindex!(::Tuple{String,Float64,Int64}, ::Float64, ::Int64)\u001b[39m", "output_type": "error", "traceback": [ "\u001b[91mMethodError: no method matching setindex!(::Tuple{String,Float64,Int64}, ::Float64, ::Int64)\u001b[39m", "", "Stacktrace:", " [1] top-level scope at In[148]:1", " [2] include_string(::Function, ::Module, ::String, ::String) at .\\loading.jl:1091" ] } ], "source": [ "tup[2] = 2.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We obtained an error precisely because of the **immutability** of tuples -- once we define a tuple, we cannot change its entry values." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try to store tuple entries as distinct variables:" ] }, { "cell_type": "code", "execution_count": 149, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"Year: 2021, Quarter: 3.0, Class: macro\"" ] }, "execution_count": 149, "metadata": {}, "output_type": "execute_result" } ], "source": [ "class, quarter, year = tup\n", "\"Year: $year, Quarter: $quarter, Class: $class\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may also create **named tuples** and merge them:" ] }, { "cell_type": "code", "execution_count": 150, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(q1 = \"Fall\", q2 = \"Winter\", q3 = \"Spring\")" ] }, "execution_count": 150, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tup3 = (q1 = \"Fall\", )\n", "tup4 = (q2 = \"Winter\", q3 = \"Spring\")\n", "tup5 = merge(tup3, tup4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that to define a tuple with only one entry, we still need to include a comma with nothing to its right in the declaration." ] } ], "metadata": { "kernelspec": { "display_name": "Julia 1.5.4", "language": "julia", "name": "julia-1.5" }, "language_info": { "file_extension": ".jl", "mimetype": "application/julia", "name": "julia", "version": "1.5.4" }, "toc": { "base_numbering": 1, "nav_menu": { "height": "171.989px", "width": "198.991px" }, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }