### A Pluto.jl notebook ### # v0.15.1 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 el = $(esc(element)) global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing el end end # ╔═╡ 82d96400-f12f-11ea-32a7-b13f7a39a164 md"# Notebook 1 -- Math 2121, Fall 2021 This is a *Pluto* notebook, using the *Julia* programming language. Julia is at the cutting edge of programming languages for scientific computing. It combines many of the best features of Matlab and Python but is also very fast. The language has a lot of built-in functions that will be useful for demonstrating concepts in Math 2121." # ╔═╡ 848b5f96-f13f-11ea-224d-bd698083fb43 md"## Installing Pluto (optional) Pluto is an interactive notebook for running Julia code. You can access this notebook as a static HTML page on our course website. But if you install Julia and Pluto on your home computer, then you can also modify and run the code here yourself. I can't improve upon the instructions at this link for installing both: " # ╔═╡ fc0c805e-f149-11ea-238f-11bce9959af8 md"## Running *this* Pluto notebook Once you have Pluto up and running, you can access the notebook you we are currently viewing by entering [this link](http://www.math.ust.hk/~emarberg/teaching/2021/Math2121/julia/01_Math2121_Fall2021.jl) (right click -> Copy Link) in the *Open from file* menu in Pluto. " # ╔═╡ 54072746-f140-11ea-0634-a1986f50bb7c md"## Working with matrices The syntax for working with matrices in Julia is much like Matlab. " # ╔═╡ dbd302d6-f11c-11ea-1893-afe7abeb02f7 # constructs a 3-by-5 matrix called Y Y = [1 2 3.1 0 6; 4 1 6 -1 8; 7 8 1 2 200] # ╔═╡ d8af9c8c-f184-11ea-1c46-5b47bc95d724 begin # you will need to install the PlutoUI package to run the cells below using PlutoUI md"""**Make it interactive** `row_index` = $(@bind row_index Slider(1:size(Y)[1], default=1, show_value=true)) `col_index` = $(@bind col_index Slider(1:size(Y)[2], default=1, show_value=true)) """ end # ╔═╡ 66c9bc2e-f12f-11ea-0bd8-49adae02f7f5 # access entries in a matrix Y[2, 5] # ╔═╡ 0c6d0568-f186-11ea-0a03-c35ca29dc8f9 # here is Y again Y # ╔═╡ a63dedb6-f185-11ea-0168-7352f3271c7b Y[row_index, col_index] # ╔═╡ 237d6364-f141-11ea-0955-832b084b95b1 # we can also set entries in a matrix Y[2, 4] = 60; # ╔═╡ 3b1e9592-f141-11ea-3630-1726d96f501e # this changes Y to be this matrix Y # ╔═╡ a5b43a64-f11f-11ea-05ce-731ffea11dac # create a submatrix, the slice notation is inclusive Y[:,3:end] # ╔═╡ 68cc01f0-f141-11ea-1b4d-5f7c81ed4fde Y[1:1,3:4] # ╔═╡ 7243bbe2-f141-11ea-2bba-f5311b588608 Y[1:3,4:4] # ╔═╡ 9637bf18-f11d-11ea-2218-9792fad48065 # we can get the dimensions of a matrix this way (m, n) = size(Y) # ╔═╡ a2ec4dba-f18a-11ea-28b9-1b7b73b0f247 # we can also create matrices with non-integer entries Z = [1.1 2.2 3 0; pi sqrt(5) exp(1) -1; 7 8 1 2] # ╔═╡ 0bf37516-f142-11ea-3660-65302f3191e4 md"Later in the course we will see many other operations involving matrices. Most of these will also be easily available in the Julia programming language." # ╔═╡ ff34739e-f127-11ea-0af5-758ee1a04e5d md"## Augmented matrices We can write our own functions to work with matrices. (This requires some programming background, however.) " # ╔═╡ 6fdab134-f142-11ea-1b7c-5915aa140601 md"The next cell implements a function called `print_linear_system` which takes a single input parameter. You can probably guess what it does. (To see the code, click the Show/Hide icon on the left.)" # ╔═╡ ea04185e-f11c-11ea-1263-d5d2f6682a53 begin function print_var(coeff, var) if coeff == 0 return "" elseif coeff == -1 return " - x_" * string(var) elseif coeff == 1 return " + x_" * string(var) elseif coeff > 0 return " + " * string(coeff) * " " * "x_" * string(var) elseif coeff < 0 return " - " * string(-coeff) * " " * "x_" * string(var) end end function print_linear_system(A) ans = [] (m, n) = size(A) for i = 1:m row = "" for j = 1:n - 1 row *= print_var(A[i, j], j) end row *= string(" = ", A[i, n]) if row[1:3] == " + " row = row[3:end] elseif row[1:3] == " - " row = "-" * row[4:end] elseif row[1:3] == " = " row = " 0" * row end push!(ans, row) end Text("\n" * join(ans, "\n\n") * "\n\n") end end # ╔═╡ 54e13b85-9dfd-4ea7-bc0f-be673ad1fa9a Y # ╔═╡ a4da23b0-f142-11ea-0756-31f99766f5ce # prints something that looks like the linear system whose augmented matrix is Y print_linear_system(Y) # ╔═╡ bfb32e84-f142-11ea-0322-812926bae95f # what happens if Y has only one column? print_linear_system(Y[1:3,4:4]) # ╔═╡ d68e9300-f142-11ea-2225-13540d43ac46 # how about two rows print_linear_system(Y[2:3,:]) # ╔═╡ f842b800-f142-11ea-19aa-0f05d3ab79aa md"Here's another function (code hidden) that returns **true** or **false** depending on whether a given list **s** is a solution to the linear system with augemented matrix **A**" # ╔═╡ cf0bb854-f130-11ea-28a9-130a925f809f function is_solution(A, s, tolerance=10e-16) (m, n) = size(A) w = A[1:m,1:n - 1] * s - A[1:m,n] transpose(w) * w < tolerance end # ╔═╡ 94f15410-f12d-11ea-2ef3-353b4bb7ecee # we saw this matrix in lecture T = [1 -2 1 0; 0 2 -8 8; 5 0 -5 10] # ╔═╡ 9485af3a-f12d-11ea-1e25-55a9a7f90437 print_linear_system(T) # ╔═╡ a6b241d8-f186-11ea-2b29-f1f29cdd1efb # T is row equivalent to this triangular matrix U = [1 -2 1 0; 0 1 -4 4; 0 0 1 -1] # ╔═╡ c4870f0e-f186-11ea-06c1-ab82ab6f779e print_linear_system(U) # ╔═╡ 6856e580-f143-11ea-2f0c-bbcc162ebc89 # finding a solution: # # x_3 = -1 so # x_2 = 4 + 4 x_3 = 4 - 4 = 0 so # x_1 = 2 x_2 - x_3 = 0 - (-1) = 1 is_solution(U, [1; 0; -1]) # ╔═╡ c0e2ab38-f186-11ea-3f48-1d3af52a9f15 # but this is also a solution to the linear system # with augmented matrix T: is_solution(T, [1; 0; -1]) # ╔═╡ 9b1be04c-f143-11ea-0ea0-2dcf67fbfae3 md"## Row operations A handy feature of these notebooks is that we can very easily explore different ranges of inputs and parameters. Let's try this out with our elementary row operations. " # ╔═╡ b40e415c-f121-11ea-31c5-755dde72021b # define some matrixx A = [1 2 3 -1; 0 0 0 -2; 3 8 12 0] # ╔═╡ ea985274-f123-11ea-06c3-f3ed2ca2ca56 # here's the linear system with A as augmented matrix print_linear_system(A) # ╔═╡ 5c121910-f144-11ea-3c90-a5e0d961bad4 md"Below are functions implementing our three row operations. Their syntax is: * `rowop_replace(A, i, j, v)`: adds `v` times row `i` in matrix `A` to row `j` * `rowop_scale(A, i, v)`: multiplies row `i` in matrix `A` by nonzero constant `v` * `rowop_swap(A, i, j)`: swaps rows `i` and `j` in matrix `A` Each function returns a new matrix without modifying the matrix A. " # ╔═╡ 11789eaa-f145-11ea-2715-df6c5768a6dc function rowop_replace(A, source_row, target_row, scalar_factor) @assert source_row != target_row A = copy(A) A[target_row,:] += A[source_row,:] * scalar_factor A end # ╔═╡ 4c9ec460-f12b-11ea-09ab-959ea5d7997f function rowop_scale(A, target_row, scalar_factor) @assert scalar_factor != 0 A = copy(A) A[target_row,:] *= scalar_factor A end # ╔═╡ 1cbabfdc-f145-11ea-0314-ed3f97ad7017 function rowop_swap(A, source_row, target_row) A = copy(A) A[target_row,:], A[source_row,:] = A[source_row,:], A[target_row,:] A end # ╔═╡ bb93d1a0-f12b-11ea-3e07-4d7e4cec63ba begin md"""**Another parameter** v = $(@bind v Slider(-30:30, default=1, show_value=true))""" end # ╔═╡ 23c6cafe-f12d-11ea-2e5b-890cf1fd62ef # our original matrix A # ╔═╡ 8a32bfdc-f12b-11ea-2d39-bb7824b518ab # add v * row 1 to row 3 rowop_replace(A, 1, 3, v) # ╔═╡ 3f327fc2-f146-11ea-0bd2-6f0ba231e808 # this row operation can be reversed rowop_replace(rowop_replace(A, 1, 3, v), 1, 3, -v) == A # ╔═╡ 52809ec4-f12d-11ea-3021-61f5bf8f270b rowop_scale(A, 3, v) # ╔═╡ 8552090a-f146-11ea-3e89-43c194ff9ac3 # also can be reversed rowop_scale(rowop_scale(A, 3, v), 3, 1/v) == A # ╔═╡ 1b8d386c-f12d-11ea-2939-d573716f7423 rowop_swap(A, 1, 3) # ╔═╡ b053aff0-f146-11ea-1d4e-f7041165f305 # doing this one twice undoes everything rowop_swap(rowop_swap(A, 1, 3), 1, 3) == A # ╔═╡ d330b6ee-f146-11ea-00a6-b146d6fced1a md"## Solving a linear system by row operations By applying a sequence of row operations, we can transform the augmented matrix of a linear system to a simpler matrix, whose associated system has the same solutions as the one we started with. " # ╔═╡ 2b5214ee-f12e-11ea-1c54-3deca60a18df M = [1 2 3 -1; 0 9 0 -2; 3 8 12 0] # ╔═╡ 4db3a5da-f12f-11ea-1baf-d7d445e201af print_linear_system(M) # ╔═╡ 2c113e02-f12e-11ea-0e56-6b5584a5902a B = rowop_replace(M, 1, 3, -3) # ╔═╡ 39a6bb80-f12e-11ea-23cb-2db569f39d1e C = rowop_replace(B, 3, 1, -1) # ╔═╡ 4ab3db38-f12e-11ea-1d2f-2f57ad49ece9 D = rowop_replace(C, 3, 2, -4) # ╔═╡ 65a70f70-f12e-11ea-2ea2-0d8746a828ca E = rowop_replace(D, 2, 3, -2) # ╔═╡ 41474e30-f12f-11ea-28ff-8fac3683a190 # we would get an error here # rowop_scale(E, 3, 1/27) # ╔═╡ 45ec716e-f147-11ea-2fbc-d13b48611d25 # need to cast the matrix E to be a matrix of floating point numbers F = float(E) # ╔═╡ 6efbf340-f12e-11ea-0d15-03932cd9beee G = rowop_scale(F, 3, 1/27) # ╔═╡ 0bbc8cf8-f12f-11ea-0331-9f6f70fa9b35 H = rowop_replace(G, 3, 2, 12) # ╔═╡ b25391b4-f130-11ea-39e4-c30e6ffefdce # our final matrix corresponds to a trivial linear system print_linear_system(H) # ╔═╡ 26ade640-f131-11ea-17cd-77fed9d9579d sol = H[1:3, 4] # ╔═╡ c43e12d4-f147-11ea-0f0a-ef9d1189e236 # this definitely should be a solution to the linear system of H is_solution(H, sol) # ╔═╡ 36e8908c-f131-11ea-2beb-d5df5ed675cf # as noted in class, it's also a solution to the linear system of M is_solution(M, sol) # ╔═╡ 00000000-0000-0000-0000-000000000001 PLUTO_PROJECT_TOML_CONTENTS = """ [deps] PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8" [compat] PlutoUI = "~0.7.9" """ # ╔═╡ 00000000-0000-0000-0000-000000000002 PLUTO_MANIFEST_TOML_CONTENTS = """ # This file is machine-generated - editing it directly is not advised [[Base64]] uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" [[Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" [[InteractiveUtils]] deps = ["Markdown"] uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" [[JSON]] deps = ["Dates", "Mmap", "Parsers", "Unicode"] git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37" uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" version = "0.21.2" [[Logging]] uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" [[Markdown]] deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" [[Parsers]] deps = ["Dates"] git-tree-sha1 = "438d35d2d95ae2c5e8780b330592b6de8494e779" uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" version = "2.0.3" [[PlutoUI]] deps = ["Base64", "Dates", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "Suppressor"] git-tree-sha1 = "44e225d5837e2a2345e69a1d1e01ac2443ff9fcb" uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8" version = "0.7.9" [[Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" [[Random]] deps = ["Serialization"] uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [[Reexport]] git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" uuid = "189a3867-3050-52da-a836-e630ba90ab69" version = "1.2.2" [[Serialization]] uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [[Suppressor]] git-tree-sha1 = "a819d77f31f83e5792a76081eee1ea6342ab8787" uuid = "fd094767-a336-5f1f-9728-57cf17d0bbfb" version = "0.2.0" [[Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" """ # ╔═╡ Cell order: # ╟─82d96400-f12f-11ea-32a7-b13f7a39a164 # ╟─848b5f96-f13f-11ea-224d-bd698083fb43 # ╟─fc0c805e-f149-11ea-238f-11bce9959af8 # ╟─54072746-f140-11ea-0634-a1986f50bb7c # ╠═dbd302d6-f11c-11ea-1893-afe7abeb02f7 # ╠═66c9bc2e-f12f-11ea-0bd8-49adae02f7f5 # ╟─d8af9c8c-f184-11ea-1c46-5b47bc95d724 # ╠═0c6d0568-f186-11ea-0a03-c35ca29dc8f9 # ╠═a63dedb6-f185-11ea-0168-7352f3271c7b # ╠═237d6364-f141-11ea-0955-832b084b95b1 # ╠═3b1e9592-f141-11ea-3630-1726d96f501e # ╠═a5b43a64-f11f-11ea-05ce-731ffea11dac # ╠═68cc01f0-f141-11ea-1b4d-5f7c81ed4fde # ╠═7243bbe2-f141-11ea-2bba-f5311b588608 # ╠═9637bf18-f11d-11ea-2218-9792fad48065 # ╠═a2ec4dba-f18a-11ea-28b9-1b7b73b0f247 # ╟─0bf37516-f142-11ea-3660-65302f3191e4 # ╟─ff34739e-f127-11ea-0af5-758ee1a04e5d # ╟─6fdab134-f142-11ea-1b7c-5915aa140601 # ╟─ea04185e-f11c-11ea-1263-d5d2f6682a53 # ╠═54e13b85-9dfd-4ea7-bc0f-be673ad1fa9a # ╠═a4da23b0-f142-11ea-0756-31f99766f5ce # ╠═bfb32e84-f142-11ea-0322-812926bae95f # ╠═d68e9300-f142-11ea-2225-13540d43ac46 # ╟─f842b800-f142-11ea-19aa-0f05d3ab79aa # ╟─cf0bb854-f130-11ea-28a9-130a925f809f # ╠═94f15410-f12d-11ea-2ef3-353b4bb7ecee # ╠═9485af3a-f12d-11ea-1e25-55a9a7f90437 # ╠═a6b241d8-f186-11ea-2b29-f1f29cdd1efb # ╠═c4870f0e-f186-11ea-06c1-ab82ab6f779e # ╠═6856e580-f143-11ea-2f0c-bbcc162ebc89 # ╠═c0e2ab38-f186-11ea-3f48-1d3af52a9f15 # ╟─9b1be04c-f143-11ea-0ea0-2dcf67fbfae3 # ╠═b40e415c-f121-11ea-31c5-755dde72021b # ╠═ea985274-f123-11ea-06c3-f3ed2ca2ca56 # ╟─5c121910-f144-11ea-3c90-a5e0d961bad4 # ╠═11789eaa-f145-11ea-2715-df6c5768a6dc # ╠═4c9ec460-f12b-11ea-09ab-959ea5d7997f # ╠═1cbabfdc-f145-11ea-0314-ed3f97ad7017 # ╟─bb93d1a0-f12b-11ea-3e07-4d7e4cec63ba # ╠═23c6cafe-f12d-11ea-2e5b-890cf1fd62ef # ╠═8a32bfdc-f12b-11ea-2d39-bb7824b518ab # ╠═3f327fc2-f146-11ea-0bd2-6f0ba231e808 # ╠═52809ec4-f12d-11ea-3021-61f5bf8f270b # ╠═8552090a-f146-11ea-3e89-43c194ff9ac3 # ╠═1b8d386c-f12d-11ea-2939-d573716f7423 # ╠═b053aff0-f146-11ea-1d4e-f7041165f305 # ╟─d330b6ee-f146-11ea-00a6-b146d6fced1a # ╠═2b5214ee-f12e-11ea-1c54-3deca60a18df # ╠═4db3a5da-f12f-11ea-1baf-d7d445e201af # ╠═2c113e02-f12e-11ea-0e56-6b5584a5902a # ╠═39a6bb80-f12e-11ea-23cb-2db569f39d1e # ╠═4ab3db38-f12e-11ea-1d2f-2f57ad49ece9 # ╠═65a70f70-f12e-11ea-2ea2-0d8746a828ca # ╠═41474e30-f12f-11ea-28ff-8fac3683a190 # ╠═45ec716e-f147-11ea-2fbc-d13b48611d25 # ╠═6efbf340-f12e-11ea-0d15-03932cd9beee # ╠═0bbc8cf8-f12f-11ea-0331-9f6f70fa9b35 # ╠═b25391b4-f130-11ea-39e4-c30e6ffefdce # ╠═26ade640-f131-11ea-17cd-77fed9d9579d # ╠═c43e12d4-f147-11ea-0f0a-ef9d1189e236 # ╠═36e8908c-f131-11ea-2beb-d5df5ed675cf # ╟─00000000-0000-0000-0000-000000000001 # ╟─00000000-0000-0000-0000-000000000002