{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Matrix operations\n", "\n", "## Arithmetic, element-by-element operations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a number of operations with matrices, we start with arithmetic operations. Imagine, we have two matrices of the size $2\\times3$:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 10 10 10\n", " 20 20 20\n", "\n", "b =\n", "\n", " 1 2 3\n", " 4 5 6\n", "\n" ] } ], "source": [ "a = [10 10 10; 20 20 20]\n", "b = [1 2 3; 4 5 6]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start with operations that work element-by-element, that is, each element of the first matrix is combined with the corresponding element of the second matrix\n", "* add `+` (the same as `.+`)\n", "* subtract (the same as `.-`)\n", "* multiply `.*`\n", "* divide `./`\n", "* left divide `.\\`\n", "* to the power`.^` (the same as `.**`)\n", "\n", "*here is a short reminder about, for example, adding matrices [https://www.mathsisfun.com/algebra/matrix-introduction.html](https://www.mathsisfun.com/algebra/matrix-introduction.html)*" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a_add_b =\n", "\n", " 11 12 13\n", " 24 25 26\n", "\n", "a_sub_b =\n", "\n", " 9 8 7\n", " 16 15 14\n", "\n", "a_mul_b =\n", "\n", " 10 20 30\n", " 80 100 120\n", "\n", "a_div_b =\n", "\n", " 10.0000 5.0000 3.3333\n", " 5.0000 4.0000 3.3333\n", "\n", "b_div_a =\n", "\n", " 0.10000 0.20000 0.30000\n", " 0.20000 0.25000 0.30000\n", "\n", "a_pow_b =\n", "\n", " 10 100 1000\n", " 160000 3200000 64000000\n", "\n" ] } ], "source": [ "a_add_b = a + b # symbol _ is just a part of a variable name\n", "a_sub_b = a - b\n", "a_mul_b = a .* b\n", "a_div_b = a ./ b\n", "b_div_a = a .\\ b # this is the same as b ./ a\n", "a_pow_b = a .^ b" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 2 1 1\n", " 1 2 1\n", " 1 1 2\n", "\n" ] } ], "source": [ "eye(3) + ones(3) # just another example, here we add an identity matrix to a matrix of ones" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This operations, of cause, also work for numbers. That is because numbers are just matrices of size $1\\times1$:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 4\n" ] } ], "source": [ "2 + 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Matrix arithmetic operations\n", "### Matrix multiplication" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The next operations treat their arguments as matrices. For example, matrix multiplication is very different from element-by-element multiplication, it is defined in the Linear Algebra. Look here to remember [https://www.mathsisfun.com/algebra/matrix-multiplying.html](https://www.mathsisfun.com/algebra/matrix-multiplying.html)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "id =\n", "\n", " 1 0 0\n", " 0 1 0\n", " 0 0 1\n", "\n", "a =\n", "\n", " 1 2 3\n", " 3 2 1\n", " -1 -2 -3\n", "\n", "b =\n", "\n", " 1 -1\n", " 2 -2\n", " 0 1\n", "\n", "c =\n", "\n", " 1 1 2\n", "\n", "d =\n", "\n", " 1\n", " 1\n", " 2\n", "\n", "id_mul_a =\n", "\n", " 1 2 3\n", " 3 2 1\n", " -1 -2 -3\n", "\n", "id_mul_b =\n", "\n", " 1 -1\n", " 2 -2\n", " 0 1\n", "\n", "a_mul_b =\n", "\n", " 5 -2\n", " 7 -6\n", " -5 2\n", "\n", "error: operator *: nonconformant arguments (op1 is 3x2, op2 is 3x3)\n", "c_mul_d = 6\n", "d_mul_c =\n", "\n", " 1 1 2\n", " 1 1 2\n", " 2 2 4\n", "\n" ] } ], "source": [ "id = [1 0 0; 0 1 0; 0 0 1] # an identity matrix, the same as eye(3)\n", "a = [1 2 3; 3 2 1; -1 -2 -3]\n", "b = [1 -1; 2 -2; 0 1]\n", "c = [1 1 2] # a row-matrix\n", "d = [1; 1; 2] # a column-matrix\n", "id_mul_a = id * a # multiplication by id has no effect, the result is a\n", "id_mul_b = id * b # multiplication by id has no effect, the result is b\n", "a_mul_b = a * b\n", "b * a # you can not do this, because sizes of b and a are do not agree \n", "c_mul_d = c * d # when you multiply row by column you get only one number: 1*1 + 1*1 + 2 * 2 = 6\n", "d_mul_c = d * c # when you multiply column by row, you get a big matrix with all possible multiplications of matrices' elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note again that `A * B` and `A .* B` are very different operations:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 1 4 9\n", "\n", "error: operator *: nonconformant arguments (op1 is 1x3, op2 is 1x3)\n" ] } ], "source": [ "[1 2 3] .* [1 2 3] # this works\n", "[1 2 3] * [1 2 3] # this raises an error, beacuse the sizes of matrices do not agree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrix division\n", "*You can safely skip everything about division, beacuse this is not used in our assignments*\n", "\n", "The division is the operation, that is inverse to the multiplication. If `A = B * C`, then `B = A / C`, and `C = B \\ A`.\n", "This operations are defined in such a way that `(X / Y) * Y = X` and `X * (X \\ Y) = Y`.\n", "\n", "This can also be defined as `X / Y = X * inv(Y)` and `X \\ Y = inv(X) * Y`, where `inv(X)` is the inversion of the matrix `X`. [https://www.mathsisfun.com/algebra/matrix-inverse.html](https://www.mathsisfun.com/algebra/matrix-inverse.html). But the last definition works only if there exists an inverse of `X`." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2\n", " 3 4\n", "\n", "b =\n", "\n", " 1 2\n", " 1 3\n", "\n", "a_mul_b =\n", "\n", " 3 8\n", " 7 18\n", "\n", "should_be_a =\n", "\n", " 1 2\n", " 3 4\n", "\n", "should_be_b =\n", "\n", " 1.00000 2.00000\n", " 1.00000 3.00000\n", "\n" ] } ], "source": [ "a = [1 2; 3 4]\n", "b = [1 2; 1 3]\n", "a_mul_b = a * b\n", "should_be_a = a_mul_b / b\n", "should_be_b = a \\ a_mul_b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "we can also multiply and divide non-square matrices, but division will most probably give a different result" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2\n", " 3 4\n", " 5 6\n", "\n", "b =\n", "\n", " 2\n", " 3\n", "\n", "a_mul_b =\n", "\n", " 8\n", " 18\n", " 28\n", "\n", "not_exactly_a =\n", "\n", " 1.2308 1.8462\n", " 2.7692 4.1538\n", " 4.3077 6.4615\n", "\n", "the_same_as_a_mul_b =\n", "\n", " 8.0000\n", " 18.0000\n", " 28.0000\n", "\n" ] } ], "source": [ "a = [1 2; 3 4; 5 6]\n", "b = [2; 3]\n", "a_mul_b = a * b # let's multiply two matrices of different sizes\n", "not_exactly_a = a_mul_b / b # the result is different from a\n", "the_same_as_a_mul_b = not_exactly_a * b # but the result after multiplication is still as needed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matrix power\n", "\n", "The powering operation works only for numbers and square matrices:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 8\n", "pow3 =\n", "\n", " 1 3\n", " 0 1\n", "\n", "pow3 =\n", "\n", " 1 3\n", " 0 1\n", "\n", "ans =\n", "\n", " 10.483 14.152\n", " 21.228 31.711\n", "\n", "ans =\n", "\n", " 2 4\n", " 8 16\n", "\n" ] } ], "source": [ "2 ^ 3 # the same as 2 ** 3\n", "pow3 = [1 1; 0 1] ^ 3\n", "pow3 = [1 1; 0 1] * [1 1; 0 1] * [1 1; 0 1] # this is the same\n", "\n", "2 ^ [1 2; 3 4] # raising to the power of a matrix is an advanced operation, we are not going to use it \n", "2 .^ [1 2; 3 4] # but raising to the power element-by-element still gives the simple and expected result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Element-by-element operations with operands of different size (broadcasting)\n", "The feature that we are going to discuss is very usefull in practice, and we have some assignments that are easily solved with it.\n", "\n", "Imaging that we sum up matrices of different sizes:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2 3\n", " 2 3 4\n", " 3 4 5\n", "\n", "b =\n", "\n", " 100\n", " 200\n", " 300\n", "\n", "a_add_b =\n", "\n", " 101 102 103\n", " 202 203 204\n", " 303 304 305\n", "\n" ] } ], "source": [ "a = [1 2 3; 2 3 4; 3 4 5]\n", "b = [100; 200; 300]\n", "a_add_b = a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here the matrix `b` has only one column instead of 3, as in `a`. In this situation, the column is repeated three times before addition:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b_expanded =\n", "\n", " 100 100 100\n", " 200 200 200\n", " 300 300 300\n", "\n", "a_add_b =\n", "\n", " 101 102 103\n", " 202 203 204\n", " 303 304 305\n", "\n" ] } ], "source": [ "b_expanded = [b b b] # this is done automatically before the addition\n", "a_add_b = a + b_expanded # the same as a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the next example, the first operand is expanded to the size of the second operand:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 101 201 301\n", " 401 501 601\n", "\n", "ans =\n", "\n", " 101 201 301\n", " 401 501 601\n", "\n" ] } ], "source": [ "1 + [100 200 300; 400 500 600]\n", "ones(2, 3) + [100 200 300; 400 500 600] # this is the same" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, if we add a number to a matrix, the number is added to each element of the matrix.\n", "\n", "In the next example, both operands are expanded:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1\n", " 2\n", " 3\n", "\n", "b =\n", "\n", " 10 20 30\n", "\n", "a_add_b =\n", "\n", " 11 21 31\n", " 12 22 32\n", " 13 23 33\n", "\n", "a_expanded =\n", "\n", " 1 1 1\n", " 2 2 2\n", " 3 3 3\n", "\n", "b_expanded =\n", "\n", " 10 20 30\n", " 10 20 30\n", " 10 20 30\n", "\n", "a_add_b =\n", "\n", " 11 21 31\n", " 12 22 32\n", " 13 23 33\n", "\n" ] } ], "source": [ "a = [1; 2; 3]\n", "b = [10 20 30]\n", "a_add_b = a + b\n", "a_expanded = [a a a]\n", "b_expanded = [b ; b ; b]\n", "a_add_b = a_expanded + b_expanded # this is the same as a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In other words, we can understand the sum of a column $a_i$ and a row $b_j$ as a matrix $c_{i,j} = a_i + b_j$, where $i$ is an index of a row, and $j$ is an index of a column.\n", "\n", "Untill now all our examples were about the sum operation. Consider now examples for different operations:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 0 1 2\n", "\n", "ans =\n", "\n", " 2 4\n", " 6 8\n", "\n", "ans =\n", "\n", " 1 2 3\n", " 2 4 6\n", " 3 6 9\n", "\n", "ans =\n", "\n", " Columns 1 through 8:\n", "\n", " 1.00000 0.50000 0.33333 0.25000 0.20000 0.16667 0.14286 0.12500\n", "\n", " Columns 9 and 10:\n", "\n", " 0.11111 0.10000\n", "\n", "ans =\n", "\n", " 1.00000 0.00000 0.00000\n", " 0.00000 0.10000 0.00000\n", " 0.00000 0.00000 0.01000\n", "\n" ] } ], "source": [ "[1 2 3] - 1\n", "[1 2; 3 4] .* 2\n", "[1 2 3] .* [1; 2; 3]\n", "1 ./ (1:10)\n", "eye(3) ./ [1 10 100]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The matrix multiplication `*` and division `/`, `\\` operations don't expand their operands, but there is a very usefull special case: they may be used with numbers:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 2 2 2 2 2\n", " 2 2 2 2 2\n", " 2 2 2 2 2\n", " 2 2 2 2 2\n", " 2 2 2 2 2\n", "\n", "ans =\n", "\n", " 0.33333 0.66667 1.00000\n", "\n" ] } ], "source": [ "2 * ones(5) # multiply all elements by 2 (the same as .*)\n", "[1 2 3] / 3 # divide each element by 3 (the same as ./)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vectorization\n", "\n", "This is an important concept, because it is what differs octave programming from programming in another general purpose languages such as C/C++, Java, Python.\n", "\n", "Consider, for example, the addition operation `+`. You just write `a + b` and all elements are added similtaneously. If you worked in C/C++ with two dimensionals arrays, you should have wrote a nested loop that iterated through rows and columns of the matrices to add elements. There are loops in Octave also (we will look at them later), but you can usually avoid them. This makes code easier to understand and even faster.\n", "\n", "Let's look at the example, how one can avoid loops, using operations that we already know. Imagine, we have a row vector `a` and we want to find differences between each consequative elements:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 3 10 13 14\n", "\n", "b =\n", "\n", " 2 7 3 1\n", "\n" ] } ], "source": [ "a = [1 3 10 13 14] # this is what we have\n", "b = [2 7 3 1] # this is what we want to get" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$2 = 3 - 1$, $7 = 10 - 3$, $3 = 13 - 10$, $1 = 14 - 13$. Note that size of `b` is smaller than the size of `a` by 1.\n", "Look at the equalities in this paragraph. The first operands, from which we subtract are `[3, 10, 13, 1]`, and the second operands, that we subtract are: `[1, 3, 10, 13]`.\n", "\n", "But that means, that we subtract from `a` without the last element. And what we subtract is `a` without the first element. That is, we can just write:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 2 7 3 1\n", "\n" ] } ], "source": [ "a(2:end) - a(1:end-1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In fact, there is a built-in function for the same:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 2 7 3 1\n", "\n" ] } ], "source": [ "diff(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, when you write a program and want to use a loop, that is to repeat some action several times, think at first, whether it is possible to avoid looping by means of broadcasting, indexing, etc. This is usually possible for loops with simple bodies." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Other operations\n", "### Transposition\n", "If you want to recall a definition: [https://www.mathsisfun.com/algebra/matrix-introduction.html](https://www.mathsisfun.com/algebra/matrix-introduction.html)." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2\n", " 3 4\n", " 5 6\n", "\n", "ans =\n", "\n", " 1 3 5\n", " 2 4 6\n", "\n", "b =\n", "\n", " 1 2 3 4 5\n", "\n", "ans =\n", "\n", " 1\n", " 2\n", " 3\n", " 4\n", " 5\n", "\n", "ans =\n", "\n", " 1\n", " 2\n", " 3\n", " 4\n", " 5\n", "\n" ] } ], "source": [ "a = [1 2; 3 4; 5 6]\n", "a'\n", "b = 1:5\n", "b'\n", "(1:5)' # the same as previuos, but without an extra variable " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Inverse and determinant\n", "We do not use this in assignments, but it is a kind of obligatory to introduce these functions when learning Octave:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2\n", " 1 3\n", "\n", "a_inv =\n", "\n", " 3 -2\n", " -1 1\n", "\n", "ans =\n", "\n", " 1 0\n", " 0 1\n", "\n", "ans = 1\n" ] } ], "source": [ "a = [1 2; 1 3]\n", "a_inv = inv(a)\n", "a * a_inv # the identity matrix eye(2)\n", "det(a) # the determinant" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many more basic matrix operations: [https://octave.org/doc/v4.4.0/Basic-Matrix-Functions.html](https://octave.org/doc/v4.4.0/Basic-Matrix-Functions.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Mathematical functions\n", "There is a number of mathematical functions in octave, such as `sin`, `log`, `exp` (sine, logarithm, exponent), they work with each element separately:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x =\n", "\n", " 0.00000 3.14159\n", " 1.00000 1.57080\n", "\n", "sin_x =\n", "\n", " 0.00000 0.00000\n", " 0.84147 1.00000\n", "\n", "ans =\n", "\n", " 1.0000 2.7183 7.3891 20.0855 54.5982\n", "\n" ] } ], "source": [ "x = [0 pi; 1 pi/2]\n", "sin_x = sin(x)\n", "exp(0:4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sum, min, max of matrix elements\n", "The next operations return\n", "* the sum of elements in each matrix's column\n", "* the minimal element in each matrix's column\n", "* the maximal element in each matrix's column" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 6 8\n", " 5 4 9\n", " 2 7 3\n", "\n", "ans =\n", "\n", " 8 17 20\n", "\n", "ans =\n", "\n", " 1 4 3\n", "\n", "ans =\n", "\n", " 5 7 9\n", "\n" ] } ], "source": [ "a = [1 6 8; 5 4 9; 2 7 3]\n", "sum(a)\n", "min(a)\n", "max(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Remember, that matrices are stored in memory by columns, that is why the default operation of these functions is by columns.\n", "\n", "But if a matrix is one dimentional, either a row or a column, these operations work with all elements of a matrix:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 6\n", "ans = 1\n", "ans = 3\n" ] } ], "source": [ "sum([2 1 3]) # although, we have 3 columns, the function returns only one result\n", "min([2 1 3])\n", "max([2 1 3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How to get sums by rows instead of columns? (use transposition), and how to find the sum of all elements of a two dimentional matrix? (call `sum` two times).\n", "\n", "But you can also type `help sum` to find out, how to get sums by rows instead of columns, and how to find the sum of all elements of a two dimentional matrix by just one call to `sum` with special arguments.\n", "\n", "Answer the same questions about `min` and `max`.\n", "\n", "It is also possible to not only find minimums, but also find an exact position of minimal elements in each column. We will call a function in such a way, that it returns several results, we use square brackets for this before an assignment operator. Some functions may return several results." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 6 8\n", " 5 4 9\n", " 2 7 3\n", "\n", "m =\n", "\n", " 1 4 3\n", "\n", "i =\n", "\n", " 1 2 3\n", "\n" ] } ], "source": [ "a = [1 6 8; 5 4 9; 2 7 3]\n", "[m, i] = min(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`m` are the minimal elements, and `i` gives indices of these elements. The minimal element of the first column is in the row 1, of the second column in the row 2, of the third column in the row 3." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison and Logical operations\n", "Consider the operation `==`. It compares values:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 1\n", "ans = 0\n", "ans =\n", "\n", " 1 0 1\n", "\n" ] } ], "source": [ "10 == 10\n", "20 == 30\n", "[10 20 30] == [10 5 30]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1 means `true`, that is, the statement about equality is true. And 0 means `false`. You see, that for matrices elements are compared element-by-element. Broadcasting also works here:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2 3\n", " 2 3 4\n", " 3 4 5\n", "\n", "a_eq_3 =\n", "\n", " 0 0 1\n", " 0 1 0\n", " 1 0 0\n", "\n" ] } ], "source": [ "a = [1 2 3; 2 3 4; 3 4 5]\n", "a_eq_3 = a == 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are other comparison operations: `~=`, `>`, `<`, `>=`, `<=`, that mean correspondingly: not equal, greater, less, greater or equal, less or equal:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a_not_eq_3 =\n", "\n", " 1 1 0\n", " 1 0 1\n", " 0 1 1\n", "\n", "a_gr_3 =\n", "\n", " 0 0 0\n", " 0 0 1\n", " 0 1 1\n", "\n", "a_gr_eq_3 =\n", "\n", " 0 0 1\n", " 0 1 1\n", " 1 1 1\n", "\n", "a_less_3 =\n", "\n", " 1 1 0\n", " 1 0 0\n", " 0 0 0\n", "\n", "a_less_eq_3 =\n", "\n", " 1 1 1\n", " 1 1 0\n", " 1 0 0\n", "\n" ] } ], "source": [ "a_not_eq_3 = a ~= 3\n", "a_gr_3 = a > 3\n", "a_gr_eq_3 = a >= 3\n", "a_less_3 = a < 3\n", "a_less_eq_3 = a <= 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are logical operations and (`&`), or (`|`), not (`~`). If you write `x & y`, both operands must be true for the result to also be true:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 0\n", "ans = 0\n", "ans = 0\n", "ans = 1\n" ] } ], "source": [ "0 & 0\n", "1 & 0\n", "0 & 1\n", "1 & 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you write `x | y`, at least one operand must be true for the result to also be true:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 0\n", "ans = 1\n", "ans = 1\n", "ans = 1\n" ] } ], "source": [ "0 | 0\n", "1 | 0\n", "0 | 1\n", "1 | 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Not operation inverts its operand:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 1\n", "ans = 0\n" ] } ], "source": [ "~0\n", "~1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is usual to combine comparison and logical operations. Note that for matrices boolean operations work element-by-element:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a =\n", "\n", " 1 2 3\n", " 2 3 4\n", " 3 4 5\n", "\n", "a_from_2_to_4 =\n", "\n", " 0 1 1\n", " 1 1 1\n", " 1 1 0\n", "\n", "a_not_in_2_3 =\n", "\n", " 1 0 0\n", " 0 0 1\n", " 0 1 1\n", "\n" ] } ], "source": [ "a = [1 2 3; 2 3 4; 3 4 5]\n", "a_from_2_to_4 = a >= 2 & a <= 4\n", "a_not_in_2_3 = a < 2 | a > 3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## More on indexing (logical indexing)\n", "Imagine, we want to get all elements of some vector, that are greater than 10. Let's start with finding which elements are greater, and which are not:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x =\n", "\n", " 1 10 2 20 3 30 40\n", "\n", "x_gr_10 =\n", "\n", " 0 0 0 1 0 1 1\n", "\n" ] } ], "source": [ "x = [1 10 2 20 3 30 40]\n", "x_gr_10 = x > 10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can use a `find` function. This function takes a matrix and find indexes of all nonzero elements: " ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 1 4 7\n", "\n", "ans =\n", "\n", " 4 6 7\n", "\n" ] } ], "source": [ "find([10 0 0 3 0 0 -4]) # just an arbitrary example of searching for non-zero elements\n", "find(x_gr_10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `find` function combines well with logical matrices, because it allows finding indexes of all true values. More examples on this:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans = 2\n", "ans =\n", "\n", " 2 3\n", "\n" ] } ], "source": [ "find([100 200 300] == 200) # the 2nd element is 200\n", "find([100 200 300] >= 200) # the 2nd and the 3rd elements are greater or equal than 200" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So, now, we can finally get al elements of `x` that are greater than ten" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x =\n", "\n", " 1 10 2 20 3 30 40\n", "\n", "x_gr_10 =\n", "\n", " 0 0 0 1 0 1 1\n", "\n", "ans =\n", "\n", " 4 6 7\n", "\n", "ans =\n", "\n", " 20 30 40\n", "\n" ] } ], "source": [ "x # to remind the value of x\n", "x_gr_10 = x > 10\n", "find(x_gr_10)\n", "x(find(x_gr_10)) # we know indexes of elements, so we can just index by that indexes:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's now write it as one line and let's also modify elements:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ans =\n", "\n", " 20 30 40\n", "\n", "x =\n", "\n", " 1 10 2 10 3 10 10\n", "\n" ] } ], "source": [ "x(find(x > 10)) # see all elements, that are greater than 10\n", "x(find(x > 10)) = 10 # assign 10 to each element" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More examples of logical operations inside indexing:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x =\n", "\n", " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n", "\n", "x_div_3 =\n", "\n", " 3 6 9 12 15\n", "\n", "x_from_5_to_10 =\n", "\n", " 5 6 7 8 9 10\n", "\n", "a =\n", "\n", " 10 20 30\n", "\n", "b =\n", "\n", " 100 200 300\n", "\n", "ans =\n", "\n", " 200 300\n", "\n", "x =\n", "\n", " 1 2 4 4 5 7 7 8 10 10 11 13 13 14 16 16\n", "\n" ] } ], "source": [ "x = 1:16\n", "x_div_3 = x(find(mod(x, 3) == 0)) # filter elements that are divisible by 3\n", "x_from_5_to_10 = x(find(5 <= x & x <= 10)) # all elements from 5 to 10\n", "\n", "# cross matrix indexing\n", "a = [10 20 30]\n", "b = [100 200 300]\n", "# we find elements from a, that are greater than 20, and take corresponding elements from b:\n", "b(find(a >= 20))\n", "\n", "# remember, that you may assign to an indexed matrix\n", "# in this case you assign only to indexed elements\n", "x(find(mod(x, 3) == 0)) = x_div_3 + 1\n", "# so, all elements, that are divisible by 3 increased by 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's now repeat the same examples without `find`. The idea is, that when you index by a logical matrix, the find is made automatically (!) " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x_div_3 = [](1x0)\n", "x_from_5_to_10 =\n", "\n", " 5 7 7 8 10 10\n", "\n", "a =\n", "\n", " 10 20 30\n", "\n", "b =\n", "\n", " 100 200 300\n", "\n", "ans =\n", "\n", " 200 300\n", "\n", "x =\n", "\n", " 1 2 4 4 5 7 7 8 10 10 11 13 13 14 16 16\n", "\n" ] } ], "source": [ "# x = 1:16\n", "x_div_3 = x(mod(x, 3) == 0) # the same as x(find(mod(x, 3) == 0))\n", "x_from_5_to_10 = x(5 <= x & x <= 10)\n", "\n", "# cross matrix indexing\n", "a = [10 20 30]\n", "b = [100 200 300]\n", "b(a >= 20)\n", "\n", "x(mod(x, 3) == 0) = x_div_3 + 1" ] } ], "metadata": { "kernelspec": { "display_name": "Octave", "language": "octave", "name": "octave" }, "language_info": { "file_extension": ".m", "help_links": [ { "text": "GNU Octave", "url": "https://www.gnu.org/software/octave/support.html" }, { "text": "Octave Kernel", "url": "https://github.com/Calysto/octave_kernel" }, { "text": "MetaKernel Magics", "url": "https://github.com/calysto/metakernel/blob/master/metakernel/magics/README.md" } ], "mimetype": "text/x-octave", "name": "octave", "version": "4.2.2" } }, "nbformat": 4, "nbformat_minor": 2 }