diff --git a/_data/toc.yml b/_data/toc.yml index dd61231..4cc2a86 100755 --- a/_data/toc.yml +++ b/_data/toc.yml @@ -58,7 +58,6 @@ - url: /data_work/stats - url: /data_work/optimisation - url: /data_work/ir_spectra - - url: /data_work/linear_algebra - url: /advanced/advanced not_numbered: false @@ -69,5 +68,24 @@ - url: /advanced/classes - url: /advanced/custom_packages + - url: /linear_algebra/linear_algebra + not_numbered: false + expand_sections: false + sections: + - url: /linear_algebra/scalars_and_vectors + - url: /linear_algebra/dot_product + - url: /linear_algebra/bases + - url: /linear_algebra/matrices + - url: /linear_algebra/determinants + - url: /linear_algebra/cross_product + - url: /linear_algebra/inverse_transformations + - url: /linear_algebra/active_passive_transformations + - url: /linear_algebra/diagonalisation + - url: /linear_algebra/eigenvectors_and_eigenfunctions + - url: /linear_algebra/change_of_variables + - url: /linear_algebra/notation + - url: /linear_algebra/problems + + \ No newline at end of file diff --git a/content/images/additive_vectors.pdf b/content/images/additive_vectors.pdf new file mode 100644 index 0000000..d3bf12c Binary files /dev/null and b/content/images/additive_vectors.pdf differ diff --git a/content/images/bases.pdf b/content/images/bases.pdf new file mode 100644 index 0000000..e00a02c Binary files /dev/null and b/content/images/bases.pdf differ diff --git a/content/images/bases_general.pdf b/content/images/bases_general.pdf new file mode 100644 index 0000000..2dd6dbd Binary files /dev/null and b/content/images/bases_general.pdf differ diff --git a/content/images/circle_road.pdf b/content/images/circle_road.pdf new file mode 100644 index 0000000..f6a914f Binary files /dev/null and b/content/images/circle_road.pdf differ diff --git a/content/images/ij.pdf b/content/images/ij.pdf new file mode 100644 index 0000000..6edec25 Binary files /dev/null and b/content/images/ij.pdf differ diff --git a/content/images/matrix_multiplication_1.pdf b/content/images/matrix_multiplication_1.pdf new file mode 100644 index 0000000..0b8896c Binary files /dev/null and b/content/images/matrix_multiplication_1.pdf differ diff --git a/content/images/matrix_multiplication_2.pdf b/content/images/matrix_multiplication_2.pdf new file mode 100644 index 0000000..38cdab4 Binary files /dev/null and b/content/images/matrix_multiplication_2.pdf differ diff --git a/content/images/road_config.pdf b/content/images/road_config.pdf new file mode 100644 index 0000000..316ace5 Binary files /dev/null and b/content/images/road_config.pdf differ diff --git a/content/images/sphere.pdf b/content/images/sphere.pdf new file mode 100644 index 0000000..581417f Binary files /dev/null and b/content/images/sphere.pdf differ diff --git a/content/images/theta.pdf b/content/images/theta.pdf new file mode 100644 index 0000000..313af6b Binary files /dev/null and b/content/images/theta.pdf differ diff --git a/content/linear_algebra/active_passive_transformations.ipynb b/content/linear_algebra/active_passive_transformations.ipynb new file mode 100644 index 0000000..967b17f --- /dev/null +++ b/content/linear_algebra/active_passive_transformations.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Active and passive transformations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/bases.ipynb b/content/linear_algebra/bases.ipynb new file mode 100644 index 0000000..0b7adac --- /dev/null +++ b/content/linear_algebra/bases.ipynb @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Prerequisites:**\n", + "- Functions\n", + "- Collections\n", + "- NumPy arrays\n", + "- Scalars and vectors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Bases\n", + "\n", + "Until now we have been representing vectors as linear combinations of $\\mathbf{i}$, $\\mathbf{j}$, and $\\mathbf{k}$. For example, we have shown the point $\\mathbf{p}$ = [2,4,3] can be written as\n", + "\n", + "$$ \\mathbf{p} = 2 \\mathbf{i} + 4 \\mathbf{j} + 3 \\mathbf{k}. $$\n", + "\n", + "In the above, we are using the standard basis. A basis is a set of vectors that describes the space that we are interested in. Any point within the domain that we are interested, in linear algebra this domain is called a linear subspace, can be described by a linear combination of our basis set. Consider three dimensional space, any point, $\\mathbf{r}$, can be described by a set of coordinates (x,y,z) and thus can be described by \n", + "\n", + "$$ \\mathbf{r} = x \\mathbf{i} + y \\mathbf{j} + z \\mathbf{k} .$$ \n", + "\n", + "Any point in three-dimensional space can be describe as such using the standard basis. The standard basis in three-dimensional space is defined as \n", + "\n", + "$$ \\mathbf{e_{x}} = \\mathbf{i} = \\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix}, \\quad \\mathbf{e_{y}} = \\mathbf{j} = \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix}, \\quad \\mathbf{e_{z}} = \\mathbf{k} = \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix}. $$\n", + "\n", + "Explicitly, when we express $\\mathbf{r}$ as above we are writing\n", + "\n", + "$$ \\mathbf{r} = x \\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix} + y \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} + z \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix} = \\begin{pmatrix} x \\\\ 0 \\\\ 0 \\end{pmatrix} + \\begin{pmatrix} 0 \\\\ y \\\\ 0 \\end{pmatrix} + \\begin{pmatrix} 0 \\\\ 0 \\\\ z \\end{pmatrix} = \\begin{pmatrix} x \\\\ y \\\\ z \\end{pmatrix}. $$\n", + "\n", + "The standard basis is the most commonly used basis set because it is easy to picture mentally and convenient to use. However, it is not the only basis set that we could use, and sometimes it is not practical to use the standard basis set. \n", + "\n", + "We choose different bases sets all the time. Consider an experiment where we track the displacement of a particle throughout time. If we define the origin as the initial position of the particle, and use standard units then after a short time, t, the displacement of the particle is:\n", + "\n", + "$$ \\mathbf{r}(t) = \\begin{pmatrix} 1.2 \\times 10^{-7} \\\\ 2.8 \\times 10^{-6} \\\\ 3.3 \\times 10^{-7} \\end{pmatrix} \\; (/m)$$\n", + "\n", + "The reason for the small values is because our basis is in meters. If we change our basis so that it is in micrometers then we would obtain more manageable values. \n", + "\n", + "$$ \\mathbf{r}(t) = \\begin{pmatrix} 0.12 \\\\ 2.8 \\\\ 0.33 \\end{pmatrix} \\;(/\\mu m)$$\n", + "\n", + "Changing units can be considered as merely a change of basis vectors. Whilst, a change of units is a simple example of a change of basis, there is no reason why we cannot use any basis that we choose, as long as the basis set can sufficiently describe our system. \n", + "\n", + "A basis set must consist of linearly independant vectors. For a set of vectors to be linearly independant, each vector in the set cannot be written as a linear combination of the remaining vectors in the set. Let's clarify this using the standard basis set. We cannot write the vector $\\mathbf{i}$ in the form:\n", + "\n", + "$$\\mathbf{i} \\neq a \\mathbf{j} + b \\mathbf{k} \\quad \\forall a,b \\in \\mathbb{R}$$\n", + "\n", + "$$\\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix} \\neq a \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} + b \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix} \\quad \\forall a,b \\in \\mathbb{R}$$\n", + "\n", + "Where \"$\\forall a,b \\in \\mathbb{R}$\" means \"for all a,b in the real numbers\". No matter what values a and b take, the right and left hand sides of the equation will never equate. Therefore, the standard basis is a linearly independant basis set. Whereas if we wish to determine whether or not the set of vectors $\\mathbf{i}$, $\\mathbf{j}$, $\\mathbf{k}$, and $\\mathbf{p}$ is a linearly independant basis set, it is clearly not because we can write \n", + "\n", + "$$ \\mathbf{p} = 2 \\mathbf{i} + 4 \\mathbf{j} + 3 \\mathbf{k}. $$\n", + "\n", + "How about the set of vectors $\\mathbf{i}$, $\\mathbf{j}$, and $\\mathbf{p}$. Let's consider the combinations:\n", + "\n", + "$$\\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix} \\neq a \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} + b \\begin{pmatrix} 2 \\\\ 4 \\\\ 3 \\end{pmatrix} \\quad \\forall a,b \\in \\mathbb{R}$$\n", + "\n", + "$$\\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} \\neq a \\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix} + b \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix} \\quad \\forall a,b \\in \\mathbb{R}$$\n", + "\n", + "$$\\begin{pmatrix} 2 \\\\ 4 \\\\ 3 \\end{pmatrix} \\neq a \\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\end{pmatrix} + b \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} \\quad \\forall a,b \\in \\mathbb{R}$$\n", + "\n", + "Therefore, the set $\\mathbf{i}$, $\\mathbf{j}$, $\\mathbf{p}$ is a valid basis set to describe three dimensional space. In order to visualise what a linear subspace looks like using a basis set that is not the standard basis set, consider a linear subspace defined by the basis set \n", + "\n", + "$$ \\begin{pmatrix} 2 \\\\ 0 \\\\ 0 \\end{pmatrix}, \\; \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix}, \\; \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix} $$\n", + "\n", + "The only difference is that the x direction basis vector has double the length. The linear subspace, and the three bases vectors can be visualised below. \n", + "\n", + "\"drawing\"\n", + "\n", + "Note that the grid lines along the x-axis are more seperated than along the y and z axes. Under this new basis set, the point (1,1,1), under the standard basis set, has coordinates (0.5, 1, 1) under this new basis set because (0.5, 1, 1) is equivalent to\n", + "\n", + "$$ 0.5 \\begin{pmatrix} 2 \\\\ 0 \\\\ 0 \\end{pmatrix} + 1 \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix} + 1 \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix}. $$\n", + "\n", + "**Exercise:** Determine the vector associated with the point (17, 2, -9) using the basis set described above." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:22:19.971522Z", + "start_time": "2020-06-15T17:22:19.968034Z" + } + }, + "outputs": [], + "source": [ + "### Write your code here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/change_of_variables.ipynb b/content/linear_algebra/change_of_variables.ipynb new file mode 100644 index 0000000..df251a1 --- /dev/null +++ b/content/linear_algebra/change_of_variables.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Change of variables" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/data_work/linear_algebra.ipynb b/content/linear_algebra/cross_product.ipynb similarity index 93% rename from content/data_work/linear_algebra.ipynb rename to content/linear_algebra/cross_product.ipynb index 11ab898..c8d2a06 100644 --- a/content/data_work/linear_algebra.ipynb +++ b/content/linear_algebra/cross_product.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Linear algebra" + "## Cross product" ] }, { @@ -35,5 +35,5 @@ } }, "nbformat": 4, - "nbformat_minor": 4 + "nbformat_minor": 2 } diff --git a/content/linear_algebra/determinants.ipynb b/content/linear_algebra/determinants.ipynb new file mode 100644 index 0000000..c0d7f25 --- /dev/null +++ b/content/linear_algebra/determinants.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Determinants" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/diagonalisation.ipynb b/content/linear_algebra/diagonalisation.ipynb new file mode 100644 index 0000000..00d504f --- /dev/null +++ b/content/linear_algebra/diagonalisation.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Diagonalisation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/dot_product.ipynb b/content/linear_algebra/dot_product.ipynb new file mode 100644 index 0000000..ae14388 --- /dev/null +++ b/content/linear_algebra/dot_product.ipynb @@ -0,0 +1,230 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Prerequisites:**\n", + "- Functions\n", + "- Collections\n", + "- NumPy arrays\n", + "- Scalars and vectors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Dot product of vectors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dot products, or alternatively the scalar product, is defined between two vectors as \n", + "\n", + "$$ \\mathbf{u} \\cdot \\mathbf{v} = \\sum_{i} u_{i} v_{i}, $$\n", + "\n", + "here we introduce the common vector notation \n", + "\n", + "$$ \\mathbf{u} = [ u_{1} , u_{2}, ... , u_{n} ] .$$\n", + "\n", + "Consider the vectors\n", + "\n", + "$$ \\mathbf{u} = [1,3, 3, 0], $$\n", + "$$\\mathbf{v} = [0,2,1,5]. $$\n", + "\n", + "The dot product between these two vectors is\n", + "\n", + "$$ \\mathbf{u} \\cdot \\mathbf{v} = \\sum_{i} u_{i} v_{i} $$\n", + "\n", + "$$= 1 \\cdot 0 + 3 \\cdot 2 + 3 \\cdot 1 + 0 \\cdot 5 = 0 + 6 + 3 + 0 = 9 $$\n", + "\n", + "Calculating the dot product is made simple with the NumPy module. If we wished to calculate the above dot product using python, one could define the vectors as previously shown and use np.dot(u,v) to determine the dot product. This is illustrated below" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:19:24.611588Z", + "start_time": "2020-06-15T17:19:24.404670Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "9" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "\n", + "u = np.array([1,3,3,0])\n", + "v = np.array([0,2,1,5])\n", + "np.dot(u,v)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected a value of 9 is returned. \n", + "\n", + "The magnitude of a vector is defined as the square root of the dot product between the vector and itself. Consider the vectors $\\mathbf{u}$ and $\\mathbf{v}$ above, their magnitudes are given by\n", + "\n", + "$$ ||\\mathbf{u}|| = \\sqrt{\\mathbf{u} \\cdot \\mathbf{u}} = $$\n", + "\n", + "$$\\sqrt{ 1 \\cdot 1 + 3 \\cdot 3 + 3 \\cdot 3 + 0 \\cdot 0 }= \\sqrt{19},$$\n", + "\n", + "\n", + "$$ ||\\mathbf{v}|| = \\sqrt{\\mathbf{v} \\cdot \\mathbf{v} }= $$\n", + "\n", + "$$ \\sqrt{0 \\cdot 0 + 2 \\cdot 2 + 1 \\cdot 1 + 5 \\cdot 5 }= \\sqrt{30}.$$\n", + "\n", + "$||\\mathbf{u}||$ represents the magnitude of a vector. The magnitude is also easily calculated using NumPy. To determime the magntiude of the vector $\\mathbf{u}$, we can use" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:19:47.656232Z", + "start_time": "2020-06-15T17:19:47.644765Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The magnitude of the vector u is sqrt( 19.00 ).\n" + ] + } + ], + "source": [ + "np.linalg.norm(u)\n", + "\n", + "print(\"The magnitude of the vector u is sqrt(\", \"{:.2f}\".format(np.linalg.norm(u)**2), \").\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above definition of the dot product is the algebraic definition of the dot product. An alternative, geometric, definition of the dot product is \n", + "\n", + "$$ \\mathbf{u} \\cdot \\mathbf{v} = || \\mathbf{u} || \\; ||\\mathbf{v} || \\cos (\\theta) $$\n", + "\n", + "where $\\theta$ is the angle between the vectors $\\mathbf{u}$ and $\\mathbf{v}$. In order to determine the angle between two vectors one can rearrange the above equation for theta,\n", + "\n", + "$$ \\theta = \\arccos \\left( \\frac{\\mathbf{u} \\cdot \\mathbf{v} }{||\\mathbf{u} || \\; || \\mathbf{v} || } \\right). $$\n", + "\n", + "The angle theta is illustrated below for two arbitrary vectors:\n", + "\n", + "\"drawing\"\n", + "\n", + "We can therefore determine the angle between $\\mathbf{u}$ and $\\mathbf{v}$ using the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:20:24.292924Z", + "start_time": "2020-06-15T17:20:24.287555Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The angle between the vectors u and v is 1.1842751591691685 radians.\n" + ] + } + ], + "source": [ + "mag_u = np.linalg.norm(u)\n", + "mag_v = np.linalg.norm(v)\n", + "\n", + "numerator = np.dot(u,v)\n", + "denominator = mag_u * mag_v \n", + "\n", + "theta = np.arccos(numerator / denominator)\n", + "\n", + "print(\"The angle between the vectors u and v is\", theta, \"radians.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:20:35.132278Z", + "start_time": "2020-06-15T17:20:35.123886Z" + } + }, + "source": [ + "**Exercise:** Using the functions np.dot, np.linalg.norm, and np.arccos, determine the magnitudes and angles between all pairs of vectors for the standard basis vectors introduced earlier\n", + "\n", + "$$ \\mathbf{i} = [1, 0, 0], $$\n", + "$$ \\mathbf{j} = [0, 1, 0], $$\n", + "$$ \\mathbf{k} = [0, 0, 1]. $$\n", + "\n", + "Think about what you would expect the answers to be before using python to calculate the solutions." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:20:45.962271Z", + "start_time": "2020-06-15T17:20:45.959171Z" + } + }, + "outputs": [], + "source": [ + "### Write your code here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/eigenvectors_and_eigenfunctions.ipynb b/content/linear_algebra/eigenvectors_and_eigenfunctions.ipynb new file mode 100644 index 0000000..08a40f7 --- /dev/null +++ b/content/linear_algebra/eigenvectors_and_eigenfunctions.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Eigenvectors and eigenfunctions" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/inverse_transformations.ipynb b/content/linear_algebra/inverse_transformations.ipynb new file mode 100644 index 0000000..169ca6c --- /dev/null +++ b/content/linear_algebra/inverse_transformations.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inverse transformations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/linear_algebra.md b/content/linear_algebra/linear_algebra.md new file mode 100644 index 0000000..d2c4b92 --- /dev/null +++ b/content/linear_algebra/linear_algebra.md @@ -0,0 +1,24 @@ +# Linear algebra + +Linear algebra is branch of mathematics that is still actively researched today. It is the fundamental basis for many chemical applications, for example solving the Schrodinger equation, and is the bedrock of computer science. + +There are multiple linear algebra courses run throughout a mathematics degree, and therefore it is impossible to cover significant proportions of linear algebra in a tutorial such as this. The purpose of this tutorial is to introduce the following key concepts: + +- Scalars and vectors +- The dot product of vectors +- Bases +- Matrices +- Notation +- Determinants +- The cross product of vectors +- Inverse transformations +- Active and passive transformations +- Diagonalisation +- Eigenvectors and eigenvalues +- Change of variables + +This notebook will not be exhaustive when it comes to the concepts above as our aim is to help facilitate your use of python for chemistry problems. For more information on the above there are a plethora of resources based on undergraduate and postgraduate mathematics courses on the web for a more indepth discussion. + +Whilst many undergraduate chemistry degree courses attempt to steer clear of mathematics as far as possible, we believe that gaining knowledge about these fundamental concepts will not only allow you to become a better programmer, but allow you to tackle the more difficult chemistry problems as well. + +Due to there being a lot of content to cover, and the topics not lending themselves easily to applied chemical problems individually, there will be a longer problem notebook that will test your knowledge of linear algebra after this that will be based on chemical problems. diff --git a/content/linear_algebra/matrices.ipynb b/content/linear_algebra/matrices.ipynb new file mode 100644 index 0000000..dd19583 --- /dev/null +++ b/content/linear_algebra/matrices.ipynb @@ -0,0 +1,217 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:24:54.579144Z", + "start_time": "2020-06-15T17:24:54.573637Z" + } + }, + "source": [ + "**Prerequisites:**\n", + "- Collections\n", + "- NumPy arrays\n", + "- Scalars and vectors\n", + "- Bases" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:22:49.075509Z", + "start_time": "2020-06-15T17:22:49.036290Z" + } + }, + "source": [ + "### Matrices\n", + "\n", + "So far we have discussed how a basis set of vectors can be used to specify a location of a vector subspace, but how do we describe a vector subspace in linear algebra? The answer is that we use a matrix. A matrix uses the bases set of vectors to define a vector subspace. Let's take the example used in the previous section, where the basis used was\n", + "\n", + "$$ \\begin{pmatrix} 2 \\\\ 0 \\\\ 0 \\end{pmatrix}, \\; \\begin{pmatrix} 0 \\\\ 1 \\\\ 0 \\end{pmatrix}, \\; \\begin{pmatrix} 0 \\\\ 0 \\\\ 1 \\end{pmatrix} $$\n", + "\n", + "In order to describe a vector subspace using this basis set we arrange our basis such that we create the matrix\n", + "\n", + "$$ \\begin{bmatrix}\n", + " 2 & 0 & 0 \\\\\n", + " 0 & 1 & 0 \\\\\n", + " 0 & 0 & 1\n", + "\\end{bmatrix}.\n", + "$$\n", + "\n", + "Recall that in order to obtain the point (1,1,1) using this basis set, we used the coordinates (0.5,1,1). These coordinates define a vector using this basis set. In order to get to the point (1,1,1), we must multiple the matrix above by the vector (0.5, 1, 1). We can do this using the \"across and down\" method. The \"across and down\" method is illustrated below:\n", + "\n", + "\"drawing\"\n", + "\n", + "First we define the matrix multiplication we wish to conduct. Then we calculate the first component of our solution by component wise multiplying the first row, with our vector and summing each multiplicative pair (highlighted in red). We then calculate our second component of our solution by the same method (highlighted in purple), and finally we calculate our third component with using the thrid row (highlighted in blue). As we expected we obtain the solution \n", + "\n", + "$$ \\begin{pmatrix} 1 \\\\ 1 \\\\ 1 \\end{pmatrix}. $$\n", + "\n", + "Let's try something a little more difficult. Imagine we are working in ths subspace defined by the basis set \n", + "\n", + "$$ \\begin{pmatrix} 5 \\\\ 2 \\\\ 1 \\end{pmatrix}, \\; \\begin{pmatrix} 1 \\\\ -1 \\\\ 1 \\end{pmatrix}, \\; \\begin{pmatrix} 2 \\\\ -1 \\\\ 3 \\end{pmatrix}. $$ \n", + "\n", + "We want to calculate the position given by the vector (2,-1,3) in this subspace. Following the same method as above, we deduce \n", + "\n", + "\"drawing\"\n", + "\n", + "How does this work? Let's consider the most general of cases, where our basis set is \n", + "\n", + "$$ \\begin{pmatrix} a_{1} \\\\ b_{1} \\\\ c_{1} \\end{pmatrix}, \\; \\begin{pmatrix} a_{2} \\\\ b_{2} \\\\ c_{2} \\end{pmatrix}, \\; \\begin{pmatrix} a_{3} \\\\ b_{3} \\\\ c_{3} \\end{pmatrix}, $$\n", + "\n", + "and the matrix defining our subspace is given by \n", + "\n", + "$$ \\begin{bmatrix}\n", + " a_{1} & a_{2} & a_{3} \\\\\n", + " b_{1} & b_{2} & b_{3} \\\\\n", + " c_{1} & c_{2} & c_{3}\n", + "\\end{bmatrix}.\n", + "$$\n", + "\n", + "If we multiply this with the general vector \n", + "$$ \\begin{pmatrix} x \\\\ y \\\\ z \\end{pmatrix}, $$\n", + "what do we obtain?\n", + "\n", + "\"drawing\"\n", + "\n", + "We can see from the above that using matrix multiplication is the same as using the explicit components of the vectors and the basis vectors!\n", + "\n", + "Now that we have a fundamental understanding of what matrices represent, we will discuss how to appropriately depict and use them using the NumPy library. Let's take the simplest 3 $\\times$ 3 matrix\n", + "\n", + "$$ \\begin{bmatrix}\n", + " 1 & 0 & 0 \\\\\n", + " 0 & 1 & 0 \\\\\n", + " 0 & 0 & 1\n", + "\\end{bmatrix}.\n", + "$$\n", + "\n", + "We can represent this in a similar way to the way we represented a vector previously" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:23:16.674325Z", + "start_time": "2020-06-15T17:23:16.181091Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[1 0 0]\n", + " [0 1 0]\n", + " [0 0 1]]\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "matrix = np.array([[1,0,0],\n", + " [0,1,0],\n", + " [0,0,1]])\n", + "\n", + "\n", + "print(matrix)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that there are an outer set of square brackets, and inner set of square brackets for each row of the matrix. To compute the product of a matrix and a vector, we use the np.matmul function which stands for matrix multiplication. Let's use python to calculate the second matrix multiplication example above" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:23:36.111174Z", + "start_time": "2020-06-15T17:23:36.104335Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[15 2 10]\n" + ] + } + ], + "source": [ + "matrix = np.array([[5,1,2],\n", + " [2,-1,-1],\n", + " [1,1,3]])\n", + "\n", + "vector = np.array([2,-1,3])\n", + "\n", + "solution = np.matmul(matrix, vector)\n", + "print(solution)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The solution returned is as expected from the illustration previously.\n", + "\n", + "**Exercise:** Determine the matrix that describes the vector subspace defined by the following basis set\n", + "\n", + "$$ \\begin{pmatrix} 1 \\\\ 2 \\\\ 1 \\\\ 0 \\end{pmatrix}, \\; \\begin{pmatrix} 1 \\\\ 0 \\\\ 0 \\\\ -1 \\end{pmatrix}, \\; \\begin{pmatrix} 2 \\\\ -2 \\\\ 1 \\\\ 0 \\end{pmatrix}, \\;\n", + "\\begin{pmatrix} 0 \\\\ -1 \\\\ 0 \\\\ 1 \\end{pmatrix}.$$\n", + "\n", + "Calculate the product of the matrix that defines the above vector subspace with the vector \n", + "$$ \\begin{pmatrix} 1 \\\\ -2 \\\\ 0 \\\\ 3 \\end{pmatrix}. $$" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:23:57.078391Z", + "start_time": "2020-06-15T17:23:57.075097Z" + } + }, + "outputs": [], + "source": [ + "### Write your code here" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/notation.ipynb b/content/linear_algebra/notation.ipynb new file mode 100644 index 0000000..748902b --- /dev/null +++ b/content/linear_algebra/notation.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/problems.ipynb b/content/linear_algebra/problems.ipynb new file mode 100644 index 0000000..ebbd766 --- /dev/null +++ b/content/linear_algebra/problems.ipynb @@ -0,0 +1,39 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Linear algebra problems" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/content/linear_algebra/scalars_and_vectors.ipynb b/content/linear_algebra/scalars_and_vectors.ipynb new file mode 100644 index 0000000..ab9b2b7 --- /dev/null +++ b/content/linear_algebra/scalars_and_vectors.ipynb @@ -0,0 +1,221 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Prerequisites:**\n", + "- Collections\n", + "- NumPy arrays" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Scalars and vectors" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Scalar values are values that consist of just a magnitude. These are properties such as the distance travelled by an atom, the mass of a compound, or the speed of a particle in a mass spectrometer. \n", + "\n", + "A vector is a property that consists of both a magnitude and a direction. This may be the displacement of an atom, the weight of a compound, or the velocity of a particle. \n", + "\n", + "This differentiation is better described with an example: a person drives to the shop from their house. The person's house is at point A, the shop is at point B, and the road connecting points A to B is circular and defined by ACBD.\n", + "\n", + "\"drawing\"\n", + "\n", + "The distance travelled by the person is simple to calculate. They must either got from A to C to B or, alternatively, A to D to B. Travelling a semi-circle of radius ten on each of the paths to the shop. Using the equation for an arc,\n", + "\n", + "$$ d = r \\theta ,$$ \n", + "\n", + "where d is the arc length, $\\theta$ is the angle traversed along the circle, and r is the radius of the circle, we deduce they travel 10 $\\pi$. \n", + "\n", + "But the displacement of the person when arriving at the shop can be determined by thinking of this circle sitting on a coordinate system, as if we are plotting a graph. We conveniently set the origin to be point A, and therefore point A has coordinates (0,0). Point B has coordinates (20,0). This consequently makes the coordinates of point C (10,10) and the coordinates of point D (10,-10) as the radius of the circle is 10. \n", + "\n", + "\"drawing\"\n", + "\n", + "The grid lines on the graph above are seperated for each value of one in both the x and y directions. It is common practice in linear algebra to define a movement of one in the x direction by **i**, which defines a vector (1,0), and a movement of one in the y direction by __j__, which defines a vector (0,1). As described in the figure below.\n", + "\n", + "\"drawing\"\n", + "\n", + "Note that the vectors **i** and __j__ are represented by arrows from the origin to the relevant point. This is a common, and accepted, method of visualising and representing vectors. We can write the coordinates defined earlier as (x,y), as vectors such that:\n", + "\n", + "$$ \\text{A}: \\quad \\mathbf{a}= 0 \\; \\mathbf{i} + 0 \\; \\mathbf{j} $$\n", + "$$ \\text{B}: \\quad \\mathbf{b}= 20 \\; \\mathbf{i} + 0 \\; \\mathbf{j} $$\n", + "$$ \\text{C}: \\quad \\mathbf{c}= 10 \\; \\mathbf{i} + 10 \\; \\mathbf{j} $$\n", + "$$ \\text{D}: \\quad\\mathbf{d}= 10 \\; \\mathbf{i} -10 \\; \\mathbf{j} $$\n", + "\n", + "Here we have defined the vector to go from the origin to point B, as $\\mathbf{b}$. This is because it is conventional to label vectors as lowercase and in bold font. Therefore, the displacement to go from home, at A, to the shop, at B, is defined by:\n", + "\n", + "$$ \\mathbf{b} - \\mathbf{a} = 20 \\; \\mathbf{i} + 0 \\; \\mathbf{j} $$\n", + "\n", + "Which you may recognise as merely being the vector $\\mathbf{b}$. This is due to the fact that the position A is the origin. \n", + "\n", + "We can represent the vectors above as NumPy arrays such that:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:16:47.318092Z", + "start_time": "2020-06-15T17:16:46.468067Z" + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "a = np.array([0,0])\n", + "\n", + "b = np.array([20,0])\n", + "\n", + "c = np.array([10,10])\n", + "\n", + "d = np.array([10,-10])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now imagine the another person travelling to the shop. This individual's house is located at C. The distance this individual has to travel is again calculated using the equation for an arc expressed before\n", + "\n", + "$$ d = r \\theta = 10 \\frac{\\pi}{2} = 5\\pi$$ \n", + "\n", + "and the displacement of this individual to go from their house is given by $\\mathbf{b} - \\mathbf{c}$. This can now be calculated using python with the following code:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:17:08.414201Z", + "start_time": "2020-06-15T17:17:08.407777Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The displacement of this individual to go to the shop is [ 10 -10]\n" + ] + } + ], + "source": [ + "displacement = b - c \n", + "\n", + "print(\"The displacement of this individual to go to the shop is\", displacement)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recall that the array [10 -10] is equivalent to \n", + "\n", + "$$ 10 \\; \\mathbf{i} - 10 \\; \\mathbf{j}$$\n", + "\n", + "**Exercise:** Using the NumPy arrays defined above, calculate the displacement of an individual travelling from point D to the shop, and the displacement between the points C and D. In addition, calculate the distances traversed when travelling between these points on the circular path. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-06-15T17:17:25.392397Z", + "start_time": "2020-06-15T17:17:25.389370Z" + } + }, + "outputs": [], + "source": [ + "### Write your code here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the above example, we described movement on a two-dimensional plane. Often, problems in chemistry are three-dimensional. Similarly to earlier, in three dimensions we describe the coordinates (x,y,z) as \n", + "\n", + "$$ x \\; \\mathbf{i} + y \\; \\mathbf{j} + z \\; \\mathbf{k} ,$$\n", + "\n", + "where **k** describes the vector associated with a movement of magntiude one in the z direction. Let us consider a problem similar to the one we have already discussed: travelling on the surface of a sphere. Consider a sphere of radius ten with the following associated points\n", + "\n", + "$$ \\text{A}: \\quad \\mathbf{a}= -10 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k}$$\n", + "$$ \\text{B}: \\quad \\mathbf{b}= 10 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k}$$\n", + "$$ \\text{C}: \\quad \\mathbf{c}= 0 \\; \\mathbf{i} + 10 \\; \\mathbf{j} + 0 \\; \\mathbf{k} $$\n", + "$$ \\text{D}: \\quad\\mathbf{d}= 0 \\; \\mathbf{i} -10 \\; \\mathbf{j} + 0 \\; \\mathbf{k}$$\n", + "$$ \\text{E}: \\quad\\mathbf{e}= 0 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 10 \\; \\mathbf{k}$$\n", + "$$ \\text{F}: \\quad\\mathbf{f}= 0 \\; \\mathbf{i} + 0 \\; \\mathbf{j} - 10 \\; \\mathbf{k}$$\n", + "\n", + "Here the origin is at the centre of the sphere. The system defined is:\n", + "\n", + "\"drawing\"\n", + "\n", + "Consider traversing the sphere between the points along the shortest path. This again can be described using the equation for an arc. To traverse between adjacent points requires moving a distance of 5 $\\pi$, whilst to traverse between points that are opposite one another requires moving a distance of 10 $\\pi$ along the surface of the sphere. \n", + "\n", + "The displacement to go from position A to position B is:\n", + "\n", + "$$ \\mathbf{b} - \\mathbf{a} = 20 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k} $$\n", + "\n", + "An easy way thinking about adding and subtracting vectors is the \"tip to tail\" method. As discussed earlier, vectors can be visualised as arrows from the origin to their respective points. If we take the example above where we subtract the vector $\\mathbf{a}$ from the vector $\\mathbf{b}$ we can think of this as:\n", + "\n", + "$$ \\mathbf{b} - \\mathbf{a} = \\mathbf{b} + \\mathbf{-a},$$\n", + "\n", + "where \n", + "\n", + "$$ \\mathbf{a}= -10 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k},$$\n", + "$$\\quad \\mathbf{b}= 10 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k}.$$\n", + "\n", + "Therefore \n", + "\n", + "$$ \\mathbf{-a}= 10 \\; \\mathbf{i} + 0 \\; \\mathbf{j} + 0 \\; \\mathbf{k}.$$\n", + "\n", + "We can therefore represent both $\\mathbf{a}$ and $\\mathbf{b}$ as an arrow from the origin to (10,0,0). The \"tip to tail\" method is where, starting from the origin, we create a trail of vectors where the tip of an arrow is followed by the tail of another. This can be seen below: \n", + "\n", + "\"drawing\"\n", + "\n", + "**Exercise:** Determine the displacement to when someone travels from point D to point F. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "### Write your code here" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}