1
0
Fork 0
mirror of https://gitlab.rlp.net/mobitar/julia_course.git synced 2024-09-14 12:47:20 +00:00
Julia_Course/day-1/main.jl
2024-05-15 02:54:36 +02:00

1646 lines
47 KiB
Julia
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

### A Pluto.jl notebook ###
# v0.19.42
using Markdown
using InteractiveUtils
# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
quote
local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
local el = $(esc(element))
global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
el
end
end
# ╔═╡ 56ca47c1-6e4d-48a2-9f55-ca89362c7d3f
# Import packages and export their (public) functions
using Measurements, Unitful
# ╔═╡ 1f347724-1db2-48f0-87df-4e63ad6e8820
# Importing a builtin library that provides more functions for linear algebra.
# The keyword `using` imports the package and exports (public) functions automatically.
using LinearAlgebra
# ╔═╡ d1a4ef8b-8e7d-4d34-80d8-cee195e237ae
# Oh, no, you found my secret! 😱
# Don't change this hidden cell!
begin
using PlutoUI
TableOfContents()
end
# ╔═╡ 2c5e32f4-1d7d-4494-b025-a90d17919756
md"""
# Introduction
"""
# ╔═╡ 21590bf1-1e1c-46b4-a2b6-7eb915e121ab
md"""
## Why Julia?
- ⚡ Need for speed
- Dynamic and interactive, yet **fast**!
- JIT: Just in time compiler
- Solution to the "2 language problem"
- 🔬 Focus on scientific and numerical programming
- Arrays (vectors, matrices, tensors) out of the box
- Awesome packages!
- 📃 Easy syntax
- 🧐 Readable code
- 🧩 Modern package manager with environments out of the box
- 🔀 Parallelism and distributed computation
- 💻 "Julia is written in Julia"
- `@` Metaprogramming (macros)
- 🔓 Free open source software
- 😉 Unicode support
"""
# ╔═╡ d04af0fd-5ced-4f4f-b157-dd170e2ef8c8
md"""
## Pluto notebooks
- ⌨️ Press **`F1`** to see the full list of **shortcuts**.
- ▶️ Most important shortcut: `Shift` + `Enter` to run a cell.
- 📚️ Take a look at the **live docs** to the right.
"""
# ╔═╡ 938adcfe-8d1b-4c77-8d82-c48415f5673e
md"""
## Calculation
You can use Julia as a calculator 🧮
"""
# ╔═╡ 73190799-fd03-4cc4-9b4e-c523bc310468
1 + 1
# ╔═╡ 4c242a67-6445-48e7-a6c3-418a489b89ba
3 - 1
# ╔═╡ fe70db85-6e68-48ee-9b9a-7072e2dd7fe3
2 * 2
# ╔═╡ a73c132f-fd81-49ae-afc8-29e08a9042c8
3^4
# ╔═╡ 7671c5cb-9265-479d-b782-195bad6b7ba7
# ⚠️ Different from Python! This gives a helpful error:
# 3 ** 4
# ╔═╡ 3f2c4ab8-4ba4-44d5-99d4-9d941e4df99e
5 / 2
# ╔═╡ 02282f61-e1ca-483d-b6de-feeccedd7bc0
# Remainder of division
5 % 2
# ╔═╡ e4237ccd-b042-408b-8177-4c0d31a28caa
# Quotient of division
5 ÷ 2
# ╔═╡ 0dc9bbb4-fdde-4006-b04d-4509f7d041a7
3^2 * 2 - 8
# ╔═╡ 9c837673-79dd-4a6f-a11d-6f0f2c001587
3^2 * (2 - 8)
# ╔═╡ 0b6c6d50-e24c-43c7-8f04-4a53a3309bbf
md"""
Compare the results of the last two cells.
The followed operation priority is the same as in math (multiplication before addition/subtraction and so on). Use brackets to make sure that you get the result you want!
"""
# ╔═╡ d1bf37f9-5135-48b8-8f9b-84ddd4a86157
md"""
## Variables
Variables store data 📦️
"""
# ╔═╡ 8d005ddd-0308-4a06-8bae-251387facf6f
# Assignment
a = 2
# ╔═╡ b7d27cd4-a655-492e-b2b3-cdc745b2c2da
b = 3
# ╔═╡ 141950e5-e9f8-414b-b08d-86777428cbec
# Change a or b above and see what happens 🪄
a * b
# ╔═╡ 2e7f29ce-3afa-4c12-838d-8051c0567e20
# You can also store the result of a computation
c = a + b
# ╔═╡ 4936c9fc-43da-4b8b-84ce-11e739802e07
# You can also use variables with long names, but make sure to connect the words with an underscore (_)
variable_with_a_long_name = 42
# ╔═╡ 5e7f8a5e-9354-442b-aa13-7b9b3de536b1
md"""
There is a useful syntax to update the value of a variable using an operator acting on the variable itself.
"""
# ╔═╡ cf08cc65-7a9e-490d-b7e6-eecf6a1d9977
md"""
From now on, blocks will be used sometimes when manipulating a variable to prevent dependency on execution order in the notebooks.
A block starts with `begin` and ends with `end`. Code in the block should be indented.
The output of a cell with a block is the output of the last line of this block.
"""
# ╔═╡ 4774fa16-a6f6-48ae-b9b6-8a279118c99a
begin
incr_var = 1
incr_var += 1
# Equivalent to the following:
# incr_var = incr_var + 1
incr_var
end
# ╔═╡ 30000e9f-ec3d-416a-b402-010da80cd9ea
md"""
This syntax can also be used for all other operators (`*`, `/`, `^`, etc.)
"""
# ╔═╡ 72daf832-dba6-49ad-8d5a-f2c3aecdb630
# Example with one more operator
begin
doppel_var = 5
doppel_var *= 2
doppel_var
end
# ╔═╡ 2121b949-06e7-4079-a25a-d0518ee2ba50
md"""
## Types
These are the most important primitive types:
- `Bool`
- `Char`
- `Float64`
- `Int64`
Most other types (like `String`) are composed.
*Spoiler: You can compose your own types! More about this later* 😉
"""
# ╔═╡ 534f3b32-1fc9-4eed-887a-2cac66c2bdb4
# Bool has only two possible values: `true` or `false`.
bo1 = true
# ╔═╡ 3894b6b5-1952-409a-9966-502c277e26c3
bo2 = false
# ╔═╡ f20de3db-f270-4c43-aab7-692c313b5fa9
# Char
# Single quotes!
ch = 'c'
# ╔═╡ c72f187f-9626-45d9-870a-267c8530202c
# String, not a char!
# Double quotes!
st1 = "c"
# ╔═╡ e4295349-fc5c-48cb-975e-803e44d1a06e
# Shows the type of a variable
typeof(ch)
# ╔═╡ 7287122b-e5ea-4f69-963b-023483914992
typeof(st1)
# ╔═╡ 8b6609b0-5d6d-4c7d-a144-deaff79f93e9
# A string is a chain of characters
hello = "Hello world!"
# ╔═╡ 196682db-f5e1-4c07-9d35-644da3eecdd6
md"""
Pluto notebooks automatically print the output of a cell.
When using scripts instead of notebooks, `println` is needed to print to the console / terminal.
"""
# ╔═╡ 10fdb32f-b66f-4c4e-abd9-e856549941b8
# Print to the console
# ln stands for new line which is printed at the end of the output
println(hello)
# ╔═╡ 00ba151b-a741-448d-b8bf-775217250915
# Float
fl = 42.0
# ╔═╡ 204cf77f-bf37-4110-9c9f-1f9236301ba9
# Float64 is the default
typeof(fl)
# ╔═╡ 750bba32-e695-48f1-af70-70c94d13366b
# Integer
meaning_of_life = 42
# ╔═╡ 0b663bcb-4ff4-4597-b28b-b58c9cbfa181
# Int64 is the default
typeof(meaning_of_life)
# ╔═╡ 5e45b854-c173-452b-b62b-54037a3780fd
md"""
## String operations
"""
# ╔═╡ 0596fe87-4201-476e-8e11-618c621c5474
# Concatenation
# ⚠️ Not +
"Hello " * "world!"
# ╔═╡ 28063282-5c60-4ffb-a715-9b1e88498df9
new_to_julia = "Hi, I am new to Julia!"
# ╔═╡ da5fb1f9-2a2d-4148-8ba5-8c4a529829e9
# check if a string is part of another one
# ⚠️ Not in
contains(new_to_julia, "Hi")
# ╔═╡ 943da836-384d-4774-aaf4-54c27feb53d8
# Split on occurrences of the provided delimiter (comma here)
split(new_to_julia, ",")
# ╔═╡ a96f3ae9-12df-4df8-85da-09b9b1e47de1
# Join a list of strings with a provided delimiter and last delimiter
# Some of the used arguments are optional, see the docs 📚️
# Lists are actually called vectors in Julia. More about this later!
join(["Apple", "Banana", "Orange", "Lemon"], ", ", " and ")
# ╔═╡ 8d106ad2-5f92-4138-bfff-56ee21e098fa
# Multi line strings with three double quotes
multi_line_string = """Line 1
Line 2
Line 3"""
# ╔═╡ f8bc4051-93c6-4376-abaa-7b4cb4b8f607
# To see the new lines (\n)
println(multi_line_string)
# ╔═╡ b25dc5f2-e186-4da1-b045-47b22c93799b
md"""
## String formatting
"""
# ╔═╡ e0d7fbc8-39fc-4b70-9b92-0c19fffb0c05
a
# ╔═╡ 398648e8-358e-4289-ae95-957e77d0c46f
b
# ╔═╡ 28fa32e7-4e50-4890-a765-5cfb1d3f791b
a_mult_b = a * b
# ╔═╡ d2607457-1794-4a0f-af41-cb80aadb598f
# Use $ followed by the name of a variable to insert the variable into a string
"The result of $a * $b is $a_mult_b"
# ╔═╡ 23dbbe13-d997-4f9f-a300-7cb78c4fb8ee
# Use brackets after $ to insert a result of computation instead of a variable
"The result of $a * $b is $(a * b)"
# ╔═╡ e767971a-7e1d-4a78-88d7-03e4ae4d51db
# Using the macro @show, helpful for usage in scripts
@show a * b
# ╔═╡ 1e7b103c-6cc9-4586-820b-9ec836b997da
md"""
### Why even string formatting?
The following is an example of a possible calculation in a physical context.
"""
# ╔═╡ 7ade3f89-4838-4a8b-815c-4e2d6ccd7fea
# Voltage
U1 = 12.0 # V
# ╔═╡ 35675b9b-a28a-427f-9da4-e6c756d2276a
# Voltage uncertainty
dU1 = 0.1 # V
# ╔═╡ 66d39465-8244-483f-9a82-8d17b95cf41d
# Current
I1 = 0.30 # mA
# ╔═╡ 879c5330-781f-44c2-b072-1ee0f9bd971d
# Current uncertainty
dI1 = 0.01 # mA
# ╔═╡ df5914e3-b250-4824-80a5-cac5d0bed084
# Resistance
R1 = U1 / I1 # kΩ
# ╔═╡ 099ac8f8-8c5c-410b-a11f-c98bc68230b2
# Resistance uncertainty calculated with the Gaussian propagation of uncertainty.
dR1 = R1 * ((dU1 / U1)^2 + (dI1 / I1)^2)^0.5 # kΩ
# ╔═╡ cd46845b-4980-465c-a64f-3a8bcb66f53e
# You can get the ± symbol by typing \pm and then pressing tab.
println("""U: $U1 ± $dU1 V
I: $I1 ± $dI1 mA
R: $R1 ± $(round(dR1; digits=2))""") # We will get to rounding later
# ╔═╡ a0bd2da0-344d-470c-918e-e8760fc77355
md"""
Nice, we were able to generate a nice output 🤩
But wait, Julia can automatically handle physical units and propagation of uncertainty for us! 🙀
"""
# ╔═╡ a2c4c4d9-4f06-41d4-baeb-b5f9f3b5b7c3
md"""
## Measurements and units
"""
# ╔═╡ f4122e58-a30c-45a4-8ede-492ddb8deba4
U2 = (12.0 ± 0.1)u"V"
# ╔═╡ 949e7fb8-8eff-49ea-8e76-0306857b05b9
I2 = (0.30 ± 0.01)u"mA"
# ╔═╡ 26869678-32f0-46e8-8cb2-d45b84441f03
R2 = U2 / I2
# ╔═╡ 0121add2-b42b-4dcd-8912-f8420a8b4c72
R2_converted = uconvert(u"", R2)
# ╔═╡ 9df364d6-0f43-4fe3-8a10-4bf0dc79e04d
md"""
Magic 🪄
"""
# ╔═╡ b8d7bd0b-a0ea-499f-9e61-3875535887e9
md"""
## Functions
In the last example, we did calculate the resistance. The resistance is a function of two variables: `I` and `U`.
In physics or mathematics, you would write this function this way:
$R(U, I) = U / I$
Guess what: In Julia, you can just write the same thing and you get a function!
"""
# ╔═╡ 13dd1d3c-dec8-4871-8ffa-b3db1bdd2847
# Function definition
R(U, I) = U / I
# ╔═╡ 0078ea9a-9c94-4703-a878-3cdd2e11d625
md"""
Now, you can call the function with some arguments.
"""
# ╔═╡ 38d3105f-427b-427b-bf7b-8aa76dfb3bef
R(12.0, 0.30)
# ╔═╡ 41b17c21-5b57-4912-88ee-e33215c1e0c8
# You can also pass units and uncertainties, Julia will just handle them.
# You can store the result in a new variable.
R3 = R((12.0 ± 0.1)u"V", (0.30 ± 0.01)u"mA")
# ╔═╡ b6dcaf22-c075-442e-b0d0-e48eae2350ac
# Now convert the result
uconvert(u"", R3)
# ╔═╡ 7f01c4a5-0e56-43aa-8d14-5fecfa04b370
md"""
OK, I guess you are asking what the benefit is. Why functions? You can just write `U / I`, right? 🤔
It was just a demonstration! Functions are more useful when you have a long calculation.
Lets write a function that does more than one thing. We want to calculate and show the results in a nice way.
Function with more than one line start with the keyword `function` and end with `end`. After `function` the name of the function and the arguments follow.
Everything inbetween should be indented (with tab). The result has to be returned with `return`.
"""
# ╔═╡ 105362be-572c-4a4d-9163-15ed8b4f1fbf
function calc_and_print_R(U, I)
@show U
@show I
R = U / I
R = uconvert(u"", R)
@show R
return R
end
# ╔═╡ 18c2ffb9-a895-491b-96ee-a0b5c68da180
# Test the function
calc_and_print_R(U2, I2)
# ╔═╡ 62cdf927-4e2b-40bb-be2d-eb32e0789548
md"""
Now, every time you want to calculate a resistance, you just use this function and it calculates and outputs for you 😃
"""
# ╔═╡ 9847a224-701a-489a-b125-95158aa805d4
# Take a look at this function doing some random calculation
function complex_function(a, b, c, d)
result = a + b
result = result * c
result = result / d
return result
end
# ╔═╡ 21163504-972d-4362-8c57-dbd708b2fa04
complex_function(1, 2, 3, 4)
# ╔═╡ 9ef91243-04fc-44f2-ae69-76f372364f21
# Try to access the variable `result`
# result
# ╔═╡ 3df766f0-38cb-4cdf-a68f-a4771c78fe31
md"""
Why can't we access the variable that we did define and use in the function? 😢
It is because of the concept of *scopes*. The variable result is only defined inside the function and it is only accessible inside of this function (in the scope of the function), not outside it!
`result` is called an *internal* variable. When you define a variable outside a function, it is called a *global* variable and is accessible everywhere.
"""
# ╔═╡ a6d882a0-c80e-4acf-b05b-c0ae120d698d
md"""
We will get back to data analysis. But first, we have to dive a bit deeper into the language 🤿
"""
# ╔═╡ 944e2d37-8280-47b8-b874-97221955d048
md"""
## Type hierarchy
Julia does have abstract types which are helpful for multiple dispatch.
More about multiple dispatch later 😉
"""
# ╔═╡ 23d4ac67-05ec-4b3d-8368-86256076be62
# The type hierarchy of Int64
supertypes(Int64)
# ╔═╡ e8d7de2f-7c7e-47cb-9364-27d583652167
md"""
All types showed in the output of the above cell except `Int64` are abstract.
This means that you can not have a variable with an abstract type.
You can only derive from an abstract type, but more about this when discussing structs and multiple dispatch 😉
`Any` is the abstract type of everything.
"""
# ╔═╡ 866edf5e-a76c-448d-98e8-925eaed5eba5
# A number can either be real or complex
subtypes(Number)
# ╔═╡ a8ea4ac1-7f62-4485-a8c5-8ccf00c45720
# There are some types of real numbers.
subtypes(Real)
# ╔═╡ 786a96be-16cd-4f1b-9b5f-138e232d3183
# Integers can have a sign or no sign (only positive).
# A Bool is also treated as an integer with the value 0 or 1.
subtypes(Integer)
# ╔═╡ dd8dad86-6bc2-4489-8469-7eac80fc41bb
# Integers can have different number of bits.
subtypes(Signed)
# ╔═╡ fac04aa7-28e9-4f93-9312-a8f8f93c0877
# Minimum and maximum value of a type
typemin(Int8), typemax(Int8)
# ╔═╡ 86bc0ff0-b6bf-4700-a741-36323be58391
typemin(Int128), typemax(Int128)
# ╔═╡ ef35a3a7-c1df-4952-aa41-1ed22d7f3981
# BigInt does not have a minimum or maximum!
BigInt(10)^1000 + 1
# ╔═╡ c336d5f6-80ee-4994-a55f-2d6b3aa3d559
# Hierarchy of Float64
supertypes(Float64)
# ╔═╡ 608d4433-6e68-4f95-8581-437234b58e87
md"""
## Conversion
You can convert some types to others if it is possible.
"""
# ╔═╡ beadbfd3-0015-449a-b6e7-b5182b396c1d
# Converting a float to an integer
convert(Int64, 3.0)
# ╔═╡ 552fafa4-fad5-4efe-895f-255b3ec5c858
# Complex is a composed type for complex numbers
convert(Complex, 3.0)
# ╔═╡ d11fde7f-3238-4013-bd2d-546aab0d9f9c
# This does not work! See rounding below.
# convert(Int64, 3.2)
# ╔═╡ 036a2c43-dbc9-487c-96aa-94324eeb4a52
md"""
## Rounding
"""
# ╔═╡ 1e954726-254e-41bb-a62f-17bdc9884bee
# We have to tell Julia explicitly what to do when converting a float with non zero digits after the decimal point.
round(Int64, 3.2)
# ╔═╡ d74f6c46-f5a8-4720-bcaf-936f1508efda
# The default is rounding to 0 digits after the decimal points, but keeping the float type.
round(π)
# ╔═╡ 3e5daca6-5aa8-42bf-988b-c09fb17388df
# ; marks the start of keyword arguments. More about it later!
round(π; digits=2)
# ╔═╡ 7ff20c67-58d5-4095-bb8e-7ab7522791c7
# You can provide a rounding mode, see the docs!
round(π, RoundUp)
# ╔═╡ 3102810f-3467-4ed8-86c0-16e9177fa69d
md"""
## `for` loop
You might be asking your self, why even bother learning a programming language when you can just use a calculator 🤨
One very important aspect of computers is their ability to do a computation for many times, without getting tired or missing a step 😴
To use this ability, programming languages provide `for` and `while` loops.
In a `for` loop, Julia iterates over every element of a given collection and does a specific computation with this element.
Lets see some examples!
"""
# ╔═╡ c1c705d2-7e46-4811-9fb1-6b88b5a4140e
# This for loop iterates over the numbers 1, 2, 3 and 4 and prints them.
for i in 1:4
println(i)
end
# ╔═╡ ddd3c019-6e70-4714-88fe-07d7a006ebc6
# This loop iterates over some strings and prints a welcoming message.
for name in ["Alice", "Bob", "everyone"]
println("Hello $name, welcome to this Julia course!")
end
# ╔═╡ 05db4e85-857d-4056-a576-5de992eabf29
md"""
Now, let's make our function for calculating and printing resistance more useful!
We want to iterate over some measured values of voltage and current.
To do so, we pair each element of one vector (list of measurements) with the corresponding element of the second vector.
*Vectors will be explained later. Until then, it is enough to understand a vector as an ordered list of elements.*
Lets take a look!
"""
# ╔═╡ 85c3c314-0f66-41be-8398-a5f9149ddfbd
# Vector of measured voltage values to different resistances
# The point is important, it will be explained later!
measured_U = [12.0, 15.0, 16.0, 12.5, 23.2, 22.6] .* u"V" 0.1u"V"
# ╔═╡ 566553a0-0202-4b59-b3ef-6954bf946b79
# Vector of measured current values to the different resistances
measured_I = [0.30, 0.25, 0.13, 0.22, 0.15, 0.75] .* u"mA" 0.05u"mA"
# ╔═╡ b70a48ca-362c-40d6-b703-2553a0b01275
for (u, i) in zip(measured_U, measured_I)
calc_and_print_R(u, i)
println("---") # Separate output
end
# ╔═╡ c0b32101-5863-4c22-8ee5-8e29abe0da39
md"""
Now imagine that you have not only 6 measurements, but 1000 or more. How much time would you need with the calculator? ⏳️
Later, we will learn how to plot and further analyze calculated values!
"""
# ╔═╡ 00456b15-5d1c-4c74-a875-31ff9c8e1789
md"""
## `while` loop
A `while` loop is similar to a `for` loop. The loop does the same computation with different values over and over. Instead of going through elements of a vector, a `while` loop checks a condition and runs the computation until the condition is `false`.
Lets see the following example!
"""
# ╔═╡ 91c4c623-5680-4b35-a694-2bd2612def94
begin
value = 5
while value > 0
value -= 1
println(value)
end
end
# ╔═╡ 4a00035f-a1d1-409f-b73b-07f9073dc9d5
md"""
## Boolean operators
Boolean operators are especially needed to check conditions, for `while`, `if` or `elseif`.
"""
# ╔═╡ d4ebb324-fa31-4058-9da1-35e07a971106
# Boolean AND
true && false
# ╔═╡ f8259580-5a29-4a13-811f-c91d6811a291
# Boolean OR
true || false
# ╔═╡ f813afd8-2e1b-43f7-beeb-ac9bd15fbeb6
# Boolean NOT
!false
# ╔═╡ 7ab3a69d-ac31-49cf-8d34-3a427b02ed06
md"""
⚠️ Don't try to use `and`, `or` or `not` if you are coming from Python!
"""
# ╔═╡ 2a85d95b-51d2-4ea0-a2a2-43307a725f2a
md"""
## `if`, `elseif`, `else`
"""
# ╔═╡ eef07cd2-0a83-491f-a3ff-c51400aadebb
md"""
`if` checks for a condition and runs the code indented under it if the condition is `true`.
"""
# ╔═╡ 9a78bf14-7fb4-448a-a8dd-69e244a0a297
@bind test_value Slider(1:4)
# ╔═╡ a5a71d00-bf30-4c07-bcd8-2bf99698522e
test_value
# ╔═╡ 5281ef32-5de6-4488-8430-e5652cbf8299
if test_value == 1
println("The value is 1")
end
# ╔═╡ 9107a95e-6ef5-465f-bd28-9a774f99f4ab
md"""
`else` runs a piece of code indented under it if the condition of `if` is `false`.
"""
# ╔═╡ eec41279-e038-4415-81b3-ad5d4c396011
# change the value of the variable `test_value` and see how the input changes
if test_value == 1
println("The value is 1")
else
println("The value is not 1")
end
# ╔═╡ 544368b2-3e39-41e7-97ea-e2bbf44a7749
md"""
`elseif` checks for further conditions if the conditions before it were `false`. If the condition is `true`, then the code indented under it is executed and `else` is ignored. Otherwise, the next `elseif` is checked or `else` is executed if no `elseif` is left.
Sounds complicated. It is best explained with an example.
"""
# ╔═╡ d2333817-e941-429b-b8e3-2ff07669096b
# change the value of the variable `test_value` and see how the input changes
if test_value == 1
println("The value is 1")
elseif test_value == 2
println("The value is 2")
elseif test_value == 3
println("The value is 3")
else
println("The value is not 1, 2 or 3")
end
# ╔═╡ be0ff87b-229a-433e-a49e-2f1ced5bb9aa
# You can combine conditions
if (test_value == 1) || (test_value == 2)
println("Value is 1 or 2")
end
# ╔═╡ 54d654cd-110f-4b1f-9578-109a80db4574
@bind second_test_value Slider(1:2)
# ╔═╡ 96803a1e-0779-4eab-b120-b5569a44ac7b
second_test_value
# ╔═╡ 5ab233d2-f360-4362-b1f8-3f3ae2a4fee1
# change the value of the variable `second_test_value` and see how the input changes
if (test_value == 1) && (second_test_value == 1)
println("Both values are 1")
end
# ╔═╡ 0d100501-de84-4a5c-beb7-8ff9e83c473d
# change the value of the variable `test_value` and see how the input changes
if !(test_value == 1)
println("Value is not 1")
end
# ╔═╡ 9e3f698d-e57b-46c2-98e0-157fa7b06ae6
md"""
# Arrays
An array is a **mutable ordered** collection of elements of the same type.
Arrays can have different dimensions.
An array with (`n × 1`) dimensions is called a vector, like in mathematics.
An array with (`n × n`) dimensions is called a matrix, also like in mathematics.
But arrays can also have other dimensions (`n₁ × n₂ × n₃ × ...`) with `nᵢ` as natural numbers.
"""
# ╔═╡ d1680205-a8eb-4ef6-ae4f-059e7a30f5c1
md"""
## Vectors
"""
# ╔═╡ b54ace0e-8947-46a3-842a-05b5cbfc4e87
first_vector = [2, 4, 6, 8, 10]
# ╔═╡ 0d5bfd45-79da-435b-9a98-8ed996bbc7b4
# Show the dimensions of an array
size(first_vector)
# ╔═╡ 8c47710f-1ed2-40fd-9290-374b498380e3
first_vector[1]
# ╔═╡ a03b46cc-1b26-44c2-b83d-884e3dbbe4fa
md"""
Yes, it is not the second element of the vector! 😯
In Julia, indexing starts with 1
"""
# ╔═╡ 68658408-188e-43f7-ad74-251172dec0a8
# ⚠️ This results in an error!
# first_vector[0]
# ╔═╡ 7c00f22c-860f-4bb1-b4b4-74c5c3c70f45
# Last element
first_vector[end]
# ╔═╡ 45b64c7a-850b-402c-b7ce-2a0bf6d77060
# ⚠️ No negative indexing!
# first_vector[-1]
# ╔═╡ d1ed1515-cd59-4e10-a15c-b64325bc44c2
# Instead, this can be used
first_vector[end-1]
# ╔═╡ 6c80e009-30de-4232-9a1b-ac954242a5a6
md"""
## Slicing
"""
# ╔═╡ b1426df5-a083-4977-a72c-81e03fd7719d
# Syntax: start_index:end_index
first_vector[2:4]
# ╔═╡ 5b16ca43-1f56-4934-a420-5ffa5ed437ec
# start_index:step:end_index
first_vector[1:2:end]
# ╔═╡ 628852dc-16e5-4a03-93a9-be209b1e8fb4
# Vector of indices
first_vector[[1, end, 2]]
# ╔═╡ 3ea54f0d-2aa5-47a3-bbc3-92023a56b834
md"""
## Mutation
"""
# ╔═╡ e9e117af-1194-4d64-94a8-3e9fd51498aa
# Setting the first element to 3
begin
second_vector = [1, 2, 3]
second_vector[1] = 42
second_vector
end
# ╔═╡ 1fd6fdd3-82a0-480e-9db6-e657536da63f
# Add elements to a vector
begin
growing_vector = []
push!(growing_vector, 42)
push!(growing_vector, 33)
growing_vector
end
# ╔═╡ ace6fd59-ccb8-4318-85ce-966b04c4ce53
# Append elements of one vector to another one
begin
growing_vector2 = [1, 2]
vector_to_append = [22, 33, 44]
append!(growing_vector2, vector_to_append)
growing_vector2
end
# ╔═╡ b7bb3e82-a2ee-4356-8c7b-0db664adcbe0
# Remove elements
begin
shrinking_vector = [-1, -2, -2, 55, 123, 44, 52, 98, -3, -112]
@show shrinking_vector
# Remove the last element
pop!(shrinking_vector)
@show shrinking_vector
# Remove the first element
popfirst!(shrinking_vector)
@show shrinking_vector
# Remove at a given index
popat!(shrinking_vector, 3)
@show shrinking_vector
end
# ╔═╡ 027313d6-c247-43e9-872b-c3f0fe71b733
third_vector = [1, 2, 3]
# ╔═╡ e77e7ceb-31e3-4231-9923-f62b1382a2d1
# ⚠️ This does not work!
# third_vector[2] = 42.1
# ╔═╡ 65d3ddc2-36ed-4126-9211-e838ffc0d859
# This is because the type of the array is Int64, a Float64 can not be inserted! All elements of an array have to have the same type!
typeof(third_vector)
# ╔═╡ 641e8c05-3e80-47e5-be77-91090a5f799a
# You can mix types during initialization of an array
begin
mixed_vector = ["hi", 2.1, 55.7]
mixed_vector[2] = 1 + 2im
mixed_vector
end
# ╔═╡ 2b9a5867-ca82-4a27-a700-bd0bd6c89bbe
# But then, the type of the array is Any
typeof(mixed_vector)
# ╔═╡ 87b43f26-7437-4ee9-9b83-5b21e86dd0c9
md"""
⚠️ Try to avoid using mixed arrays (type `Any`)!
It hurts the performance! 🐢
This is because the array can contain anything and the compiler can not optimize for specific types.
"""
# ╔═╡ 22f5ebc1-fd5c-4ee7-b169-8144fbd9b570
# ⚠️ This does not work! Run it and see the helpful error message
# first_vector[1:2] = 5
# ╔═╡ 7479c420-2e04-4fe7-823c-3fde9efb54ca
# Instead use this to change many slices in the original vector
first_vector[1:2] .= 5
# ╔═╡ 4cd82256-be63-4db1-b2af-82a1358f4881
# Compare the output of the cell above with this. What is the difference?
typeof(first_vector[1:2])
# ╔═╡ 605ee405-ec83-4064-adc8-861d95513e5e
md"""
## Views
Views are not a copy of an array, but a *reference* to a part of it. It is best explained by an example:
"""
# ╔═╡ 22a7baee-6533-43f7-8503-e5d5537a8c78
# Don't panic!
# You don't have to understand everything in this "long" piece of code.
# It is only meant for concept explanation.
# The output is important!
begin
v = [3, 6, 9, 12]
@show v
# Copy
@show copy_of_v = v[1:3]
# View
@show view_of_v = view(v, 1:3)
println() # Generate a new empty line
new_value = 100
v[1] = new_value
println("Changed first element of v to $new_value")
@show v
@show copy_of_v
@show view_of_v
println()
new_value = 42
copy_of_v[2] = new_value
println("Changed second element of copy_of_v to $new_value")
@show v
@show copy_of_v
@show view_of_v
println()
new_value = 55
view_of_v[3] = new_value
println("Changed third element of view_of_v to $new_value")
@show v
@show copy_of_v
@show view_of_v
end
# ╔═╡ 90b0fb2f-eb2d-4d06-96da-a4605ce61c41
md"""
Using views is important for performance. Copying or initializing an array is expensive!
This is because a free place in the memory has to be found and assigned to the new array. This process is called *memory allocation*. More about allocations and performance improvements in the days 😉
"""
# ╔═╡ 786682f6-692d-488d-8dab-231b0111d07f
md"""
## Vector operations
"""
# ╔═╡ 16a9cb53-2812-4ed3-afe4-96c0b116ad9a
v1 = [1, 2, 3]
# ╔═╡ dfd91d6b-65a5-454b-a0f9-6ed267def022
v2 = [0, 5, 10]
# ╔═╡ e68c54d8-3fb8-4aae-a334-665fdb8db1f0
v1 + v2
# ╔═╡ 8d74d994-3d4e-40ba-97cb-6dac1003fb8f
# Now we have access to the function `dot` (and many others)
# Dot product
dot(v1, v2)
# ╔═╡ af87251f-a37c-4088-8f4d-3803778bd97e
# Cross product
cross(v1, v2)
# ╔═╡ 2ac5d431-1a4d-4db2-8954-97e011cd2175
md"""
## Matrices
"""
# ╔═╡ d30b3a5f-e14c-45ea-89a4-cf710733a2ee
# Readable method to define a matrix
first_matrix = [
1 2
3 4
]
# ╔═╡ 6bb730e4-b5aa-4e7b-9ccd-9298db061e7f
# Easier to write method
second_matrix = [1 2; 3 4]
# ╔═╡ 2ef34862-0578-41fe-adad-0e894c287dd5
third_matrix = [
1 2 3
4 5 6
]
# ╔═╡ 09f2d0f9-cd0e-45e4-a159-cb360292dac1
# Dimensions: n × m
size(third_matrix)
# ╔═╡ 6f6a875e-fe60-47ba-8837-60edef1b20e0
# Determinant, from LinearAlgebra
det(first_matrix)
# ╔═╡ e99a89ab-af3a-42f5-b1c1-22e13a761eeb
# Inverse matrix, from LinearAlgebra
inv_first_matrix = inv(first_matrix)
# ╔═╡ f45b7774-df6f-4019-9217-e88d99babdb3
# Matrix multiplication
inv_first_matrix * first_matrix
# ╔═╡ db1b6e53-3116-48df-b098-1c3045be0dad
# Calculate eigenvalues and vectors, from LinearAlgebra
vals, vecs = eigen(first_matrix)
# ╔═╡ cd5abd71-1bf8-484f-a46a-99cc8b994b91
# Eigenvalues
vals
# ╔═╡ 7cef46dc-803a-4a7a-9663-148b6de4a267
# First eigenvector
vecs[:, 1]
# ╔═╡ 70710989-9139-4970-a7b0-5702571e59a4
# Second eigenvector
vecs[:, 2]
# ╔═╡ 873be989-d587-4d9f-ad5d-5632ae24b0bf
# Transpose a matrix
first_matrix'
# ╔═╡ a9f39e34-4c2c-48f2-9353-babe1bc3cd05
md"""
## More dimensions
One of the best ways to initialize arrays is to use `zeros`, `ones` or `fill` providing the dimensions.
After initialization, you can populate the array (inplace).
"""
# ╔═╡ 83eca43d-2280-40f1-bf2a-016a843362a3
# Tensor with the following dimensions: 3 × 3 × 3
begin
first_tensor = zeros(3, 3, 3)
first_tensor[1, 1, 1] = 1.0
first_tensor[2, :, :] .= 4.0 # The dot is important! (Remember views)
first_tensor
end
# ╔═╡ f4c48701-d90e-48d6-bf9d-539c7fb7c7a5
ones(3, 2)
# ╔═╡ 875cb2c2-e78d-41e3-808b-c6948f215b76
# Fill with a value other than 0 or 1
fill(42, (2, 2, 3))
# ╔═╡ 91cc92b5-0be7-4ddf-91d1-bf56506e899c
md"""
## Range
While using `for` loops, we used a syntax like the following:
for i in 1:4
The `1:4` is a range. You can think of it as a vector that does not store all values in memory, but only the start, end and step values.
To see what a range contains, you can convert it to a vector by *collecting* its elements using `collect`.
"""
# ╔═╡ c24f0bf2-0054-49f2-bffc-8b3e3ff6409b
# Does not show the elements explicitly
1:4
# ╔═╡ 800d4999-d7d7-4818-95e7-d93027f23c53
collect(1:4)
# ╔═╡ a790ba58-c369-49eb-8f00-fdb73bcaab6c
# Using a step different from 1
collect(1:2:10)
# ╔═╡ 28c9ef22-25b9-4640-bdd1-1b8dc7b33090
# Ranges of floats are also possible
collect(0.0:0.4:2.0)
# ╔═╡ 1c4c05d7-455f-4a47-88aa-cf84a323a663
# You can generate a range by providing the number of elements you want between start and end. The step is then calculated automatically.
# This will be helpful for plotting later
r = range(0.0, 2.0; length=5)
# ╔═╡ e8c26d42-f841-4966-8d9e-3f11e9334551
collect(r)
# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Measurements = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
[compat]
Measurements = "~2.11.0"
PlutoUI = "~0.7.59"
Unitful = "~1.19.1"
"""
# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised
julia_version = "1.10.3"
manifest_format = "2.0"
project_hash = "022676ff05294a4cf046ceb66a716a28bdcf6c6a"
[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "6e1d2a35f2f90a4bc7c2ed98079b2ba09c35b83a"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.3.2"
[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
version = "1.1.1"
[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
[[deps.Calculus]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad"
uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
version = "0.5.1"
[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.5"
[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
version = "1.1.1+0"
[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
[[deps.Downloads]]
deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
version = "1.6.0"
[[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
[[deps.FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.5"
[[deps.Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "179267cfa5e712760cd43dcae385d7ea90cc25a4"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.5"
[[deps.HypertextLiteral]]
deps = ["Tricks"]
git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.5"
[[deps.IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "8b72179abc660bfab5e28472e019392b97d0985c"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.4"
[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.4"
[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
version = "0.6.4"
[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
version = "8.4.0+0"
[[deps.LibGit2]]
deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
[[deps.LibGit2_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"]
uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5"
version = "1.6.4+0"
[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
version = "1.11.0+1"
[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
[[deps.LinearAlgebra]]
deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
[[deps.MIMEs]]
git-tree-sha1 = "65f28ad4b594aebe22157d6fac869786a255b7eb"
uuid = "6c6e2e6c-3030-632d-7369-2d6c69616d65"
version = "0.1.4"
[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
version = "2.28.2+1"
[[deps.Measurements]]
deps = ["Calculus", "LinearAlgebra", "Printf", "Requires"]
git-tree-sha1 = "bdcde8ec04ca84aef5b124a17684bf3b302de00e"
uuid = "eff96d63-e80a-5855-80a2-b1b0885c5ab7"
version = "2.11.0"
[deps.Measurements.extensions]
MeasurementsBaseTypeExt = "BaseType"
MeasurementsJunoExt = "Juno"
MeasurementsRecipesBaseExt = "RecipesBase"
MeasurementsSpecialFunctionsExt = "SpecialFunctions"
MeasurementsUnitfulExt = "Unitful"
[deps.Measurements.weakdeps]
BaseType = "7fbed51b-1ef5-4d67-9085-a4a9b26f478c"
Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d"
RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"
[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
version = "2023.1.10"
[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
version = "1.2.0"
[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
version = "0.3.23+4"
[[deps.Parsers]]
deps = ["Dates", "PrecompileTools", "UUIDs"]
git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.8.1"
[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
version = "1.10.0"
[[deps.PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "FixedPointNumbers", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "MIMEs", "Markdown", "Random", "Reexport", "URIs", "UUIDs"]
git-tree-sha1 = "ab55ee1510ad2af0ff674dbcced5e94921f867a9"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.59"
[[deps.PrecompileTools]]
deps = ["Preferences"]
git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f"
uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
version = "1.2.1"
[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.4.3"
[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
[[deps.Random]]
deps = ["SHA"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"
[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"
[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
version = "0.7.0"
[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
[[deps.SparseArrays]]
deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
version = "1.10.0"
[[deps.Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
version = "1.10.0"
[[deps.SuiteSparse_jll]]
deps = ["Artifacts", "Libdl", "libblastrampoline_jll"]
uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c"
version = "7.2.1+1"
[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
version = "1.0.3"
[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
version = "1.10.0"
[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
[[deps.Tricks]]
git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f"
uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775"
version = "0.1.8"
[[deps.URIs]]
git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.5.1"
[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
[[deps.Unitful]]
deps = ["Dates", "LinearAlgebra", "Random"]
git-tree-sha1 = "352edac1ad17e018186881b051960bfca78a075a"
uuid = "1986cc42-f94f-5a68-af5c-568840ba703d"
version = "1.19.1"
[deps.Unitful.extensions]
ConstructionBaseUnitfulExt = "ConstructionBase"
InverseFunctionsUnitfulExt = "InverseFunctions"
[deps.Unitful.weakdeps]
ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9"
InverseFunctions = "3587e190-3f89-42d0-90ee-14403ec27112"
[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
version = "1.2.13+1"
[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
version = "5.8.0+1"
[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
version = "1.52.0+1"
[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
version = "17.4.0+2"
"""
# ╔═╡ Cell order:
# ╟─2c5e32f4-1d7d-4494-b025-a90d17919756
# ╟─21590bf1-1e1c-46b4-a2b6-7eb915e121ab
# ╟─d04af0fd-5ced-4f4f-b157-dd170e2ef8c8
# ╟─938adcfe-8d1b-4c77-8d82-c48415f5673e
# ╠═73190799-fd03-4cc4-9b4e-c523bc310468
# ╠═4c242a67-6445-48e7-a6c3-418a489b89ba
# ╠═fe70db85-6e68-48ee-9b9a-7072e2dd7fe3
# ╠═a73c132f-fd81-49ae-afc8-29e08a9042c8
# ╠═7671c5cb-9265-479d-b782-195bad6b7ba7
# ╠═3f2c4ab8-4ba4-44d5-99d4-9d941e4df99e
# ╠═02282f61-e1ca-483d-b6de-feeccedd7bc0
# ╠═e4237ccd-b042-408b-8177-4c0d31a28caa
# ╠═0dc9bbb4-fdde-4006-b04d-4509f7d041a7
# ╠═9c837673-79dd-4a6f-a11d-6f0f2c001587
# ╟─0b6c6d50-e24c-43c7-8f04-4a53a3309bbf
# ╟─d1bf37f9-5135-48b8-8f9b-84ddd4a86157
# ╠═8d005ddd-0308-4a06-8bae-251387facf6f
# ╠═b7d27cd4-a655-492e-b2b3-cdc745b2c2da
# ╠═141950e5-e9f8-414b-b08d-86777428cbec
# ╠═2e7f29ce-3afa-4c12-838d-8051c0567e20
# ╠═4936c9fc-43da-4b8b-84ce-11e739802e07
# ╟─5e7f8a5e-9354-442b-aa13-7b9b3de536b1
# ╟─cf08cc65-7a9e-490d-b7e6-eecf6a1d9977
# ╠═4774fa16-a6f6-48ae-b9b6-8a279118c99a
# ╟─30000e9f-ec3d-416a-b402-010da80cd9ea
# ╠═72daf832-dba6-49ad-8d5a-f2c3aecdb630
# ╟─2121b949-06e7-4079-a25a-d0518ee2ba50
# ╠═534f3b32-1fc9-4eed-887a-2cac66c2bdb4
# ╠═3894b6b5-1952-409a-9966-502c277e26c3
# ╠═f20de3db-f270-4c43-aab7-692c313b5fa9
# ╠═c72f187f-9626-45d9-870a-267c8530202c
# ╠═e4295349-fc5c-48cb-975e-803e44d1a06e
# ╠═7287122b-e5ea-4f69-963b-023483914992
# ╠═8b6609b0-5d6d-4c7d-a144-deaff79f93e9
# ╟─196682db-f5e1-4c07-9d35-644da3eecdd6
# ╠═10fdb32f-b66f-4c4e-abd9-e856549941b8
# ╠═00ba151b-a741-448d-b8bf-775217250915
# ╠═204cf77f-bf37-4110-9c9f-1f9236301ba9
# ╠═750bba32-e695-48f1-af70-70c94d13366b
# ╠═0b663bcb-4ff4-4597-b28b-b58c9cbfa181
# ╟─5e45b854-c173-452b-b62b-54037a3780fd
# ╠═0596fe87-4201-476e-8e11-618c621c5474
# ╠═28063282-5c60-4ffb-a715-9b1e88498df9
# ╠═da5fb1f9-2a2d-4148-8ba5-8c4a529829e9
# ╠═943da836-384d-4774-aaf4-54c27feb53d8
# ╠═a96f3ae9-12df-4df8-85da-09b9b1e47de1
# ╠═8d106ad2-5f92-4138-bfff-56ee21e098fa
# ╠═f8bc4051-93c6-4376-abaa-7b4cb4b8f607
# ╟─b25dc5f2-e186-4da1-b045-47b22c93799b
# ╠═e0d7fbc8-39fc-4b70-9b92-0c19fffb0c05
# ╠═398648e8-358e-4289-ae95-957e77d0c46f
# ╠═28fa32e7-4e50-4890-a765-5cfb1d3f791b
# ╠═d2607457-1794-4a0f-af41-cb80aadb598f
# ╠═23dbbe13-d997-4f9f-a300-7cb78c4fb8ee
# ╠═e767971a-7e1d-4a78-88d7-03e4ae4d51db
# ╟─1e7b103c-6cc9-4586-820b-9ec836b997da
# ╠═7ade3f89-4838-4a8b-815c-4e2d6ccd7fea
# ╠═35675b9b-a28a-427f-9da4-e6c756d2276a
# ╠═66d39465-8244-483f-9a82-8d17b95cf41d
# ╠═879c5330-781f-44c2-b072-1ee0f9bd971d
# ╠═df5914e3-b250-4824-80a5-cac5d0bed084
# ╠═099ac8f8-8c5c-410b-a11f-c98bc68230b2
# ╠═cd46845b-4980-465c-a64f-3a8bcb66f53e
# ╟─a0bd2da0-344d-470c-918e-e8760fc77355
# ╟─a2c4c4d9-4f06-41d4-baeb-b5f9f3b5b7c3
# ╠═56ca47c1-6e4d-48a2-9f55-ca89362c7d3f
# ╠═f4122e58-a30c-45a4-8ede-492ddb8deba4
# ╠═949e7fb8-8eff-49ea-8e76-0306857b05b9
# ╠═26869678-32f0-46e8-8cb2-d45b84441f03
# ╠═0121add2-b42b-4dcd-8912-f8420a8b4c72
# ╟─9df364d6-0f43-4fe3-8a10-4bf0dc79e04d
# ╟─b8d7bd0b-a0ea-499f-9e61-3875535887e9
# ╠═13dd1d3c-dec8-4871-8ffa-b3db1bdd2847
# ╟─0078ea9a-9c94-4703-a878-3cdd2e11d625
# ╠═38d3105f-427b-427b-bf7b-8aa76dfb3bef
# ╠═41b17c21-5b57-4912-88ee-e33215c1e0c8
# ╠═b6dcaf22-c075-442e-b0d0-e48eae2350ac
# ╟─7f01c4a5-0e56-43aa-8d14-5fecfa04b370
# ╠═105362be-572c-4a4d-9163-15ed8b4f1fbf
# ╠═18c2ffb9-a895-491b-96ee-a0b5c68da180
# ╟─62cdf927-4e2b-40bb-be2d-eb32e0789548
# ╠═9847a224-701a-489a-b125-95158aa805d4
# ╠═21163504-972d-4362-8c57-dbd708b2fa04
# ╠═9ef91243-04fc-44f2-ae69-76f372364f21
# ╟─3df766f0-38cb-4cdf-a68f-a4771c78fe31
# ╟─a6d882a0-c80e-4acf-b05b-c0ae120d698d
# ╟─944e2d37-8280-47b8-b874-97221955d048
# ╠═23d4ac67-05ec-4b3d-8368-86256076be62
# ╟─e8d7de2f-7c7e-47cb-9364-27d583652167
# ╠═866edf5e-a76c-448d-98e8-925eaed5eba5
# ╠═a8ea4ac1-7f62-4485-a8c5-8ccf00c45720
# ╠═786a96be-16cd-4f1b-9b5f-138e232d3183
# ╠═dd8dad86-6bc2-4489-8469-7eac80fc41bb
# ╠═fac04aa7-28e9-4f93-9312-a8f8f93c0877
# ╠═86bc0ff0-b6bf-4700-a741-36323be58391
# ╠═ef35a3a7-c1df-4952-aa41-1ed22d7f3981
# ╠═c336d5f6-80ee-4994-a55f-2d6b3aa3d559
# ╟─608d4433-6e68-4f95-8581-437234b58e87
# ╠═beadbfd3-0015-449a-b6e7-b5182b396c1d
# ╠═552fafa4-fad5-4efe-895f-255b3ec5c858
# ╠═d11fde7f-3238-4013-bd2d-546aab0d9f9c
# ╟─036a2c43-dbc9-487c-96aa-94324eeb4a52
# ╠═1e954726-254e-41bb-a62f-17bdc9884bee
# ╠═d74f6c46-f5a8-4720-bcaf-936f1508efda
# ╠═3e5daca6-5aa8-42bf-988b-c09fb17388df
# ╠═7ff20c67-58d5-4095-bb8e-7ab7522791c7
# ╟─3102810f-3467-4ed8-86c0-16e9177fa69d
# ╠═c1c705d2-7e46-4811-9fb1-6b88b5a4140e
# ╠═ddd3c019-6e70-4714-88fe-07d7a006ebc6
# ╟─05db4e85-857d-4056-a576-5de992eabf29
# ╠═85c3c314-0f66-41be-8398-a5f9149ddfbd
# ╠═566553a0-0202-4b59-b3ef-6954bf946b79
# ╠═b70a48ca-362c-40d6-b703-2553a0b01275
# ╟─c0b32101-5863-4c22-8ee5-8e29abe0da39
# ╟─00456b15-5d1c-4c74-a875-31ff9c8e1789
# ╠═91c4c623-5680-4b35-a694-2bd2612def94
# ╟─4a00035f-a1d1-409f-b73b-07f9073dc9d5
# ╠═d4ebb324-fa31-4058-9da1-35e07a971106
# ╠═f8259580-5a29-4a13-811f-c91d6811a291
# ╠═f813afd8-2e1b-43f7-beeb-ac9bd15fbeb6
# ╟─7ab3a69d-ac31-49cf-8d34-3a427b02ed06
# ╟─2a85d95b-51d2-4ea0-a2a2-43307a725f2a
# ╟─eef07cd2-0a83-491f-a3ff-c51400aadebb
# ╠═a5a71d00-bf30-4c07-bcd8-2bf99698522e
# ╟─9a78bf14-7fb4-448a-a8dd-69e244a0a297
# ╠═5281ef32-5de6-4488-8430-e5652cbf8299
# ╟─9107a95e-6ef5-465f-bd28-9a774f99f4ab
# ╠═eec41279-e038-4415-81b3-ad5d4c396011
# ╟─544368b2-3e39-41e7-97ea-e2bbf44a7749
# ╠═d2333817-e941-429b-b8e3-2ff07669096b
# ╠═be0ff87b-229a-433e-a49e-2f1ced5bb9aa
# ╠═96803a1e-0779-4eab-b120-b5569a44ac7b
# ╟─54d654cd-110f-4b1f-9578-109a80db4574
# ╠═5ab233d2-f360-4362-b1f8-3f3ae2a4fee1
# ╠═0d100501-de84-4a5c-beb7-8ff9e83c473d
# ╟─9e3f698d-e57b-46c2-98e0-157fa7b06ae6
# ╟─d1680205-a8eb-4ef6-ae4f-059e7a30f5c1
# ╠═b54ace0e-8947-46a3-842a-05b5cbfc4e87
# ╠═0d5bfd45-79da-435b-9a98-8ed996bbc7b4
# ╠═8c47710f-1ed2-40fd-9290-374b498380e3
# ╟─a03b46cc-1b26-44c2-b83d-884e3dbbe4fa
# ╠═68658408-188e-43f7-ad74-251172dec0a8
# ╠═7c00f22c-860f-4bb1-b4b4-74c5c3c70f45
# ╠═45b64c7a-850b-402c-b7ce-2a0bf6d77060
# ╠═d1ed1515-cd59-4e10-a15c-b64325bc44c2
# ╟─6c80e009-30de-4232-9a1b-ac954242a5a6
# ╠═b1426df5-a083-4977-a72c-81e03fd7719d
# ╠═5b16ca43-1f56-4934-a420-5ffa5ed437ec
# ╠═628852dc-16e5-4a03-93a9-be209b1e8fb4
# ╟─3ea54f0d-2aa5-47a3-bbc3-92023a56b834
# ╠═e9e117af-1194-4d64-94a8-3e9fd51498aa
# ╠═1fd6fdd3-82a0-480e-9db6-e657536da63f
# ╠═ace6fd59-ccb8-4318-85ce-966b04c4ce53
# ╠═b7bb3e82-a2ee-4356-8c7b-0db664adcbe0
# ╠═027313d6-c247-43e9-872b-c3f0fe71b733
# ╠═e77e7ceb-31e3-4231-9923-f62b1382a2d1
# ╠═65d3ddc2-36ed-4126-9211-e838ffc0d859
# ╠═641e8c05-3e80-47e5-be77-91090a5f799a
# ╠═2b9a5867-ca82-4a27-a700-bd0bd6c89bbe
# ╟─87b43f26-7437-4ee9-9b83-5b21e86dd0c9
# ╠═22f5ebc1-fd5c-4ee7-b169-8144fbd9b570
# ╠═7479c420-2e04-4fe7-823c-3fde9efb54ca
# ╠═4cd82256-be63-4db1-b2af-82a1358f4881
# ╟─605ee405-ec83-4064-adc8-861d95513e5e
# ╠═22a7baee-6533-43f7-8503-e5d5537a8c78
# ╟─90b0fb2f-eb2d-4d06-96da-a4605ce61c41
# ╟─786682f6-692d-488d-8dab-231b0111d07f
# ╠═16a9cb53-2812-4ed3-afe4-96c0b116ad9a
# ╠═dfd91d6b-65a5-454b-a0f9-6ed267def022
# ╠═e68c54d8-3fb8-4aae-a334-665fdb8db1f0
# ╠═1f347724-1db2-48f0-87df-4e63ad6e8820
# ╠═8d74d994-3d4e-40ba-97cb-6dac1003fb8f
# ╠═af87251f-a37c-4088-8f4d-3803778bd97e
# ╟─2ac5d431-1a4d-4db2-8954-97e011cd2175
# ╠═d30b3a5f-e14c-45ea-89a4-cf710733a2ee
# ╠═6bb730e4-b5aa-4e7b-9ccd-9298db061e7f
# ╠═2ef34862-0578-41fe-adad-0e894c287dd5
# ╠═09f2d0f9-cd0e-45e4-a159-cb360292dac1
# ╠═6f6a875e-fe60-47ba-8837-60edef1b20e0
# ╠═e99a89ab-af3a-42f5-b1c1-22e13a761eeb
# ╠═f45b7774-df6f-4019-9217-e88d99babdb3
# ╠═db1b6e53-3116-48df-b098-1c3045be0dad
# ╠═cd5abd71-1bf8-484f-a46a-99cc8b994b91
# ╠═7cef46dc-803a-4a7a-9663-148b6de4a267
# ╠═70710989-9139-4970-a7b0-5702571e59a4
# ╠═873be989-d587-4d9f-ad5d-5632ae24b0bf
# ╟─a9f39e34-4c2c-48f2-9353-babe1bc3cd05
# ╠═83eca43d-2280-40f1-bf2a-016a843362a3
# ╠═f4c48701-d90e-48d6-bf9d-539c7fb7c7a5
# ╠═875cb2c2-e78d-41e3-808b-c6948f215b76
# ╟─91cc92b5-0be7-4ddf-91d1-bf56506e899c
# ╠═c24f0bf2-0054-49f2-bffc-8b3e3ff6409b
# ╠═800d4999-d7d7-4818-95e7-d93027f23c53
# ╠═a790ba58-c369-49eb-8f00-fdb73bcaab6c
# ╠═28c9ef22-25b9-4640-bdd1-1b8dc7b33090
# ╠═1c4c05d7-455f-4a47-88aa-cf84a323a663
# ╠═e8c26d42-f841-4966-8d9e-3f11e9334551
# ╟─d1a4ef8b-8e7d-4d34-80d8-cee195e237ae
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002