 All right, thanks. I will just close the chat because it always stays on top. I can't see anything else. So, okay, we have biostatistics, IT support, quantum computing, a lot of computational fields, of course, since this is a course about Julia and mathematics and systems analysis control. Okay, yeah, and of course, you know, what the packages you need is part of what you want to know. So maybe a better way of formulating the question would have been what things you need to be able to do or want to be able to do what should the libraries do. But yeah, let's move on. Of course, you can continue typing there. My terminal open Julia and now I already have iJulie installed. So just start the notebook or well start run the notebook function to start the Jupiter notebook system. Okay, yesterday we went through most of sections one through four. You can, if you're interested, look through some tips in section four. But the most important part there is the mapping and the dot syntax. And we'll finish implementing the simulation from section four before we go on. And then we'll have we will go through packages and plotting, which is mainly how to use packages. I mean, we've been doing that a lot already, so it will be relatively fast. And then we'll introduce one or a set of packages specifically, which is for plotting, because that is something people have to do a lot. And it's quite convenient. So yeah, we'll spend some time on that. We'll basically skip strings and IO, unless we have time for it at the end and people request it. But you can look through it on your own. So this we already showed you how to do later in strings and how to do well, at least how to do raw strings. So if you want the refresher on that, if you want to remind yourself how to do that, you can check this strings and IO section. It also has a section on how you actually an exercise on how you can write the configuration of the simulation state to a file and then reread it. And that should work with any any structs you have defined any array of structs you have you have created. That's called JLD or actually libraries JLD2. That's very useful here. But then I guess the main part of today will be creating packages. And that section has how we how you can write your own package. And what is the general structure of a package in Julia and how you can create how you can write tests for your package while you're working on it. Okay. And then probably we'll have time for something at the end. So there is the option between both strings and IO is one option performance. We hope to have time to do anyway. But it might be one of the optional sections. So we'll have a poll at the end. This ecosystem is only a list of packages where you can look for things. I'll point that out again later. There's meta programming. So essentially how to program how to write something that writes the code. How to write macros. So that is very useful when you're getting to more complicated expressions or symptom vectorization, which is of course tied to performance, but also kind of separate topic. There is is it in performance, there's MPI exercise, I think in performance. So if you're interested in MPI, we can also cover that. Okay. But let's get started. So I'll move this. Actually, I'll first go and start my demonstration notebook. And so where we'll be continuing from yesterday is in this control flow section, where we have some, we continue the simulation a little bit. And then we have a small exercise, basically finishing up the simulation program. So the first thing I will do is essentially go to the end of my notebook and copy everything we have for the simulation so far. And you can find this in, I'll just show you, made it full screen. And now there's some cool powers on the way. Okay. So in the control flow notebook, after the dot syntax, exercises, there is back to the simulation. This is slide number, is it numbered? Well, it's right after the dot syntax part. So you can copy stuff from here or you can just execute this cell and continue from there. So I will just run it and that will define everything we wrote yesterday for the simulation. So we now have such a thing as plant again, it can be in the state, uninfected. You have to give it the number zero. You could make this, you could, you could define a function, of course, that builds a plan without you having to specify this number zero every time. So yeah, you can create those sort of convenience constructors, which are often quite useful. But yeah, that works now. And since we defined this thing we did at the end, we replaced how you show, how Julia shows the plant type, replaced it with printing these boxes. It now immediately prints an uninfected box here. Okay. So now to really run the simulation, we'll need a grid of these plants. So that all the, I mean, all the plants have neighbors and plants tend to grow on two dimensional surface, although not always on a strict grid. But in this simulation they do. But yeah, we'll just create one here. So let's make a 16 times 16 matrix of plants. We'll call it plants. So first, this is the most convenient way I have figured out how to do this. So we will create a matrix of plants. And you need to give it an initial state, but that can be undefined. So undefined is undefined. Unfortunately, if you give it just one plant variable, it doesn't, it can't figure out what to do. So, and then the width and height. So 16 times 16. So this creates a matrix of plants, but they're all in this undefined state. And then we can run a follow before I in, then we'll just go from 0 to 1 to 16. Or we could do size of the plants in the first direction. So the number of rows, number of rows in a plant, in the plants matrix, which is 16. So this is exactly the same thing. But if we happen to change this number here, it is more convenient to then refer to it this way. Another follow before J in 1, 2, and again, it would be 16. But we'll just refer to it as the second dimension of the matrix. So the size of plants gives you, maybe I should actually run this size of plants gives you 16 times 16, or it is a tuple of two numbers, 16 and 16. And this will just take the first one of those, which is 16. This will take the second one of those, which is also 16. Okay. So both of these follow-ups go from 1 to 16. Let's type the ends in. I just like to do that to make it kind of formatted properly. And then inside here, we want to do something with the plants. So we don't want them to be in the undefined state. By the way, this is how you refer to a location in a matrix. It's i, first index, comma second index. Okay. So we're going to place a plant that is uninfected. And the number is just zero. Okay. Plants not defined. Oh, the type, yeah, with capital P plants is not defined. Because it is just plant. Okay. Oh, this didn't print anything. Because the last statement is an end just there. So now it prints it properly. And maybe this makes it clearer why we wanted to implement this whole show function. Because now if we had a huge matrix of these plants, it would print for each of them, it would print the word plant. And then in parentheses, uninfected comma zero. And that would be a huge, huge section of text that will be completely unreadable. So this is much nicer to look at. And it gives us information about what's going on. Now, in order to have a simulation where anything happens, we want to have one infected cell there. And I just plop it in the middle so that eight comma eight. And that one is let's just set the status actually. So we will make it infected. Okay. And what didn't work? Plant not defined. No, because it's plants. Okay. Yeah. The same mistake except the other way around. Okay. So now it's printing this. In fact, it's printing the status of this plant. That's what it's returning at the end. So let's just type the plants to return the matrix again. Okay. Great. I hope everybody's with me. And I hope you are typing along. That is kind of this kind of thing is the most useful if you are typing what I'm typing. And if you get ahead of me, play around with stuff, if you get behind, then look at the notebook and copy this into your own notebook. But yeah, it's kind of like me writing into a blackboard if this was a lecture about anything other than coding. That would be what I would be doing. And you would be taking notes. So it just goes through of course people are somewhat different than you do what works for you. But it is very useful for most people to type it yourself. Okay. But yeah, just mentioning both why I'm doing it this way. And because I didn't remind you what you should be doing, I need to remind you at some point. Okay. So now we have this matrix of these plant objects. And we want the disease to spread from this one to its neighbors with some probability. So to do that, did we write an interact function already? I don't think we did. Yes, we did. We did it. We did go through it yesterday, right? Yeah, because it's in the previous notebook. So we have this interact function. Oh, yeah, no, I remember we did go through it. That takes two plants, this plant and a another plant, a neighboring plant, and an infection rate. And it will, if the other plant is infected, it will make this plant infected with the probability given by the infection rate. So that function is already defined. And we can essentially, well, we can do the interaction between these two plants, for example, by running interact. Now, the one in the middle is 8,8. So let's do 8,9. It's either this one or this one. I never remember which way the indices go. The first one is the index of the row and the second is the index of the column. Okay. Well, then if I wanted this one, then it would be 8,9. Okay. And 8,8 is the infected one. And the infection rate is whatever we want, but let's say 0.05. Actually, let's make it 0.5. Okay. So the first time it returns zero. This function doesn't really return anything. So, well, it returned this infection time, maybe. But what I wanted really to do is to print this plant. Okay. Well, it is already infected. I ran it twice. The rate is 0.5. So it's almost certainly going to be infected after 2, but 75% probability it's going to be infected after running it twice. Okay. So this is basically what we want to do for every pair of plants in the simulation. And I'm just going to print the matrix again. So I'll type through the update function that does this. And then there is an exercise of doing this. I will do this vertically and there is an exercise for doing it horizontally basically. So this is essentially a reminder of everything that we did yesterday. So a function. Let me start from the beginning. Just define a function with the function keyword. We will call the function update and it ends with an exclamation point because it updates the plants. So it changes one of the inputs, one of the parameters. The first parameter is plants. That's the matrix of plants that we want to update. We could specify the type. So matrix of plants, matrix of type plant objects. Let me check type of, so this is very convenient. If you type type of plants, this is exactly what I should be writing there. So this is the type of plant. It's also array plant 2, array plant comma 2. But yeah, so matrix plant is the type I should be writing there. Then we'll need an infection rate. We'll also need the time it takes for the plant to recover. Recovery time, put that first. We'll need a death rate, how likely it is for, I wonder if I can make the rose wrap. The probability of a single plant dying when it's infected in a single time step in the simulation. And finally the infection rate. So this has three parameters, four parameters. The matrix of plants, the recovery time, death rate, and infection rate. Okay, type in the end keyword and start typing the function. So the first thing we'll want to do is to update all the plants as they are, I mean in place, so without interaction with the neighbors. That function we also called update. But the update function takes a single plant. So not a matrix of plants, but a single plant. It takes recovery time and death rate. So this is the function we wrote yesterday and it's here. Now, because it takes a single plant, what do we do too? So we could write a for loop that goes over all the plants, fine. A slightly more convenient option is to put plants here. This is a matrix now, so this will not work as such, but then just add a dot. And it will run this function for every element in the matrix plants. Because this is just a single number and this is just a single number, it knows that it wants a copy of these two numbers for every element. And it will go through every element of this first one. So it's running the broadcast function. That's what the dot syntax does. So it's broadcasting these two parameters to be the same size as this one. Okay, so that's convenient. And then we will need to loop over all of the neighbors in the horizontal direction and update. So have every cell of every plant, every plant in this matrix interact with it's all of its neighbors. So essentially we'll do what we just did with this pair. But with, well first this pair, and then this pair, and this pair, and so on. Ending up with this one. Okay. And the way to do that one way of thinking about that is that every, so you take the leftmost one in every pair and that will index the whole pair. So this is the only one that doesn't have a neighbor on the right. So we will just have the number of columns minus one of these pairs. Okay, to make things a bit easier, I'll take the, actually this is nx. I will just take the size of the matrix into two short variables. So just what we did before, size of plants. And I'll take the first one into nx. And the size of plants. Second one into ny. Okay, and now I can write a slightly shorter for loop. So the index j, let's say that is the row. And the pairs that I'm taking are in the horizontal direction. So I will just go through all the rows. So ny. But I will not go through all the columns. So I label the column, or I in fact labels the pair in the horizontal direction. So I will not go through all of them because the last one doesn't have a pair on the right side. Everyone else has a pair on the right side. So I'll just go through up to nx minus one. So nx minus one is the last one. nx is the last one. So nx minus one is the second to last one. So it's this one. Okay. And what do we do with this? Well, the two plants in the pair are, one is at i and j. And the other one is at i and no, sorry, i is the second index here. So i plus one and j. So they both have the same j, the both same row, but they have a different i. Okay. So I want to run the interact function with this pair of plants. But I also want to run the interact function with, because the interact function only updates the first one, not the second one. I want to run it in the other direction as well. And it also needs the infection rate. Okay. So fill in the interact function here, infection rate. Okay. Now there's one more important detail. So something that could happen here in a single time turn is that this one, because this starts from the left, goes through all the pairs and ends up with the one on the right. This one could infect this one. And then when you're running running this function, this function for the next index i, this one would already be infected. So it could already infect this one. And then this one could infect this one and so on. So you could get a cascade on infections in a single time step. And that's not okay. So that's not what the simulation should do. Each neighbor should only interact once with each of its neighbors. And it shouldn't know about the future state of the next state of the neighbor. It should only know about the state in the previous time step. So the way the plants are now determine what each plant is in the next time step. So to avoid the update changing the result for the next update, we'll record the state and make a copy of the state of the plants before any update, any changes. And for that we'll use the deep copy function. So the deep copy doesn't just assign the matrix plants to another variable called old plants. It actually makes a copy so that when you change old plants, or when you change the important thing is when you change plants, old plants doesn't change. So this is just a copy. And now we can use this old plants variable here so that when the pair is interacting, the thing that changes doesn't know about the new state of the neighbor. Okay. Hopefully that was a sensible explanation. Okay. Now that defines an update function. I'll just empty that so that the cells are in order. And now we can run the update function on the plants array. And we'll need to give it a number of time steps it takes for a cell of a plant to recover a death rate, let's say 0.2% and an infection rate up again, 0.5 which is a very high infection rate. So we'll see quickly that it works. Okay. So now this is actually, like I said, I got mixed up with the directions. So it's actually going down, it's spreading down. It should also spread up. Yeah, it is spreading also up. Okay. And now these cells in the middle, these plants in the middle are recovering. So they are no longer infected. Okay. Now there is a probably relatively quick exercise, which is to fill in the details. So there's some comments that I didn't write down, but otherwise this is exactly what I just did. So in exercise three in control flow, there is another loop that does that should do the same thing. But you know, in the instead of the up down direction, the left, right direction, instead of vertical, it should do it horizontally. Right. So and then we have an exercise extending base.show to a matrix of plants. So just to set that up, I will see what happens if you run print plants. So if you type plants, it will show up properly, like we did boxes. But if you type print plants, it kind of uses this sort of matrix printing representation. So spaces between, between elements and then for every new row, there is a semicolon. That doesn't look great. So if we are turning this, well, let's just keep that. If we are turning this into a package and we want to, well, we want to put this into a file or a bunch of files for people to download and run on their own to do the, to run the simulation, we will need to use print instead of just this thing that we can do in a, in a notebook. So we will want to implement this properly. And that is the second exercise. Now, I would say you don't have to finish the second exercise. But fine, if you do good, if you do, there is also some extra stuff that you can take a look at. But let's say we'll give you 10 minutes to do these exercises, and then we can take a break. So, well, yeah, I guess that's all I need to say. So like before, can you put up a green check mark when you are done? Let's say when you're done with the first. So when it would be worth, when would it be worth to write code in Julia? Instead of Python, for example, okay, yeah. If you're fluent in Python, it's, of course, probably faster to write things in Python. But Julia is actually a pretty good language in that it doesn't take a lot of time to, I mean, it's basically as fast to write as Python. And I mean, if you're comparing to something like C, or Fortran, or C++, where it's, it will take you a lot more time to write anything. Julia solves the two languages problem, because generally, if you have like, you need a language which is easy to write like Python, and the language which is fast like C. So you need two languages. Whereas Julia is said to solve this like problem, because it's fast and easy to write and easy to read. So it's, I think the motto was at some point, works like Python runs like C. So it's like as easy to write as Python and as fast as C. So it's like efficiency matters from your Python, and also Julia is very good at interoperating with other languages. So if you have a code base like the whole interface in Python, you don't need to like replace that. You can call that from Julia and have the more computation-expensive parts in Julia, for example. So basically, when you would want to use Julia rather than Python is when you want good performance, when you want your code to be fast. And when you're writing something yourself rather than using a library that's already been optimized. Well, now if there is a library in Julia that's much faster than in Python and you need to call it to run fast, then of course, you probably want to use Julia anyway. But if you're using TensorFlow, for example, then probably you might as well use it from Python. If you are developing machine learning libraries, you need them to be fast and you don't want to write them in C and then call from Python, then I would use Julia. For example, since I noticed there were a few people from physics or what a few people from computational fields, Julia has a very powerful and very good ecosystem for differential equations and like modeling. And indeed, because of the interoperability, Julia actually has also can call like all like solvers which have been written since the 50s, 40s or when people started solving differential equations on computers, has also like wrappers for those like FORTRAN and C code and solvers so that you have like a huge, huge toolbox of solvers for differential equations and has also like this differential equations and machine learning combination. So like also a very like powerful like this is system very close to the topic of the next part. So let's finish up this exercise and the simulation before we go on. So here's the first exercise. So I've already added the actually what I did was just to add to my own notebook to add this part at the end. So it has the correct number of parameters and it specifies that it needs to plants needs to be a matrix of plants. But yeah, this is the essential part of the exercise. So just like we did here, there are one few pairs than there are plants in a row. So and in this case, so here we of course, we did columns, we did rows, here we want to do columns. So we do ny minus one instead of nx minus one. And this one just goes to nx. So yeah, this is, I mean, this essentially is already the reminder, but yeah, just quickly so that you can you remember how to type a follow that goes starts from a value and ends up at a not a value. And so, you know, this essentially was a follow doesn't see, for example, an infortune, or do look doesn't fortune. Okay. And then we again want a plant. So this needs to be in the plants variable, because it gets updated. So not the old plants. And let's take the ij again first. So where's the neighbor? Well, I mean, it's the same as above, but we put the plus one instead of i plus one, we put a plus one. So like this, j plus one, like this. And add the infection rate. Okay. And then the other pair is basically the same except we switched in this is around. So ij plus one old plants. So I kept writing, even though there was a parentheses closing there. So so now it looks correct. Okay. And then I and J. So just the same indices, but the other way around infection rate at the end. And that's it. Now we don't have any infected cells here. So let's go back and redo the cells. And now it's spreading very fast to all directions. Now much more realistically, this should be something like point one. I don't know realistic to what this is not a super realistic simulation of any kind of infection. Okay, it just died. Yeah, we'll play around with this a bit more. Okay, in the next section here, it's actually spreading. But it's not the infection is not doing great. So this was not an epidemic. Okay, let's move on. Okay, we'll do the other exercise as well. So this is what happens when you print plants. And here is the skeleton code for the exercise. So you want to extend base dot show to and it takes an IO object, and then it takes the, the plants object. Now here's an array plant to, it could also be matrix, equivalently matrix of plants. That's the same thing. So we need to go we need to go over all the rows and all the columns. So one, two, and why? And one, two, and X. And we need to do something. So of course, the reason for going over rows and columns is that we want to print a new line after each row. And then all we need to do actually here, because we already have implemented a show function for a single plant. So we could do this. We could have an if statement if the plant status is infected and bring this otherwise bring this. But actually, what we need to do is to call the print function function with this specific plant. So this will actually call the show function and send it to the whatever this IO stream here is. So this should work. Well, but it doesn't plant is not defined because it's plants. It's the matrix. Okay. So I don't know if this looks a lot better. Well, I mean, it looks a lot better than this one, but it doesn't look as good as this one. So we could have a bit more formatting here to make it look nicer. Should we try something like this? That's a bit better. That's much better. Okay, but in the next section, we'll do something much, much better than this. So that is packages and plotting. So I will