 So let's talk about matrices, the wonderful, very useful, mathematical form of a matrix. There are a few differences between a matrix and computer science, or at least here in Julia and the mathematical variant, but in the end it all works out nicely. Now the first thing I just want to get to talk about is what is a vector and what is an array. So I'm asking this Boolean question, is an array of 64-bit integers in a column format, is that equal to a vector of 64-bit integers? And the answer is going to be true. Let's toggle all of these, so we just get rid of all the output. There we go, there we go, there we go, where are we, where are we, where are we, there we go. So if we run this again, we see that it is true. So an array in a column vector there is exactly the same thing. But now let's ask an array of 64-bit integers in this row format, is that equal to a matrix? And indeed we are going to get the true back. So even though we've referred to this as the row, initially it actually means that we are talking about two dimensions. And I'm not talking about the dimensions of a vector. If I have a column vector with ten values and ten elements, that's a ten-dimensional array. Yeah, we're just talking about rows and columns referring to the two. But as soon as you have a row, I mean a row does have columns in it, so it is going to say a two there. So if it is an array, it doesn't matter if these are floats or integers, but the two there actually means it is a matrix. So let's create our first matrix and we're going to do it this way. Remember when we did not put any commas in between, that meant that it was a row. So this one, two, three is going to be a row. I use the semicolon to jump to the second row, four, five and six. Semicolon to jump to the seven, eight and nine. So there we go, it's a three by three array and you see 64-bit integers, all of them, and the two again. So even if we just had one row, that will still be a two. So now we have three rows and three columns. Now there are other ways to go about this. Look at doing this. I have these square brackets on the outside. I have the semicolon separating the two. But inside of that, instead of not having commas, I do have commas now, but I also have these inner square brackets. What do you think is going to happen there? Well, we get this six element array as far as just a column is concerned. Okay, so that is the output that you're going to see from there. Now let's go on. Let me do the exact same thing. So I still have the commas, I still have the square brackets inside of the largest set of square brackets, but instead of a semicolon, there's just a space. So that's another way to go about it and look what I did now. It took this one, two, three and made column vectors, a column vector out of it. One, two, three and then four, five, six. And that is just because there's a space there now and not the semicolon we had there. So remember that little difference. Now let's mix things up. Now I'm going to have the inner brackets with the outer square brackets. I'm going to still have the semicolon, but now I'm not going to have the commas there. So what's going to happen there? Now this is all for version four, anything after version three, I should say, up till now that is up to 0.4.2. I get these as two rows. The one, two, three will now be across a row. Four, five and six will be on the next row. Now, once again, we're going to do this, no commas, no semicolon, but still the inner brackets, inner square brackets. And this will be almost the same as doing this with everything in. This one with nothing in it is going to give me this one long row. So be aware of your notation in Julia. You're going to get different things depending on your use of square brackets, your use of commas and your use of a semicolon or a space. Now, let's repeat some rows. These are obviously going to be rows. There's spaces in between. So take this one, two, three, which is a row vector and repeat it three times. So we're going to get one, two, three, one, two, three, one, two, three. What about this? So that was doing it along the rows, but what about doing it like this? I can specify row and column. So if we do this, it says make one row of it and three columns. So there's my first one, two, three, my second one, two, three, and my third one, two, three. Good. So what will happen if we specify do it over two rows, rep, mat, two rows and three columns? I think you know what's going to come. So I have the one, two, one, one, two, two, three, three, one, one, two, two, two, three, three. So what it did was it did this one, two, three, one, two, three, because this was specified as a column vector. So that's what it wanted and it wanted two rows of that because there's a one, two, and three. The next row of one, two, and three. And make three columns of all of that. That's a column, that's a column, and that's a column. Good. So if I had one, two, three with the spaces in between and now make two rows and three columns of that. There's my one, two, three, another one, two, three, and another one, two, three, so three columns of that and then two rows of that. Excellent. Now a matrix is indexed by its row and then by its column number. So if I call a computer variable here matrix MAT remember that what that was we created it way up here. One, two, three, four, five, six, seven, eight, nine and three by three matrix. If I were to just refer to it to it MAT and then the square brackets this is going to be the row value that's going to be the comma value. So give me the element that is in row two column number three and then indeed that was the six. Now we can almost get the same thing here just get index matrix two comma three and we're going to get back that six. Now let's just make a new column I'm going to use the random function and I'm going to say six comma five. So between the values of zero and one inclusive, I'm going to get pseudo random selection of values in six rows and five columns. So there we go big six by five matrix of 64 bit floating values. And I've called that met underscore and now let's make a random in function. So that's slightly different. So that means it comes from the standard normal distribution that means a mean of zero in a standard deviation of one create for me from that a three by three matrix. And there is my three by three matrix. So that's the use of Rand and Rand in just to create a matrix. Let's create a tensor. Well, let's call it a tensor for now tense underscore and and that is Rand three comma three comma four. That means three rows, three columns, but it's going to be four values deep. And this is going to be the front one three by three matrix. And you see this colon colon colon colon one. So that's the front one behind it stands this three by three matrix. It stands as three by three matrix. And this stands a three by three matrix. You can always think of this as elongated or rectangle at least three by three on the front side and four D just to show you what the type of this is. And it is an array 64 but floating values. And now for the first time we see something else is not one, which was just a column two, which was a row or then a two by two or row and column matrix. Now we see we've added this third dimension. So let's create these two matrices just to show you how Julia handles matrix multiplication. So I have these two matrices one, two, three and two. So one, two would be a row three, two would be a row and one, three, two, four, three, two. And it's the second one that is printed to the skin here the two by three. Remember the rules of matrix multiplication, the number of columns in the first matrix must equal the number of rows in the second matrix. And the result, the result in size. So there we go, the two, the two there is equal to the two there and the result will be this outside but it will be a two by three matrix. So you can only do it when this column size is the same as the second one's row size. So I'm saying matrix A times matrix B. And there we get, well let's just run that and then run the multiplication and there is our multiplication. We can also do element wise operations. So that was matrix multiplication. So I'm going to create these two arrays here. Let's print them to the screen or I should say just matrices. So there they are two, three by three matrices. You see them there, 64 bit integer values in both. And instead of multiplying them, I'm using this dot multiply for syntax. That means it's not normal mathematical matrix multiplication. I'm taking one element and multiplying it by the same element in the other matrix. It's going to be one times two to give you two, the three times three to give you nine, etc. So it's element by element. And indeed they receive a two and we see the nine. Now we can ask element wise questions. Let's just use the ran function. So between zero and one, five by five to five by five matrices. I'm asking on an element for element basis is the value in matrix are smaller than the corresponding element in matrix s. And I'm going to get this matrix of Boolean values when it is smaller. Again, as we did with the column vectors, I can say, well, take the first one and check element by element. If its value is smaller than what is in there, that's going to return something for me. And if that is, if that is so, I'm going to add the, or that's values is true. We're going to attach the value hundred there. So I can now do that element wise operation again. And we should see false everywhere because everything in the mat are is now going to be larger. Let's just look at the dimension sizes, etc. Of other matrix. Now remember a matrix B, I can ask what its number of dimensions are by this indoms. Function and it returns to there were rows and they were columns for the tens underscore and remember there were three. We had this depth to it size returns this tuple and we'll talk about tuples two comma three. So it's got two rows and three columns. See the difference between the number of dimensions there and the size of it. And if we ask for the size of this tense underscore and of course we're going to get a three come three come four. I can ask for the size of the number of rows and met B and that is what a rose refers to rose is the first dimension. And it tells me, well, there were two of those. I can ask how many columns they were. Well, there were three columns. And I can also ask the length of the matrix six because it's two by three. And that gives me all of those. Now let's have a look at how Julia counts these six. Where do they go? So I'm going to have this for loop inside of a for loop. The outside is going to run from one to the size of the rose. So first is going to run through the first row. And in the first row, it's going to execute this little for loop and then run to the second row. And inside I'm going to have for the columns. So it's going to run from one to the columns. So I'm printing element in a row with i and column. There is the value at that position ij. Look at that section of a for loop and you see very quickly how it runs. Element in row one column one is one element in row one column two is three element in row one column three is two. So let's check that. Let's just run that and there we go. We can see the rows are one three two columns are one and four three and three two and two. So you can work out exactly where the element the six elements are. So we've got this end to sub function that returns the row and column have values of an element specified by its index. So now I'm going to run from one to six remember the length of the matrix was six. And I'm going to say element i is matrix bi and is row and column value of such. So this is going to work element one is one and has a row and column value of one comma one. So that is what this end to sub returns for me. So if you look at these two these two this for loop inside of a for loop and this for loop down here. It will show you exactly how Julia goes about numbering these elements in a matrix. Now remember I said the size returns a tuple so I can actually give each tuple a computer variable. So I'm going to use RWS and CLMS for the size and remember that was a two by three. So RWS is now two and CLMS so there will be rows and columns is three. So I can print the number of rows are two and the number of columns are the number of columns. The number of columns is I should say proper English there. There you go you can work out from this tuple or you can give each of these values in the tuple it's in computer variable. Let's just have some special matrix functions the identity matrix I and we're going to make it five by five. There we go once along the main diagonal zeros every off of the main diagonal that's a five by five identity matrix. I can make a matrix of all zeros and specifying the number of rows and columns. There we go a matrix of all ones specifying how many rows and columns I want. I can do a diagonal matrix and I can tell Julia what I want on that diagonal here. I want to use a collection of these of this range from one to five with a step of one. So along the main diagonal along the main diagonal I'm going to get one two three four five. I can also specify what I want on my main diagonal by just using an array of values that should go inside of and then I'm using pi there that should go inside of the main diagonal. And there we have three negative three and this shorter version at least of the value of pi there. So count the number of zeros in something that has a main diagonal with values of one to five. That's going to return the count of the non zero numbers. And remember on a diagonal matrix everything is zero except everything on the main diagonal and there are only five values. So count the non zeros I should be clear. Now a matrix of Boolean values indeed we can have that. So just three by five set of true values a three by two set of false values. That's all possible. Now let's slice up an array. That's quite a useful thing to do and but can be a bit tricky. So let's make this matrix mat underscore slice. It's a five by six five rows six columns using the ran function. So that's very from zero to one inclusive at CETA random selection there five by six matrix we can look at it there. Now I'm going to slice only by the first column. That's all I want to see. And remember it's a rose comma columns. So and I use these square brackets because I'm asking the value at that index. Now we can see the column values one so it's certainly going to be this first column. But I want all the values in that first row and I can use short hand for that by this colon sign. So it says all the values in row one comma. Oh, that's the row in the column values. Let's have a look what it returns. So it says that's a rose. So all the rows. So that would be a row. That would be a row. That would be a row. That would be a row. You can see how quickly one can get confused between the two in column one. So all the rows just in column one. Now another way to look at it is to say go from one to the end. That would be same as just having used that colon sign, but I can say go from one to the end. So that's all the rows. So that includes all the rows, but just for column one. And we get the exact same thing back. Now let's go from row one and two for all the columns. This row one and two for all the columns. And there's row one and row two for all the columns. Now let's take the transpose of a matrix. Remember transpose makes all the values in the row makes them column values. All the column values in the row value. And we use this apostrophe, the mat underscore slice for that apostrophe. That gives me the transpose. And that's exactly the same thing as calling the transpose function on this matrix. We're going to get exactly the same thing back. There's an inverse of the matrix. So I can have this matrix one, two in the first row, three, four in the second row. And I can just ask for its inverse. And you see the inverse there. Remember, we can solve a linear system of equations in this format. I'm going to make this matrix A of coefficients. My matrix of unknowns x there and my solution column vector there, I should say B. So let's cheat a little bit. You can have a look at this. So three times two is six minus two plus eight, that gives me 12. But you can see all these values in brackets here. Two to two, one, one, one, four, four, four. So I've cheated a bit just to make a set up like this. But imagine I put x in the place of two, y in the place of one, and z or z in the place of four. So it will read three x minus two y plus two z equals 12. And I have the system because the x's are the same for all three equations. The y values are the same for all three. So from that, I can make this matrix of coefficients. So I just take the coefficients three, negative two and two, there they are, three, negative two and two. Two zero, negative two, two zero, negative two, three, one, three, three, one, three, there they are. And the solutions are twelve, negative four, nineteen, twelve, negative four, nineteen. Now I can write it like this. A, which is this, times x. Now this x is not just x, it is a column vector which states x, y and z. So if I take A, which is this, times x, y and z. So it's a three by three matrix times a three by one matrix that equals a three by one matrix and there it is. So I can divide both sides by A just to get x on its own, which is x, y and z, but in matrix format that means taking the inverse. So if I take the inverse on both sides, I'll land up with this, x equals A inverse times B and that will give me the values for x, y and z. So let's do that in Julia. So I've got my matrix of coefficients here, three, negative two and two, which makes up a row. So there's the spaces in between. The next row comes after the semicolon, etc. And I have my column a vector of my solution. So I have A and B there, there they are. And instead of taking the inverse, there is the short hand, the short cut in Julia that you can get used to. So A and then it's this backslash B. And that gives me my solutions which should read 2, 1, 4, just as I had them there, 2, 1, 4, it all works out. But that is exactly the same way, which takes a bit longer with a Julia code to say the inverse of A times B. That looks like that's still 2, 1, 4. So this is just the short hand notation for A inverse times B. Now a raise of a vector or matrix form can be concatenated. Let's do that. So I've got matrix A and matrix B here, mat A, mat B, 2 by 2 matrix, 2 by 2 matrix. And I'm going to horizontally concatenate them. First matrix A and then matrix B. You can well imagine what's going to happen. There's my 1, 2, 3, 4 there, my 10, 11, 12, 13 there, and it's concatenated them horizontally. Okay, that would be the same as just doing that. Remember, there's a space in between the two. In other words, this is a row that is being produced, and you see we get exactly the same. We get v cap, which is a vertical concatenation. You see what happened there, which is the same as using a semicolon in the array format there. Good reshaping. Let's take a linear and just an array of values. We're going to collect from 2 to 12 in increments of 2. So there we go, 2, 4, 6, 8, 10, 12. And I can reshape them. So reshape the array as a 2 by 3. So this 2 by 3, 2 times 3 equals 6. So it better work out to have the six elements there, and it'll reshape that for you into a 2 by 3 matrix. Not a bang, so this is not permanent. So we can sort. Remember, let's make a matrix, we call it sort underscore mat, and it's going to be a ran value. Choose from 1 to 10 in a 4 by 5 pattern for me, please. There we go, 4 by 5 matrix of random integers. See the random integers between 1 and 10 inclusive. I can sort them by dimension 1. What does that look like? So let's just have a look at it. So we had 7, 5, 8, 8, 5. 5, 5, 10, 10. And what has it done here? Look at the differences between these two matrices. So it went down every single column. So we have a 7, 5, 3, and 8, and it put them in order 3, 5, 7, 8. 5, 5, 3, and 7 down this column, and it made it change the rows. So it goes column by column, but it changes the rows in that column. So that's what I mean by rows here, even though we put a 1 there. So if I use the 2 there, it is going to go this way out. So let's just go back up so we can see our matrix there. It was 7, 5, 8, 8, 5. So for each of the values in these 5 columns, I'm going to sort them in a setting order which makes it a 5, 5, 7, 8, 8. So don't get confused between the way that this sorting is done. Let's use rank, determinant, and trace of a matrix. Let's create this 4 by 4 matrix very quickly. We're going to rank the matrix, which is something we use in linear algebra. It has a rank of 4. The determinant, which is a difficult thing to work out in a 4 by 4 matrix. Doing that by hand takes a phenomenal amount of time. And very quickly in Julia, we see the determinant at least is not 0. And then the trace just adds the values on the main diagonal. It can work out the trace for us very quickly, 25. Now we can do the trace by hand. I've just put in just for fun a little bit of some script here. Remember size returns a tuple to me, it's going to be the number of rows and the number of columns. I'm making this global variable. It exists outside of the 4 loop. Call it my underscore trace, and I'm setting the value to 0. So my trace, which starts off at 0 inside of this loop, and remember the loop is going to go from 1 to the number of rows. And we're just going to choose the value at index ii. So the initial is going to be index at row 1 column 1, then a row 2 column 2, then row 3 column 3, and we're just going to keep on adding them with my trace. My trace is something that existed outside. So I can just call it directly in this print statement. Please print my trace for me. And lo and behold, we see it is also 25. So that's a lot of fun with matrices, and obviously it gets a lot more powerful than that, just to give you some idea of how to work with a matrix. Now next up, we're going to look at just a bit of set theory and its calculations as far as Julia goes.