Today's plan is to continue with funny kinds of arrays and array operations, you know, non-trivial ways of looking through multiple arrays. And then at the end of today, we will start getting into 2D matrices. And just like arrays, 2D matrices can also be dealt with natively by the C++ compiler or you can use some library packages to do it. In this particular case, the standard C++ library doesn't have, as far as I know, options for multidimensional arrays and matrices. So we will use an external library called Boost. Boost is readily available on Linux systems. You can just install it using APT or Synaptic or whatever your package manager is. If you are on a Windows or some other platform, you can readily download Boost from a website and install it on your computer. If you need help installing Boost on your system, the sysads, the juniors can help you out. So today we won't really do much with Boost. I'll just show you how to include the files and use them to declare arrays and do very basic operations on matrices. Most of today we'll use native multidimensional matrices. And more specifically for at least this week and next, we'll never go beyond two dimensions. There's enough to do with two-dimensional matrices. So coming back to sparse arrays and how they are represented. So remember that the easiest way to represent sparse arrays is a couple of vectors. One vector records the dimension or the index in a dense array where you would have stored the vector if you could afford the space. And the lower vector is a value array. So you're saying in that dense array, which I'm not storing explicitly, index number 11 had value 2.1. Index number 5 had value 4.3 and so on. So the other indices which do not appear in the upper row in this table are implicitly with value 0. And the whole point of storing it this way is that I don't have to store all those zeros. If the fraction of zeros in the original dense vector is much larger than half, say, then it makes sense to store the array in a sparse format. The trade-off is, of course, that operations get a little more complicated. So you sort of have to address things through the position of the dense array now. So for example, if you have provided the array where the dims are not in order, then to set it in order, we have to do some kind of sort. But now the sort key, the value on which you're sorting, is the upper row, not the lower row. So use the values in the upper row to permute the columns of this matrix. And the lower row always travels with the upper row. So unless the two cells in a column stick together, the vector becomes meaningless. So in the first step, if I'm doing selection sort by sweeping a frontier from left to right, then at fx equal to 0, where fx is pointing to the very first column, leftmost column, I find that the smallest dim is 2. And it appears at position 3, 0, 1, 2, 3. So what I do is I swap the 0th column with the 3th column. And that results in the following array. 2 and 3.2 have moved left. 11 and 2.1 have moved right. And 2 and 3.2 are now excluded from the remaining sorting because the frontier has now swept past 0. So now fx is equal to 1. So I started the 1th column. And now the minimum dimension to the right of it is 5 in position 2, 0, 1, 2. And at this point, I have to swap the frontier with the minimum. And again, the lower row has to travel with the upper row. So after the swap, it becomes 5 and 7 and 4.3 and 6.5. Now after that, my frontier has become 2. But now the minimum position is already 2, which is 7 itself. So one more position is already sorted. So I sweep fx one more. And now fx is 3. So I have the last two cells to sort. And the minimum position is 4. And the dimension of the minimum position is 8, shown in yellow. So now I have to swap the last two columns. And that results in a finally sorted or canonical representation of a sparse vector, where the dims are in strictly increasing order. So now to recap, we have covered the basic representation of a sparse array as a mapping from indices or dimensions to values. And we have figured out if it is not provided in an already dims sorted order, how to do it. And once you do that, then many operations become easy. For example, taking the dot product of two vectors or taking the sum or difference of two vectors, we now know how to do that. As we get into matrix algebra, we'll see that there are other operations which need to be ported to, say, sparse arrays. We'll see that in due course. So any questions about representation of sparse arrays? So for example, sparse arrays are a natural representation if you have to store polynomials. If you have a polynomial which looks like 2 times x to the power 37 plus 5 times x to the power 101, then all you need to store is the power and the coefficient. So that's a natural representation of a polynomial. So this is the code which implements that selection sort on sparse arrays, which uses dim to calculate the minimum position, but then does two swaps at once on both the upper and lower rows together. So the next artifact we will study is indirection or index arrays. And the motivation for this was as follows. Suppose you have a data vector or data array, data dn, which consumes a lot of bytes. For example, each item in the data array could be a string, and the string could be fairly long. Or every element in the data array could actually be a large record with your first name, last name, your parent's name, your city of stay, your name of your employer, your address, all kinds of things. If you package all of this up into a record, which in c and c++ is called a struct or a structure, which we shall study after midterms, then the number of bytes or bits in every element could become quite large. Now in both the sorting methods we have seen, there's a considerable copying of data involved. In case of selection sort, we have to detect that minimum element and pull it up to the front and push something back. That involves copying the whole record. If the record was just an int, then it's just 32 bits. But if the record is a complicated record like this, then it might take a lot of bits movement. So can we avoid this? And there are multiple reasons to avoid this. We shall see examples of that. The idea was to create an indirection or a permutation added. Pause, think of it as a permutation added. So that as you clock up px, pause px will dance all around the place, but data pause px will become increasing order. So here is the example. Suppose the data is these six strings, which I'll just use one character for simplicity. So zp, ay, bm. And we want, therefore, pause to be 2, 4, 5, 1, 3, 0. Why is that? Because the smallest element a appears in index 2, 0, 1, 2. The second smallest element b appears in index position 4. That's why after 2 comes 4. The third smallest is m. And so that's 5. So in other words, the ith cell of pause should contain the index of the ith smallest element of data. That's the definition of the pause permutation. So in the table, you see that the first column shows i as the index which sweeps through pause. Pause i is, as written in the second line, 2, 4, 5, 1, 3, 0. But now, if you look through where data pause, what data pause i is, you'll find that it's abmpyz. So that's in increasing order. Now, so one fact that many of you should know is that any permutation can be represented as a composition of loops or cycles. So 0, we'll look at that a little later. So how do you find the introduction? So last time we saw that. We start with a vector of strings and names, which suitably filled with animal names in our example. And pause was the permutation. Nn was the size of both of those things. Initially, I set up pause to be the identity permutation. So pause i is equal to i. And then I do selection sort on this. I only move data around in the permutation, but not in names, which is data here. So fx is equal to 0, fx less than n, plus plus fx. Find the smallest string among the positions, pause fx to pause nn minus 1. So observe that in standard selection sort, we are finding the smallest element between fx and nn minus 1. Now, at all times, we will look at names through pause. We will never inspect an element of names by itself. And then we do the swap.  And then I created the identity permutation in pause. And then here was the main sorting loop. Frontier goes from 0 to n. Min pause is minus 1. Now I create a minimum name, which is the plus infinity of animal names. No animal name is larger or equal to this. And then I sweep the minimum searching iterator, mx, from fx up to the n. And if the minimum name is greater than, instead of names mx, I have names pause mx. Every time I access names, it will just be pause. Then min name is assigned to names pause mx. But min pause will be mx. It will not be pause mx. That will tell me how to permute pause itself. So after I find out the minimum position, I swap only the pause added between fx and min pause. So you saw the demo already in the animated slide. So I'm not going to repeat that. And then finally, I'll print pause. If you want, I can show what is happening step by step. So we'll see. So initially, at the very first step, let me print out pause before starting out anything else. So we start with the identity permutation. Now we search between beginning and end for the smallest animal, and that's alligator. So I need to bring one up to the front. So one and zero are interchanged. Now I look at only, so the first position is now done. I only look at the data array at these indices. So alligator is effectively left out. Alligator is already done. So I look at zebra, giraffe, wolf, lynx, and jackalope, and ask which is the smallest among them. And the answer is giraffe. So now I swap these two. Zero two become two zero. And now one and two are done. So I only look at the original data array in position zero, three, four, and five. Zero, three, four, and five. And now the smallest is five. So I swap five and zero, and so on. So is everyone clear about how the pause array is being generated, step by step? At the end, we have one, two, five, four, three, zero. If you access data in that order, you'll get a sorted list of animals. Any questions about this? So how to compute an index array? So an obvious question for you is we use selection sort because it looks simple. Naturally, you don't want an n squared algorithm. We would like to use an n log n algorithm, like mod sort. So can you generalize mod sort to generate an index array? So try this out. All right. So how can you use introduction arrays? Well, some of the reasons are obvious. You want to access them in sorted order, and you don't want to actually move around the data. But here is an interesting problem. So suppose each element in an array called customer cn, or data, whatever it is, is 1,000 bytes. Now as I was saying, this can easily happen because I'm trying to package name, home address, employer, work address, data abort, all these fields into a struct, which we shall see soon. Now pause cn will sort without physically moving the records within customer cn. But suppose we do want to restructure cast cn to be physically sorted by name. We might want to do that if we want to then store the customer array on disk. Generally speaking, most companies will have customer arrays which are too large to store in RAM. Many companies will have that. So you would like to store the customer array on disk. And now if you want to do some calculation where you need the customers in increasing order of anything, suppose you want to get the customers in decreasing order of total sales to date to find out your most important customers. If you depend on the pause array to do that, then pause cx will be jumping out all over disk. And that will take a long time. So remember, I already told you that disks are best accessed in sequential order of bytes. So for this reason, you may want to reorganize the customer database to be sorted in whatever your sort order was. If you're sorting by customer name, then that's one order. If you're sorting by total sales to date, then you might want to store back the customer array in that order so that you can access it fast. So we can always do that by using another array called temp cast cn. So we can write code which looks like this. So remember, I had the customer array. But I also created the pause array. And now suppose I create the new temp cast array of size cn as well. Then all I have to do is for i equal to 0 to cn minus 1. So this loop will create in temp cast a sorted version of the array in cast. But the problem is that I'll be using twice the amount of storage. So what if this 2x space is not available? So as I was saying, permutations can be decomposed into cycles. For example, our old table with animal names had these values for i, pause i, and data of pause i. So let's pick out cycles in it. So I go to 0, 0 maps to 2 in pause. So let's trace back to 2. Now 2 maps to 5, 5 maps to 0, so 0 loops back. And that's a cycle. So we can write out the cycle like this, 0, 2, 5, and forget about those elements. The some arbitrary element that's not covered yet is 1. That maps to 4, 4 maps to 3, 3 maps to 1, and we have loop back. So that corresponds to another cycle, which is 1, 4, 3. So what we are saying is that the permutation given by pause can be decomposed into these two cycles. 0 goes to 2 goes to 5 to 0. 1 goes to 4 goes to 3 to 0. So now it should be reasonably clear how we can exploit cycles to permute and sort the data array in place, given pause. So a swap is just a special case of this. If I'm trying to rotate a cycle one position forward, what do I have to do? I have to preserve one value, keep overwriting, and the last thing I plug in from the preserved temporary value. So this may not be the correct pseudocode. So let me actually write this down on paper. So suppose I have my original array. Let's say it looks like this. These are the indices. So let's call this px. And then let the strings here, just for short handle, let's say z, a, g, w, l, j. So that's data px, or names px, or customer px, whatever you call it. That's data px. And if you went through the selection sort, you would find that pause px should be 1, 2, 5, 4, 3, 0. This is a slightly different example. So the indices are different. So now let's start at 0. So let's say I want to do this in place copy. I start a copy cursor, cx. And I have cx equal to 0. If cx equal to 0, then data cx is equal to z. So let's remember that I started at 0. And remember that the first value I looked at was z. Now let me do this assignment. I'll do data cx is equal to data pause cx. So I'm starting to rotate the cycle. I'm advancing everything to the next value in that directed cycle. So what happens if I do that? Effectively, I'm doing data 0 equal to data pause 0, which is 1. So that results in data 0 being overwritten with a a. But luckily, I have already preserved the z. So I'm not scared. So my data array now becomes a, a, g, w, l, j. So observe that there are now two copies of a here. So now I do the following to walk over one link in the cycle. What I have to do is cx equals pause cx. So that becomes equal to pause 0, which is 1. So cx has now become 1. So in the next step, I just continue. I said data 1 equals data pause 1. What is pause 1? Pause 1 is 2. So that's data 2, which is equal to g. So now my data array has become a, g, g, w, l, j. So at this point, I step up cx to be equal to pause cx, which is 1. So that is equal to 2. So next step is again the data assignment. So data of 2 equals data of pause of 2. What is pause of 2? Pause of 2 is 5. So that's j. So what is my array now? a, g, j, w, l, j. I'm just looking at a cycle and taking the next element of the cycle and copying it into the current one. As a result, there's always two copies of something, temporarily. How many people are comfortable with what's going on here? So I started out at a position 0, and I kept doing two things. One is data of cx equals data of pause cx. So pull over the next value in the cycle to the current place, and then step over to the next position. So that meant initially cx was 0. Data 0 used to be z. I overwrote it with data 1 because pause 0 was 1. So the first position became a, as well as the second one. Then cx changed to pause cx. So cx became 1. Then I wrote data of 1. Again, it's always data cx equal to data pause cx. That's the basic template statement. And the other is cx equals pause cx. So there's two steps you execute in a loop. So in the second step, what happens is data 1 gets assigned to g, which is data pause 1. Pause 1 is 2. So now it becomes a, g, g, w, l, j. Then cx steps over to pause 1, which is 2. And then data 2 from g gets assigned to data pause 2, which is 5. And that takes the data 2 to value data 5, j. So now there are two copies of j, just like there are two copies of g here, two copies of a here. But I've preserved the original z. I'll fix it when the time comes. So what happens in the next step? So the next thing that happens is cx equals pause 2, which is equal to 5. So now I could try to do the following. I could say data 5 equals data pause 5. What is pause 5? It's 0. So that is equal to data 0, which is equal to a. So that would be wrong. I don't want that. I have looked back. The first cycle has closed. And it's pretty easy to detect that, which is this 0 is the same as the value I remembered here. As soon as that happens, you should not be using data pause anymore. You should instead replace it by whatever you remembered here. So we'll replace this wrong computation with just whatever I was storing in temp. And that finishes one cycle. So once that happens, your new value of data will be a, g, j, w, l, z. This is what came from the temporary variable. So this has exhausted one cycle. But this one cycle doesn't cover the whole permutation because these two has remained unsorted. So let's keep track of what cx has been through. cx started with 0. Then it became 1. Then it became 2. Then it became 5. So basically, I'm now done with 0, 1, 2, 5. Those still remain to be done. If you follow the same procedure starting from any one of them, you are now going to get a relatively trivial cycle with two things. And that's like a swap. So shifting things around in a cycle is a generalization of swapping between two things. Remembering one, pulling it out, having them do a musical chair, and then insert the temporary at the other end. So overall, what does it give us? It tells us that first I can, no matter how big the records are, each record, each array element could be 1,000 bytes long. I don't care. I can write an efficient sort routine which only creates a permutation array. And now given the permutation array, I am going to fix the original data array to become sorted in at most linear time. So the number of data copies you're doing in a cycle is just the length of the cycle. The sum of all the lengths of the cycles has to be n at most. In fact, there could be trivial cycles with only single-tall elements in it that will reduce your time. If something happened to be in the correct sorted order by accident, then you're already done.  Whereas if you trace through what ModSort would do, you would actually copy 1,000 bits or bytes per record how many times? Log number of element times. So here, you do log n amount of copying of only the indirection array in pause, which is only 4 bytes per element. And you prepare the permutation array once, and then finally do a one-time implementation of the permutation through cycles. So you'll end up not moving so much data all over the place, log n times. You'll only move it once. Is the benefit of this clear? So you can reduce data copies in the case that each array element is really large. Yes? Can we also get copies of data of 2,000, data of 1,000? Yes, but that's done only one shot. Every item in data is going to its home in one shot. It just moves once. Of course, you have to move it once. The permutation pause expresses what is the correct sort order. And I'm moving every item of data just one shot to its final destination. Whereas if you looked at how ModSort was behaving, because it was doing it in runs, each item could be copied log n times. So let's try to implement this and see how it works. So at this point, the pause array is ready. I'll stop the prints. I'll print the name still. So the final pause array will be printed. And now let's try this one shot permutation copying. So we'll start off by keeping track of what has already been copied. Remember, I covered the cycle of 0, 1, 2, 5. And I can cross off those positions to remember that I'm already done with them. So now I initialize a Boolean array called copied. And one other way of initializing vectors in the standard C++ libraries is to give it the number of elements and one value to fill in all those cells. So that prevents a lot of that, avoid some work in writing a for loop. So you say I need nn cells. Each of them initialized to false. So I have not copied anything yet. And then forever, what I mean is until copied becomes entirely true, that's what I really want. Find the next not copied element. And here are some more easy things to use from the algorithms library. So you say not copied position. So find some not copied position, in particular the leftmost one. You do that by calling the find algorithm. Between copied begin and copied end, you're looking for false, so something that's not copied. That returns to you something. And you have to subtract begin to get the offset. It's just like subtracting a or subtracting the character 0. So we'll see this more as we go into templates. Any collection object has a beginning and an end. The end is abstractly one position beyond the last element. But begin and end are not directly integer types. So you shouldn't think of begin and end as integers, but find will return you another abstract position in a collection, and you can subtract begin to get an index. I could have done this with a loop. I could have said go through position by position. If you find false, break the loop and use that value. This is just one line of shorthand for the same thing. So eventually, you don't want this kind of trivial loops to paper your code. You want to pick up all these available libraries from the algorithm package and use them so that things become much easier to read and it's less typing, less mistakes to make. So I find the first not copied position. Now if not copied position is less than 0 or greater than equal to nn, then that means all positions have been copied and I can break the infinite for loop here. This is an infinite loop. No initialization, no test condition. So then break. Otherwise, I remember the beginning of the cycle as ncpause. And I remember names, I think this is wrong. I need to remember the names at ncpause. And now let me not write it as a while. Let me first write it in a relatively uncivilized fashion. So I'll say again infinite for loop. So this is the cycle shift loop. Whereas this is the loop to find the next not copied element, which is find entry into next uncopied cycle. So the outer loop finds an entry point into an uncopied cycle. And then the inner loop does the cycle shifting. So how do I do the cycle shift loop? I've already preserved the first element of it. Now the first thing is I should not be doing the cycle shift if pause of ncpause is cycle begin. So I say if pause of ncpause is equal to cycle begin, then I'm done. I should break. Otherwise, what should I do? I should do data of ncpause equals data of pause of ncpause. That was the basic cycle shift step. And finally, I have to walk over forward in the cycle one position. And that's equivalent to ncpause equal to pause of ncpause. Is that OK? And just so that we don't lose track of this entirely, I'm going to print things at the end of this. Not after every cycle shift, but after one whole cycle. But after I exit the loop, what will I have to do? So I've exited when pause of ncpause became cycle begin. So now I have to say data of ncpause is equal to the stuff I remembered. I check that the pause of ncpause is equal to cycle begin. Then I've come back to the beginning of the cycle. So I'm not sure this is completely bug-free, but let's run it on c. And after all this, I'll always try to print out the data added. Suppose I do that. Let's see if it sends off smoke from my machine or whatever. Data was not declared in the scope, line 57, or its names, not data. Clearly that wasn't working. I was trying to. Just give me a sec. So this is the original add-a. Then this is the permutation add-a. So in the first step, I should print not. Sorry, that doesn't make sense. Let me print out what I'm trying to do. Then it will be a little clearer. Let me not print names to Rachele. I will write out what is being assigned here. So I'll say ncpause gets the value from pause ncpause. So if that's wrong, we'll know why it's going wrong. So replaced by. So the contents of names ncpause will be replaced by the contents of pause ncpause. So I'm just printing out what the swap should be before mistakes are made so we can debug gradually. So 0, I'll copy 1. 1, I'll copy 2. 2, I'll copy 5. Now 5, I'll copy 0 is kind of done. So let me print a message for cycle done. Yes? You have to set all the others to true as well. That's right. Good observation. So I have to say, I also have to mark all the others as done. So 0 gets 1, 1 gets 2, 2 gets 5, and cycle is done, because 5 loops back to 0. And then 3 to 4, cycle is done. So now if I finally get the courage to print out what's happening, so after the first cycle, Alligator, Gdav, Jackalope, Zebra are in correct position as you saw in the example, but Ulf and Lynx are still not correctly done. And in the second cycle, I basically swap 3 and 4, and now I get sorted out. So there is a bit of a Josephus problem going on here in that as I am eliminating cycles by marking them to be true, I have to keep doing a linear search in the copied array to find out what remains not copied. So that is an additional complexity. You could try to think of how you can avoid that. So the search of our copies, it looks like one line of code, but it's not cheap. Every time I have to scan from the beginning to the end to find out what work is left to do. Can I make that more efficient? So again, I could try to squeeze out values, but that would be a little painful. So think about that. Any questions so far on? Basic indirection arrays. So an indirection array computes the index of the is smallest element in the original data array. And it's basically a permutation.  And even if you are not given an additional array to store all the original data, if you didn't have 2x the amount of space, you could still just hold one temporary records worth of data and permute the whole sequence. Any questions on this? So indirection arrays are very useful because you can declare them on the same data array depending on what your sort order should be. For example, suppose I have a database conceptually which has two arrays, each of the same size, cn. And the two arrays have student names and student marks. Maybe it's an example uncomfortably close to home, but bear with me. So each index accesses names ix and his or her marks ix. And as always mentioned, they have to be ganged. You have to access two of them at the same time. But the names and marks are not in any particular order. So suppose we want to do some fast grading on any one of them. For example, given a student name, quickly binary search and find the student's marks. Or given a range of marks, report all the students who got marks in that range. Clearly, if you wanted to solve both problems simultaneously, ordinarily you would have to store them in two different sorted orders. And then you'd have to replicate the student names in two places. But now you can avoid that. You can avoid that by keeping only the original pristine data unchanged, so name and marks. But you create two indirection arrays on them. One will be for the student names. The other will be for the marks. So to give a very simple example here, just to make this clear. So suppose I have name and I have marks. And so here are the names. And the marks may be something arbitrary. Let's say, I don't know, 14, 2, 11, 5, 9, 7. Suppose those are the respective marks of the students with those names. So now I can create two pause arrays. Names pause and marks pause. Or rather, let me create names pause on this side. It becomes cleaner. So names pause, the first position has to point to the smallest name. So that's 0, 1, 2, 3, 4, 5. So it has to be 2. The second smallest name is b at position 4. Third smallest name is m at position 5. Then we have 1, then we have 3, 0. So that will be the n pause array. Whereas m pause will be its own order. So m pause will be, the smallest marks is here. So m pause will be 1, which will go here. Then we'll have 3, which is here. Then we have 5, and then we have 4 of 1. Sorry, 2, we have 0. So any questions about this? So now we know how to compute each of them. Now as a software engineering exercise, it seems like a horrible waste if to convert any data record into pause records, you have to write separate code. Ideally, you should be able to write one piece of code which given any record and what key you want to get it sorted biologically. We'll find a pause array for it. So we'll see how to do that as generic code once we get into templates much later in the course. Once we know about classes, templates, we can do that. But can we get back into the kind of queries we'd like to answer on this? So we said, find the marks obtained by a given student. So how do I do that? So basically, you have to look at the names array through the n pause viewer. And remember, this is now sorted as this increases. Names of n pause of that thing will also increase. And so now we can do binary search. Now meanwhile, if I had some two marks, m begin and m end, and I wanted to find all students in that range, what did I do? I would use marks, m pause, and I'd do binary search. So of course, I assume that that is the case. So what will happen is I'll find two positions, m begin and where the marks are between that. And then I'll access the records using that. So any questions about how to code it up before we actually get started on it? So let's try this out. You haven't missed much. String, vector, algorithm, et cetera. And now I say vector string names. Then I do the usual. Suppose I have just five to reduce. And then I have vector, say int marks. So what you learn in the course, you should learn in life as well. If you're quickly trying to create an example, you should double the number of coppings you do, 11, 9. So five animals with five marks. Now, what's the indirection added? Let me dispense with long names and give the exact names as here, so that the example is exact. We can relate back to paper and so on. Then m got 7. So now we already know the indirection adder, so I won't write code to find the indirection adder. That's painful. So I'll say vector int n pause. And n pause. So there are various ways of declaring it. Maybe I should play it cheap for the purpose of this lecture and say int n pause. Actually you say something like input int n pause equals something like that. Then you say 2, 4, 5, 1, 3, 0. Similarly, you declare m pause as 1, 3, 5, 4, 2, 0. So there are two columns of your database with individual indices on it, called n pause and m pause. So now, suppose I want to write a binary search of two names, two marks. Suppose I want to find all students with marks between, say, 2 and, sorry, say 5 and 7 inclusive. So then I need to do binary search for 5. So let's say int m low equals 5, m high equals, say, 9. So now, if I have to search for those positions, how do I go about it? Remember the old binary search code? So this is what it looked like, low and high and so on. So again, because we haven't learned how to do functions yet, we need to copy and paste the search code twice over. So in fact, this is the low bracket for the low guy. This is the high bracket for the low guy. And this is the low mark answer. While low bracket for low guy is high bracket for low guy. The mid bracket for the low guy is that. I don't print anymore. But now the important thing is that my query here is marks low. So while marks low is less than, what do I do here? I take marks, but I can't do mid. I have to do m pause, mid low, another bracket. And if the low marks is greater than the same thing, otherwise if m low is equal to that same thing. So I just show one part of it because it's too tiring. And then we'll just, after that you can continue. We'll go on to matrices instead. So answer equal to mid and so on. And then, so I'll print out something. Let's say I print out mid low and also answered low. So suppose I want to access the names and marks. So now I say names, m pause, not n pause. We are searching on m pause now. So I do answer low and the marks, m pause again. Let's see if this at all works. Probably have a million compile time trouble. This is name marks because this is the thing about parameter copying. So this should be names.size-1. So see, I looked for low, which is 5. And 5 was obtained by y. So I see that y and 5 here. So I'll post this code. You should complete it to find all students who got marks in a particular range. Fine? Yes? We are assuming that the find has to be somebody. So what if no one actually got that mark? That's also an extension that you can do as a practice lab. When you binary search and your query value falls between two adjacent values, depending on what your code wants to do, you can choose the left, snap to the left, or snap to the right. But report that you didn't quite find that value and it snapped. That's what you need from a binary search routine. So the solution is, as I showed in the code, two indirection arrays, n pause and m pause, where names pause, n x increases with n x. But marks of names pause will not, generally. And conversely, marks pause, where marks of marks pause m x will increase with m x. But names of marks pause m x need not. And then you can use these two indices to do all kinds of interesting access on the data, even though the original data has not moved an inch or a bit. So that's how indirection arrays are organized. So that sort of wraps up what we have to do about the starter problems on 1D vectors arrays. Now we'll lift our dimensionality to 2D and get into 2D matrices. Declaration and storage of 2D matrices is very, very similar to declaration of 1D native arrays. So this is the native array way to declare matrices in G plus plus or C plus plus. So you say, I have an integer matrix. So int is the type of each cell, imat. And then you give the number of rows and number of columns. Instead of one box bracket, you have two box brackets, as simple as that. And or you can declare a double matrix called demat, which has, again, rows and columns. Internally, there is no distinction between 3, 5, and 15. Internally, the storage required for a matrix with three rows and five columns, rows go vertically, columns go horizontally, is indistinguishable from allocating a one-dimensional array with 15 elements in it. And CNC plus plus compilers implement what is just called syntactic sugar. It just makes life a little sweet for you, hopefully. By using the information about how many columns we have. So since you have declared the number of columns, like five, the compiler now knows that if you have to access imat at rx and cx, then the memory cell you are looking for is the base address of the integer at imat plus calls into rx plus cx. Why that funny multiplication? So here's the picture. So suppose I declared int imat 3, 5. Internally, so this is number of rows. That's number of columns. And internally, the c plus plus compiler will logically think of the matrix as three rows and five columns. The columns will be numbered 0, 1, 2, 3, 4. The rows will be numbered 0, 1, 2. But in memory, what will happen is imat will start at a particular place, its integer. So you need four bytes for each element. This is the 0, 0 cell that will be stored in the first integer. And then 0, 1, the next one will be the next four. 0, 2 would be the next four bytes, and so on. Right up to 2, 4, which would take another four bytes somewhere. So 15 cells goes from 0 to 14 integers. So let's see a basic declaration. So three rows, five columns. Int imat rows calls. Same syntax, just simple extension. Keep adding dimensions. Now again, I'll do some address voodoo magic to get the address of the very first 0, 0 cell. And then turn that into an integer by force. You shouldn't really be doing that. This is all bad, bad, illegal things to do. But this gives us a peek into how the memory is organized. That is base. And then this is the basic for loop. Row is 0 to rows. Column CX is 0 to calls. And I get the absolute address of the RxCx element in the matrix. And then I'll print the row and the column. I'll print the row address of the current cell as an integer. And then I'll also print address minus base to suggest what happens. So I compile that. Now when I run it, well, the address itself is some arbitrary hex number, which happened to have its highest order bit set. So that's why it said minus. But if you are upset with that, we can also always do unsigned, because this machine has 1.5 GB RAM. And depending on how the address base is organized, your address can look negative, but it's actually not. That's meaningless. So that's the address. So element 0, 0 has relative address 0. Absolute address is that in this particular run. If you run it again, it can change, as always. So element 0, 1 has relative address 4. So 4 bytes forward. I need the first 4 bytes for the 0, 0 element. Element 0, 2 is at relative byte offset 8. 0, 3 is at 12. 0, 4 is at 16. So overall, the first 5 elements take 20 bytes, starting at 0, 4, 8, 12, 16. So 16 to 19 will be the last element. So byte number 0 through 19 is the first row. And then the second row, namely row number 1 starts. And that's just the next position. So overall, I take 15 times 4 or 60 bytes. The last byte is the last element is starting at 56 and going to 56, 57, 58, 59. So bytes 0 through 59 are allocated for this 15 element matrix, so 15 times 4. Now if I change this to say double, nothing should change except for the storage model. So now I take, instead of 60 bytes, I'll take 120 bytes. The last one is 8 bytes going from 112 to 119. The element indexes are the same. The storage taken doubles. And the storage is addressed exactly like this. The base address is this. If you keep adding the second number, you get the absolute byte address in RAM of that array element. So this is how arrays are organized. But if you wanted to assign values to them, that's pretty easy.  I'm at, yeah. So of course, there's nothing to done. We are not printing anything, but this will compile. Now if you wanted to, you could always print out the value 2. So I'll just combine that here, silly old habits. So you access a value and you write into a value exactly with the same notation as before, except that a new index is stuck into another pair of box brackets. So all the cells are 0.5. And as far as native array declaration and initialization goes, that's pretty much it. There's nothing else you need to know. But once again, note that this knowledge that the 2D array had three rows and five columns is lost immediately after this statement. So C++ compiler and runtime system is not going to remember this for you. You have to hang on to rows and columns for dear life. And earlier it was just storing one number. This time it's actually vital to store both numbers because the way the compiler figures out that 0, 2 has relative address 16 is by remembering that there are five things. If you go into the second row, it has to understand that the first row had five things. Because the arithmetic it's doing here depends on multiplying the number of columns. Let me show it here. So if I write another relative cell number in here, so that is cell 0, that is 1, 2, 3, 4. But now it's 5, 6, 7, 8, 9, 10, 11, 12, 13, 14. Then the cell number of ij is equal to what? 5 into i plus j. So for example, cell of 2, 3 is equal to 5 into 2 plus 3, which is equal to 13, cell number 2, 3. So that's why the C++ compiler has to be always told that the array had five columns. Without that knowledge, it's just a one-dimensional byte array. So this creates infinite misery if you want to pass 2D arrays into functions. It's almost impossible to write functions which can accept native arrays of any size, because the column information is hardware. And it's outside the array itself. So for all these reasons, although we could sort of live with native one-dimensional arrays, I just don't like to deal with native two-dimensional or multi-dimensional arrays at all, because that knowledge of five is going to haunt you when you write functions. You'll keep passing it in. You have to keep pretending that the 2D array is actually a 1D array. So why pretend? So what's happened is that there is this other library you can use called Boost, which gives you all of this. So you can include Boost libraries using a more complicated-looking path. So you say, include Boost, numeric. This is basic linear algebra. And then you say, I want matrices. I want IO4 matrices. And these two will basically give you all the basic stuff you need for 2D matrices. So for example, you can say, now note that I have not used a default namespace yet here. And you can now start using the namespace called Boost, numeric, hublase. This actually follows exactly that path. So all these classes or types are registered inside this namespace. And anyway, so you can forget about those details. You can say, I want a matrix of doubles, which is m, which is size 3 by 3. And now you get two methods called size 1 and size 2, by which you can get the rows and columns. So next time we'll go on to study Boost in some more detail before starting matrix algorithms.


The study examines predictors of belief in COVID-19 misinformation across five national samples from the UK, Ireland, USA, Spain and Mexico, finding that while public belief in misinformation is not common, a substantial proportion views it as highly reliable. Increased susceptibility to misinformation negatively affects self-reported compliance with public health guidance about COVID-19, as well as willingness to get vaccinated against the virus and recommend it to vulnerable friends and family. Higher trust in scientists and having higher numeracy skills were associated with lower susceptibility to coronavirus-related misinformation, suggesting that interventions aimed at improving critical thinking and trust in science may be a promising avenue for future research. This article was authored by John Rosenbeek, Claudia Arschneider, Sarah Dryhurst and others.


In 2022, the Ministry of Forest began implementing old-growth deferrals across British Columbia. These deferrals temporarily halt any harvesting of old growth, giving us time to consider long-term solutions. BC Timber Sales is working to implement the deferrals by tracking where they overlay with harvest areas to ensure our most at-risk ecosystems are managed appropriately. These deferrals are reviewed in-depth by forest professionals before they head into the field to verify them. So we're headed that way? And then this will be our first area that we'll hone in on. This is where it's kind of most obvious that this is a different forest type. If a harvest area was developed before the deferrals were passed, foresters must re-engineer the area to exclude the old growth from the harvest area. As you can see pictured, the yellow background is the proposed cut block. Prior to the old growth deferrals being released, BCTS protected the green areas as reserves. The yellow grid is the deferral area. The red is the deferral area that overlaps with the planned block. The trees in the red looked like second growth, but upon field verification, foresters found they met the criteria of old growth. The block was re-engineered by removing the red deferral overlap from the harvesting area and placing it into the reserve. It kind of showed that not all old growth is the same. That's why this field verification process is so important so that we can actually determine what is old and what isn't, regardless of its size or its ecological services. Our trusty increment bore to measure the age of the tree in a less invasive way than a chainsaw. You kind of try to line it up so that you are ensured to hit the middle of the tree and then you start boring. Okay so you can kind of hear that we've hit the center. See if I can get it right the first time. This tree is from what I recall counting about 273 years old. Doing this really paints the picture of what happened in the history of the forest you're in because otherwise some of these trees which were tiny little suppressed understory trees, you know 80 years ago, they released when this was logged and they took off and now they're in the dominant and co-dominant parts of the canopies. We're really glad to be doing this and making sure that we're properly managing our ecosystems. When deferral areas don't contain old growth characteristics it means those areas can be harvested if needed. However, every effort must be made to find a replacement area nearby that does contain old growth characteristics and it must be preserved in its place. It's in a tap polygon but when we field verified it it didn't meet the criteria to actually be considered old growth so that was a deletion of the tap. Type 4 is a replacement area for that deletion. When the high-level data doesn't match what's on the ground foresters find replacements to ensure that we are conserving old growth in the places where it does exist. We're going to use the vertex which uses sound to measure the distance to this device which the other person will use and then we'll measure the angles and it'll do the trigonometry for us, give us the height of the trees. Yeah 41.2 93.5 centimeters. It's an exciting time in forestry there's lots of changes and it can be challenging but I'm really excited to be part of the changes and I'm just really proud of the work we've done. This ecosystem in particular around here is rare so let's get that this is in the deferral area. The old growth deferral process is complex. Identification of old growth isn't always straightforward and requires forest professionals to collect and present high quality data and to make decisions on the latest policy in science. By ensuring that the appropriate areas are temporarily deferred decisions can be made to create a new future for old forests.


When I was 5-ish, my family and I went to a kids' expo located on the Gold Coast. For those who don't know what an expo is, it's basically just an abbreviation for exhibition. It makes no sense why is there a pee.  Because it was such a big event at the time, the news were there to get amongst the action. The biggest news company in Australia.  Okay, so before I get into this main story, this hasn't been the first time I've been on TV. A few years ago now, there was a specific shot of a group of people, and I just so happened to be in the back of it, and I was on TV for a split second. Well, what a medal. That's pretty much it to that story. If I made a video on that experience, it would literally be the most boring video ever. But talking about mistakes made by younger me on TV? Now that's a video I would click, and then everyone clicks off.  But it was great. I remember absolutely loving the pony rides there because they had butt stamps. I remember absolutely loving the pony rides there because on the pony, they had those butt stamps. From... And I liked that because... This was definitely during a time where I was obsessed with my little pony. That whole explanation was a mess. After running around in circles on the pony a few times, I got off to join the others, but someone stopped me. A camera crew came up to me with their big set up of mics and large cameras, and they wanted to ask some questions about the big day. Okay, what I actually did in this moment, it needs some explaining. When I was younger, I was always taught to smile like cameras, because it meant I was getting my picture taken.  Little did I know it was a video camera. So how's your day been? What was your favorite thing today? Did you like the ponies? They're cute, right? Don't mess this up. Keep smiling. I was being asked all these questions, and I did not answer a single one of them. As I thought the camera in front of me was just there to take my photo. I did not budge. I did not want to wreck my smile for this photographer. I just stood there awkwardly staring this camera down. And to make that as worse, my smile was barely a smile. Okay, so imagine this being my smile, and this bit is a bit flat.  So many school photos were harmed by this smile. My brothers did come over to me as they knew what was going on, but they only found their sister to be smiling at the camera like a creep. Well boys, time to pack up our things. We aren't getting anything here. Off to our next victim. Oh dear, we don't need that goat poop. We got him boys, roll out.  That evening we went back to our grandparents place and all sat together to watch the program about the kids' expo. That clip of me staring awkwardly at the camera played on TV for a few seconds as they transitioned it back to the news reporters. My family were shook. I honestly wish we had the footage today because it would be the funniest thing now. Hey guys, thank you so much for watching this video, I hope you all liked it. If you guys didn't know, I have a Patreon now and don't forget to follow me on Twitter. Thank you all for the beautiful fanart as well.


This video is part of an online course on commutative algebra and will be about a gadget called the COSL complex. So I'm first going to recall a little bit about regular sequences, and then I'll explain what the COSL complex is, and then I'll explain how to use the COSL complex to solve a problem about regular sequences. So we recall that if we've got a ring R, a regular sequence is a sequence of elements x1, x2 and so on, such that x1 is not a zero divisor in R, and x2 is not a zero divisor in R over x1, and x3 is not a zero divisor in R over x1, x2 and so on. And there's one other condition that I forgot to mention last lecture, which you have to add the non-triviality condition that R over x1 up to xn is not zero, because if you allow this to be zero, then there are lots of rather silly examples of regular sequences. So, well, the definition of regular sequence depends on the order, and we can ask the following question, is a permutation of a regular sequence also regular? And if it is, that would make life much easier, because we wouldn't have to worry about the order of the regular sequence. And the answer is no in general. So here's an example. Let's just take a polynomial ring in three variables and quotient it out by xz. So this is just the coordinate ring of a union of two hyperplanes meeting along a line, sorry, two planes meeting along a line. And now we can look at the sequence of elements x-1 and xy, and this is regular, because x-1 is not a zero divisor here, and if we question out this ring by the ideal x-1, we're just setting x equals to one, so we set z equals to naught and just polynomials in y, and this just becomes y, and it's not a zero divisor. On the other hand, xy x-1 is not regular, and this is because xy is a zero divisor, because if you multiply it by z, it becomes zero.  So you can see that if you permute a regular sequence, it need not be regular in general. However, it's true if r is a local ring. When I say true, I mean the permutation of a regular sequence is regular. So for a local ring, the condition that r divided by the regular sequence is none zero just says that all elements x-1, x-2 and so on x-n of the regular sequence in the maximal ideal m of r. Well, the proof that for r being a local ring can't be entirely trivial because it's not true for all rings, so we must somehow use the fact that r is local improving this. And to do this, we will define the causal complex of a sequence. You can define the causal complex for any sequence, but it will only really be interesting if x-1 up to x-n is a regular sequence. So let's first take n equals 1 and look at the causal complex of an element x-1. Well, the causal complex in this case is just nought goes to r, goes to r. Here we multiply by x-1, goes to r over x-1, goes to zero. So it's a rather obvious exact sequence. Notice that it is exact if x-1 is not a zero divisor, which is most of the condition that x-1 should be a regular sequence. For n equals 2, we take a sequence of two elements and we define the causal complex like this. Nought goes to r, goes to r squared, goes to r, goes to r over x-1, x-2, goes to zero. And in this case, the differential is defined as follows. It takes the element 1 to x-1, x-2 in r-2 and it takes an element a, b in r-2 to x-2, a minus x-1, b. And the map from r to r over, that is the obvious map. And note by the way there's a minus sign there which you need in order to make this differential followed by this, sorry the composition of these two differentials equal to zero. And in general, the causal complex is defined in a rather similar way. What it looks like is the following. You take nought goes to r, goes to r to the n, goes to r to the n, choose 2, so on all the way up to r to the n, choose n minus 2, goes to r to the n, choose n minus 1, goes to r to the n, choose n, goes to r over x-1 up to x-n, goes to zero. So another way of writing these is that these are just the exterior powers of r. So you can think of this as being r, the first exterior power of r, the second exterior power of r and so on. And what we'd like to do is define this and also check it's exact if the sequence is regular. Well the easy way to define it and prove it's exact is to get the causal sequence for n elements by splicing together two copies of the causal sequence for n minus 1 elements. So I suppose we've got the causal sequence for x-1 up to x-n minus 1. So this is going to map nought goes to r, goes to r to the n minus 1, goes to, and go to r to the n minus 1, goes to r, goes to r over x-1 up to x-n minus 1. So here's a copy of the causal sequence for n minus 1 elements. Now we're going to take a second copy of it. So it's exactly the same as the first row. So what's the point of writing this out twice? Well now what we're going to do is we're going to define a map between these two things and this map is going to be given by multiplication by x-n here.  So the signs here alternate. So you remember on the previous sheet we had a little sign here and the signs in general come by making them alternate. And the reason for this is we can now define the causal complex where we almost define it by taking the sum of these two bits here as our causal complex. So the terms of our nth causal complex are going to be the sums here. So we're going to get nought goes to r, goes to, well if we take r plus r to the n minus 1 we get r to the n and so on. And the differential is given by taking the obvious maps from this thing to this thing as a sum of that and that and that. And the reason we put minus signs in here is so the composition of two differentials is zero. Well there's one thing we have to be a little bit careful about. What we actually do is we cross out this bit. So the causal complex ends with r, goes to r over x1 up to x to the n. So we're not going to cross off this bit but we replace this, we're quoting out this bit by xn. So we sort of quote out this by the image of that and then delete that. So we do a little bit of twiddling right at the end. And otherwise we just get r to the exterior powers of r and a differential and so on. So that sort of more or less defines what the causal complex is. If you write out a formula for the differential explicitly we see that the causal complex does not depend on the order of x1 up to xn up to isomorphism. And to see that you have to sort of work out what the differential is explicitly and you see that it's really independent of the order. And I'm not going to do that because it's slightly tedious and I will get it wrong if I try and do it. So now we want to show that if x1 up to xn is regular it implies the causal complex is exact. Well, most of this is fairly easy. If you define the complex consisting exactly of these pink things then it's a very easy exercise to check it's exact. And the only problem is we're not quite defining the causal complex to be these pink things here because we sort of crossed off this term here and twiddled the last term very slightly. It turns out that this means the causal complex is obviously exact except right at the end. So we've got this slight problem that we're going from... If I write out the last bit we've got r here, r to the n-1 goes to xn goes to r and this goes to r over x1 up to xn-1. And the only problem is exactness at this term here that we need to know that if something here maps to zero in r then it's the image of something here. Well, if it maps to zero in this bit here I guess that yellow isn't quite visible so let me do it in green. If it maps to zero in here then it's certainly the image of something there that's easy to check but as I said we deleted this. So all we know is that its image is zero in here and we want to know it's in the image of something there. Well to do that we would like to know that the image in here is zero and we can argue as follows, suppose we've got an element of this represented by an element a here and an element b here whose image here is zero. Well then the image of b here must also be zero. Now if this map here is injective this implies the image of b in this group here is also zero which makes it easier to prove exactness. So xn injective on r over x1 up to xn minus 1 implies exactness. That's assuming we've shown exactness for the causal complex on n minus 1 elements as long as xn is injective on this then the causal complex on n elements is injective. Well this is exactly the condition that x1 up to xn is regular. Well at least it's most of the condition that x1 up to xn is regular. So we see that if x1 up to xn is regular this implies the causal complex is exact. And this is very nice because it gives us a way of producing exact resolutions of modules and because you see the causal complex is a resolution of this module here by free modules so we see that if x1 up to xn is regular we get a finite free resolution of the module r over x1 up to xn and this is very exciting if you do homological algebra because you can use this free resolution to calculate x groups and tor groups of this module here. Of course not all modules over a ring can be constructed even if they're generated by one element they aren't necessary of this form with x1 up to xn a regular sequence. For instance if it has a finite free resolution of length n this implies that a lot of all its tor groups for sufficiently lot for anything bigger than n vanish but there are plenty of examples of modules over rings with an infinite number of non-zero tor groups. So this is actually not all modules can be written like this. Well what we would like to do is ask if the causal complex is exact is x1 up to xn regular and the answer is no in general. The reason for this is that we actually gave a counter example to this at the beginning of the lecture. If we take a sequence such that x1 x2 is regular then the causal complex is exact but if x2 x1 is not regular it has an isomorphic causal complex so the causal complex of this is still exact but if x2 is a zero divisor as in the example at the beginning of the lecture then the causal complex will not be exact. However the answer is yes if r is a local ring and the consequence of this is that r local implies a permutation of a regular sequence is regular. So this will prove the result we state at the beginning of the lecture very useful it means you don't need to worry too much about the order of a regular sequence as long as you're just working with local rings in which case all the elements of the regular sequence are in the maximum ideal. So to finish off with I'm just going to explain roughly why when r is a local ring the exactness of the causal complex implies x1 up to xn is regular and what we do for this is in fact we don't need the full exactness of the full causal complex we only need exactness of the h1 term so let's write hi for the ith homology of the causal complex actually I should have put hi of x1 up to xn for the ith homology of the causal complex on x1 up to xn and then we find we get the following long exact sequence so I'll first write down the long exact sequence and then explain roughly where it comes from so the only bit of it we're interested is going to be h1 of kx1 up to xn-1 goes to h1 of x1 up to xn-1 goes to h1 of x1 up to xn goes to m over x1 up to xn-1 goes to m so that should be an r my notation muddled up over x1 up to xn-1 so this map here is multiplication by xn and this map here is also multiplication by xn and now this exact sequence holds whether or not the ring is local and where it comes from is if we go back and look at the construction of the causal complex on x1 up to xn we get it by splicing together two copies of the causal complex for x1 up to xn-1 and if you sort of do a bit of diagram chasing on that it's not too difficult to find out you get a sort of long exact sequence where in general this would be an hi and an hi and an hi and here would have an hi-1 and it would sort of go on like that I'm not going to give the proof of this because most proofs of diagram chasing are very easy to do and very boring to watch somebody else do them so I'll just leave it as an exercise anyway the key point is here we're assuming the causal complex on x1 up to xn is exact this means the homology vanishes so in other words this term here would be equal to zero and let's see what consequences that gives well first of all when it gives two consequences the first one is that this implies that this map here is injective so if x1 up to xn-1 is regular so is x1 up to xn so that side of it reduces us to showing that x1 up to xn-1 is regular well to show that x1 up to xn-1 is regular we would like to show this term here is zero so we can ask is this zero well what information do we have about this well if this vanishes we know this map here is on to now for general rings the fact that we've got the map multiplication by xn is a surjective map on modules doesn't really tell us very much about the modules there's lots of modules where multiplication by some ring element is surjective however in the special case when r is local we have the famous Nakayama's Lemma which says that if m is a finitely generated r module and m times m equals m where m is the maximal ideal then m equals zero well let's go back and apply this to this module here so let's apply it to m being h1 of x1 up to xn-1 then xn from m to m is on to by assumption and xn is contained in the maximal ideal because for a local ring elements of a regular sequence would be in the maximal ideal so m times m equals m so m equals zero and m was of course just this module here so h1 of x1 up to xn-1 equals zero so by induction so using some sort of inductive assumption x1 up to xn-1 is regular which is what we wanted to prove so this completes the sketch of the proof that for regular sequences over a local ring the order doesn't matter okay I think that's enough about regular sequences for the moment the next lecture will be about the next type of local ring which are Goromstein local rings which is a slightly stronger condition than being Cohen-McCawley


sleeping giant. What's up? I'm Giggs Mr. V here. Welcome to another video, guys. So in today's video, I want us to talk about Ticket Symbol, I.N.O. Inovio, a pharmaceutical. So this is a company that we profiled here on the channel before when we talked about our COVID-19 vaccine companies in Inovio was actually one of them. But ever since then, this stock has really struggled to make some moves and has just sit back and taking a vaccine from companies like Pfizer, Moderna, Johnson & Johnson. And I mean, like the guys that are leading the space today, we know that Pfizer's vaccine is currently being administered to people across the country. Moderna vaccine is on its way. So you're going to have two companies with their vaccines out there. But what we notice, if you look at the price for Moderna and Pfizer, the stock price just totally collapsed. It hasn't made any move. If you would think that companies announced vaccines like this, the stock prices are supposed to jump or skyrocket. But we see the complete opposite. Moderna pulled back to under 120 at one point. Pfizer is currently trading about $34. So there's been this crazy movement not really going along with the vaccine that these companies are putting out. So I want us to take a look at Inovio because what they are doing, even though they're really slow to get to market, but the vaccine is to me has a lot of promise. They are working on what I call a DNA vaccine, which is a complete different approach from the Moderna and Pfizer vaccine. And I'm going to show you guys some other advantages that this vaccine has in the marketplace that the competition doesn't have. But before we get started, guys, if you're new to the channel, we talk about how to earn money, how to save money, how to invest and build wealth. So if that's something that interests you, go ahead and hit that subscribe. And any notification bell so you don't miss out on new content. So if we see here, again, for Inovio, here's the latest news that came out, the fact that their vaccine, phase one trier, really turned out to look really, really good. So again, this is, let me bring that up here. So this is the information that I actually got. And that's why I wanted to do this video. They've gone back and after their issues with the FDA, they've gone back and just redoing their trials. And now they're going back to phase one. And now they're looking ahead. This is the vaccine that we have. And so far they've ran some tests and the clinical trials for that phase one is looking really, really promising. And that to me, that's good. And if you listen to most doctors and you see the reason why they think this vaccine is by far the best in the marketplace, even though the vaccine is not complete. But the idea that is doing a DNA vaccine is something that differentiates guys from the other companies. It was a race to the finish. We thought that whoever comes out with the vaccine first, the prior stock is going to completely explode. That has proven to not be the case because Pfizer stock has not exploded. Again, Moderna stock has not exploded. Like we anticipated. But now I'm looking like, hey, it looks like whoever comes out with the vaccine, that's going to do the work. That's going to be efficient. It's going to take one vaccine.  I think that's going to be a game changer and Inovio is really on track for doing that. One of the things they need to be aware of is that even though Inovio is slow to get their vaccine, I think it's because of the fact that they do DNA. So it's not very easy to just run their clinical trials compared to the other companies. Then here's another thing that I want you guys to really keep an eye on because based on the information that I'm getting and reading, it means like that vaccine has a lot of efficiencies that the other ones don't have. Transportation wise, it's easy to transport. Storage wise, it's easy to store. You don't have to put it in refrigerator to transport it across the country. So it doesn't have to be frozen like you can see here which is excellent. We're talking about if you're taking this vaccine to remote areas and you have to worry about keeping it frozen, that's not really going to cut it because the cost of distribution is going to be very, very expensive. Renting containers that are half refrigerators that will keep it frozen. So again, this vaccine to me has an upside. Again, the stock right now is relatively cheap. If we look at the current price of the stock, it's trading somewhere at about $10 and some change. But if we're getting early now and just hold it for the long run and give these guys enough time to build this stock, if this vaccine comes out, this stock would be over $100 stock. Again, that's my personal prediction. So I'm looking more or so from the technology standpoint what these guys are doing. They're not just building a vaccine like the other guys. They're building something that it's going to change in the future. Again, I was looking like just the details as to how the vaccine works. I'm not a doctor. Never been to med school. But I see the way the vaccine works from a DNA standpoint has tremendous amount of promise compared to the current vaccines in the marketplace. So do some research about these guys. Read a little bit about them. There's a ton of information on the website. You can actually learn more about what they're working on from a vaccine standpoint. They don't have the reputation of a Pfizer or a Moderna. But if these guys come out with the vaccine that you can go in and take one shot and you're good to go. And again, the fact that it targets like the DNA I think is to me, it's huge, a huge amount of upside there. So definitely do some research on these companies. The other thing I wanted to bring up to you guys here is the last one in here that they actually have this funding from the US Defense Department. So they're still getting funding in order to because they see a tremendous amount of potential in their vaccines. So that's why these guys are getting a lot of funding from the government to keep their work going. So that's what I wanted to cover in this particular work for you guys. So I still think that if you are under $11 right now you can pick up a few shares of Inovio and just hold on to it. Again, my whole concept here is that for stocks that I think they're highly on the value, you pick somewhere between 50 and 100 shares and just hang on to it. This one is going to be a little bit of a weight for us because it's really dependent on this vaccine. And so just hang on to that. And then as we see more and more data comes out for the test when the phase two comes out, phase three. So looking to go for FDA approvers and then you can start adding and building that position. But then your dollar cost average is going to be really, really low because you started at $10. So that would be the game plan for this. So I still think that there's some good opportunity here. And I didn't want to just let you just want to sleep. This is to me, this is a sleeping giant and I don't want us to miss out on it. So again, let me know in the comment section what you think. If you're new to the channel guys, we talk about how to earn money, how to save money, how to invest and build wealth. So if that's something that interests you, go ahead and hit that subscribe button and the notification bell so you don't miss out on new content.


All right, welcome to the Bookmap Platform Details webinar. This is Bruce at Bookmap Risk Disclaimer, Trading Equities, Futures, and Cryptocurrencies, involves substantial risk of loss. And it's not suitable for all investors. Past performance is not necessarily indicative of future results. For more information, go to bookmap.com. There's a 14 day free trial of the product that comes with education. There's an educational course to go through. It's four parts. And it also includes the advanced order flow webinars. These are live market webinars that we go through looking at the order flow and analyzing it, looking for future price movement based on what we see in the chart. So the idea is to combine the educational course with the live market and support that educational course with what we cover in those advanced order flow live webinars. There are other educational resources as well. And if you have any questions, you can reach out to us at support at bookmap.com. Let's go to the website quickly here. You can see digital currencies coming soon. Let's scroll down a bit. And there's an intro video here, just general information about Bookmap. A bit further down, there's NASDAQ Total View. So you can connect to US equities. You can read about the advantages here. And a bit further down, this is an important section, connectivity. So Bookmap is a trading software platform. Just like any other platform that is out there, we are not a data provider. So you will need to provide your own data through one of these data providers here. We also connect through the API of various platforms. So Ninja Trader, TTX Trader Pro, and Interactive Brokers Traders Workstation. So we connect to these three platforms via the API.  So you can connect Bookmap directly using CQG, Rhythmic, Gain, IQ Feed, or Transact, or that DevExperts for that NASDAQ Total View that includes all US equities. Bit further down, pricing information here. The 14-day trial period for Bookmap Basic and Advanced, you can see it's $49 per month and $99 for the advanced. They are billed quarterly, so note that. You get that 14-day free trial. Now, the difference between these two are the features here, the add-ons. So the ability to trade right from the Bookmap Chart with the one-click trading, as well as proprietary indicators that we put together that analyze the order flow. So in specific, the large lot tracker, we're looking for not only order flow phenomena, but specific players in the market. So this algo will identify larger players. Another player identifier here is the iceberg detector where we can find where larger players are using hidden orders to show, well, not to show their hand in that limit order book, but where their icebergs are getting filled. And then there's imbalance indicators here, as you can see, as well as a correlation tracker. Quants, you can reach out to us here. You'll have specific needs, and we work with many quants. So let us know for connecting your own data feed and proprietary indicators. If you're new to futures, you can click here if you need a data feed. So there are some free trial data feeds that are out there. And so you can get a free data feed, as well as Bookmap free trial, and get up and running within minutes, basically. If you can't decide which platform or which version is correct for you, you can see the complete comparison here. Other resources follow us on Twitter, at bookmap underscore pro. And there's our YouTube page here, all sorts of videos for reference. And you can subscribe to our page. And when new videos are uploaded, you'll get alerts. The Bookmap intro videos are here. I would suggest starting with those and then move on to some features and components, understand the user interface and how to work Bookmap. And then these order flow video snippets, very concise videos that go through that phenomena that we cover in detail in the live order flow, advanced webinars that start in about 25 or four minutes. All right, let's jump in and take a look at Bookmap. Here is, actually, I'm using a version here that is not available to you at the moment. This is the new Bookmap version seven that's coming out in about 10 days or so. So we'll be on the lookout for that. And all sorts of new features in here, so ask any questions that you have, happy to answer them for you. And you can see right away, for example, the heat map is colored here. So there's a few different options as well for that colored heat map. You can use red as the highest liquidity. And just note these areas here. Now you're seeing really distinct values here in that by using this colored heat map, really focusing in on some subtle details in some of these areas, which is great. That's the reason that we have that new offering here with the color, because look in some of these areas here, you don't quite see that distinction here. Now you could if you zoomed in here and maybe played around with some of the settings a bit. But the colored heat map will show it immediately. And that's a really nice advantage here. I'm gonna go with the orange one for now. And anyway, for those of you who are new here, so let's go through some of the details here. That's what this webinar is for. And we will look at some of the order flow phenomenon as well, but start with some of the basics. So what are we looking at in book map? And well, there's looks like a lot of data here. There is a lot of data, but it's actually pretty simple stuff. In fact, I think maybe I'll jump over to the NASDAQ here. It might be a little simpler, although I do like this really high liquidity that you see up here and we traded right into it with Bitcoin. So some absorption up here. And then we can see that this was all filled up in this area here and we've sold off since. Anyway, let's jump over to that NASDAQ and we'll take a look here and I'll zoom out. Okay, all right. Okay, so looking at the NASDAQ here, all the different data that you see here. So it looks like there's quite a bit here. Well, it's actually really simple and straightforward. There's only three elements here in this chart. We're only looking at here historical best bid and offer. If we zoom in here, it might be a little bit better. Okay, so historical best bid and offer. And then you see these dots here. These dots represent volume that traded on that historical best bid and offer. Make it a little bit bigger here so you can see that. And that's the second element. And the third element is the liquidity. So from your depth of market, your dome, we've taken the areas of liquidity and then projected on the chart historically. So that's all you're looking at here. So let me go through it in a bit more detail and let me actually get rid of this column here. Okay. And I also want to configure my price ladder quickly here so it's a little bit easier to read. There we go. Okay, so these three elements, right? Well, let's start off with something we already know. And we'll look at a, just a candlestick chart. We'll zoom out a little bit. And we're looking at a five minute candlestick chart here. Okay, that's it. And it looks very clean and clear, right? And that's one of the benefits of the candlestick chart. However, the problem here is we're making financial decisions based off of very, very limited and opaque data here. The only thing that we're seeing in this five minute period is open, high, low and close. And it's all aggregated. All data is aggregated within this five minute bar, right? And that's the problem. So there's all sorts of information that is just simply not here on this chart. And we want to know that information, it's important. We want to understand first off, micro structures within this five minute period, right? And we're going to be able to do that very easily in book map by showing the best bid and offer, historical best bid and offer. So I turn that on and the red line is the historical best offer and the green line is the historical best bid. Okay, so we're going to see all sorts of micro structures within that five minute aggregated period. And let's just zoom in a little bit here and you'll see what I mean here. So there's a structure here, as you can see. Another structure, we broke out above that structure here. And we traded up here for a while and then we broke down from that structure here. Okay, so some trappy action within this area here. And you're not really seeing that within that five minute period. You're seeing some of it actually. I'll give it a little bit of credit here. It's not so bad, but there's all sorts of activity like for example, down here, okay, a beautiful example is we see that, you know, price is slowing down. We don't see any of that within this candlestick chart. And we can see a structure was made down here and we broke out of it, came back retested to where we broke from. And this is one of the things we look for in the advanced order flow webinars is these are opportunities to look for the continuation to the upside if we're gonna accept or reject out of this trading zone here in the microstructure. And that's where the candlestick is just not allowing us that transparency. Now the next level of data here or layer we wanna look at is the volume. So let's turn that on. And the candlestick chart here is not showing any of that. We do have a sub chart here. However, we wanna understand very specific volume. Where it traded, when, how much, and what type. Okay, so now we do have that. Okay, we can see within that microstructure exactly where that volume traded, how much. Okay, we can see that with the bigger dot. And then we can also see what type. Okay, a green dot is a market buy order. A red dot is market sell. Okay, now we use aggressor classification of volume. So let me just show you the two elements so far that we have. And I'm gonna zoom into this area. So this is it, just these two elements here. So we have the historical best bid is the green line. Historical best offer is the red line. Okay, and the volume dots here are transactions on that historical best bid and offer. Okay, the red dot here is a market sell. Green dot is a market buy. That's the aggressor. Okay, so when hit the market buy button, they paid up here, actually the spread is actually two ticks wide here. So they paid up for it to be able to get filled up in this area here. Okay, but they wanted in right away and they didn't provide liquidity, waiting in the dome. They took liquidity from the dome. That's what, that's why we consider it the aggressor. Okay, so these are the two elements that we're showing so far. And we already have a tremendous amount of insight into some of these areas. If I zoom out, we can see that we're trending down here and we're starting to make just slightly lower lows here. As you can see this, we're slowing down. And then that structure is broken here. Okay, this microstructure here. It's broken and you see the aggressor here lift the offer up out of that area. This is the new evaluation of price. It's above this 65.92 area here. And we can see that we get a retest back to where we broke from. And we don't find a lot of sellers here. Whereas you can see we find sellers down here. So all sorts of details here in the order flow that we're starting to comprehend already. So we're looking, at this point we'd be looking for a retest back up to the high and maybe price discovery to the high side. Okay, because we have more aggressive volume trading at a higher area. And that's exactly what we got. And in fact, if we scroll forward here a bit, we have that same setup here. Again, here's the first one. Here's the second one. So here's that first retest to where we broke from here. And then here's the second one. Here's that retest right here. So same pattern. And these are excellent areas for understanding the order flow. And it's a potential trading strategy here. Now we cover that in the educational course. But anyway, let me continue on here. So we're just looking at these two elements and already getting a lot of information. Okay, the third element here is the, and let's go to the current market for the moment, is the dome, the depth of market. So here's our price ladder. Everything to the right of this vertical white line here is the live market. So this is current best bid and offer here with the dashed lines. Okay, this number here is our last traded volume. And then you see our price ladder here. In the COB column, it stands for current order book. You can see best bid and offer here. And then you can see the liquidity at these areas. The numbers here in the column. These are traders, and let's zoom in a little bit more. These are traders who are lined up in these areas here to provide liquidity. They wanna be sellers up above current price and they wanna be buyers down here. So we know exactly where these traders are lining up and providing liquidity. You can note, however, that these numbers are constantly changing, right? And although we get lots of insight with the current market, the problem is when those numbers change, we have no history of understanding what happened at that area, right? Because the number has changed and refreshed. And that problem is solved with the book map heat map. So we'll turn on the heat map here and this is that final piece of data. So areas of high liquidity are painted bright orange here with using this heat map here. So over here, dark gray or black is very low liquidity. Blue is higher, white is higher yet. And then yellow and then finally orange is the highest. So areas of high liquidity here in the book, 103 contracts up here is orange, okay? And you can see the reference here, right? So we're starting to add liquidity in here. So when these numbers change, you'll see the heat map change, okay? Where this becomes insightful and useful is not just for the current market, but the historical market because everything to the left of the vertical white line here is historical. So we just captured that change here in liquidity. They provided higher liquidity here at 66.13 and a half. They pulled it, added a little higher for a moment and then they just pulled it completely. So now we have an understanding of this player up here in the auction. And we're starting to understand where they are interested in dealing and we can start to note their behavior. Now look at them getting more aggressive here, providing liquidity down at this level at 66.12 and then also at this guy's jumping back in or someone's jumping back in here at 13 and a quarter, okay? Just pulled and it looks like they added up here, okay? So look at the behavior here. This would be rather difficult and challenging to put together in a dome, okay? So let me use the crosshairs here and you can see here, jumped into the book, provided high liquidity and then the moment that he jumps out, jumps up here and provides liquidity. Probably the same player. Probably this guy is probably this guy too, which is obviously the same player because as soon as he pulls, he adds here and then jumps out, okay? So all sorts of understanding of this auction and where traders are lining up to trade and deal and that's an important part of understanding the market and so you're able to now use your dome, not only for the current market, but for the historical market, okay? So you can start to gauge their intent to trade at some of these levels and then if you see that they're still interested in the current market there, well maybe you wanna be along with them or maybe these are targets. There's all sorts of ways of reading this and that's what we go into more depth in the advanced webinar, okay? We're also able to make the distinction between fake and real liquidity. Okay, so for example, in this area here, it looks like they stayed in the book. They may have pulled at the last moment here so we can make that distinction. We'll click on the move tool and hover over here and then just with my center mouse wheel zoom in really quickly and here's our answer, okay? So high liquidity that was here at this 66.12 and they stayed in here for a little bit and started to trade into it just a little bit and then they pulled, okay? A lot of the liquidity is pulled. We can use the data tip tool and get exactly what happened here. So we have the date, the time and then the liquidity here on the ask at this price level, okay? So over here was 90 contracts. They start pulling as price is coming up toward them down to 88 and then we can see that it was down to 80 and then down to 68, 67 and then 65 in this area here. So nice subtlety, we're using this colored heat map. We can see just these small distinctions in the liquidity that was pulled. So the majority, about a third of that liquidity was pulled at this area, okay? And we see some trades that took place here but look at our volume column, let's see here at this point. Our volume column, okay, so not so bad. 80 contracts traded here, as you can see here, 79 traded here and they were providing, what around 52 or 49 as you can see here, I'm sorry, 49 was last trade. So yeah, I mean, they're pulling the liquidity but they're also getting filled at this area. Okay, so it's a little bit of both, a little bit of pulling as well as getting filled and staying in that book, okay? So this was partially absorbed, right? Now we know that, that's fact, okay? So we know that larger players are starting to get interested up at this area here. Well, we can see that also in this area here, it looks like in this area here as well, it looks like some partial absorption in some of these little areas. So there are a lot of other areas here so they're absorbing on the way up. And finally, if they continue to absorb with high liquidity or at least higher liquidity in some of these areas, well, maybe the buying pressure starts to dwindle, right? And you can see that's kind of what happened here. In fact, look at the volume that traded up at this higher high here that made a higher high by just a tick. We can see it's just there's very little contracts that traded up here, okay? In fact, four, right? Our volume column is showing that. I can hover over this and it gives me volume of three at this moment here, okay? So that was one of the trades. And okay, so we're starting to understand, well, that the buying pressure is drying up, okay? So start to look for sideways activity based on what we know from this auction and the way that this liquidity was filled and absorbed, okay? So all sorts of ways of comprehending the context of the auction as well as the traded volume, okay? And we can see all of this within the microstructure, okay, which is key, okay? So let's go back to originally where we were with that microstructure, that idea. Here's another microstructure here. In fact, I can outline it with the rectangle here, all right? So we came up and went sideways for a bit and then broke down, okay? Look at the retest came back up to twice, okay? Right to where we broke from, okay? I don't see any of that activity here in the candlestick chart, all right? I just see a big long wick up here and then kind of a common looking bar here. So understanding the details here and getting this kind of level of transparency into price and the auction and the transactions is really gonna help you, okay? So anyway, that's the basics of a book map and if you're signed up for the trial or a current customer, then we'll see you over in the advanced webinar in just a few minutes, okay? All right, thanks for coming guys, take care.


It's a great pleasure to be here to represent his Excellency, the President of the Federal Republic of Nigeria, President Mohamed Ibuari, and what I'll be reading in the next few minutes is his speech, is the President's speech. I also bring his personal greetings and felicitations and a special congratulatory message to the Ministry of Science and Technology and to all the participants at this very important event. So it's a pleasure to be here at this Technology and Innovation Expo, which is aimed at showcasing research and development results and the products and services of inventive minds in the country. The Expo is particularly important to us from the policy and the practical perspective, especially as we pivot towards innovation as a key to economic diversification and recovery. The theme, science, technology, and innovation for economic recovery and sustainability amidst COVID-19 challenges, end of quote, is particularly relevant given the new challenges and the fresh opportunities presented by the COVID-19 pandemic. No nation of the world has ever developed without proper utilization of science and technology, and we are fully committed to the belief that this must be the path for Nigeria as well. We have some of the brightest and best minds in the world in the innovation economy, and I'm convinced that this cohort can and should be the vanguard of our efforts not only to foster economic recovery, but to reposition Nigeria entirely as an innovator's haven. I'm aware of the efforts of the Federal Ministry of Science and Technology in its contribution to the provision of homegrown solutions, especially those to prevent and or minimize the effects of the pandemic on the healthcare system of the nation by constituting ministerial committees on the COVID-19 herbal remedies and natural compounds to authenticate claims of anti-COVID-19 products produced by scientists, researchers, and traditional medicine practitioners in Nigeria. The COVID-19 pandemic has asked tough questions of our national capabilities in the area of research and innovation, and I'm gratified to report that we are competently answering these questions through the commendable efforts of our researchers and scientists. It will be recalled that the first recorded case of COVID-19 in sub-Saharan Africa was reported on February 27th, 2020, and this was an Italian man living in Nigeria who had just returned from Milan from Milan in Italy. What is less well known is that shortly after the patient was identified, a sample of the virus was sent to the African Center of Excellence for Genomics of Infectious Diseases at the Redeemer's University, Ede Ocean State. There, a team led by Professor Kristin Happie analyzed the sample and was able within 48 hours to share the very first genome sequence of the severe acute respiratory syndrome Coronavirus 2 SARS-CoV-2 from Africa with the global science community. This finding was shared faster than what was been done in many developed countries of the world. More importantly, it was also much faster than sending it to a laboratory overseas. The last bit is very important as it is groundbreaking, not so long after test samples had to be flown out of the country for examination. This is no longer the case because thanks to the efforts of our medical scientists and agencies like the Nigerian Center for Disease Control, NCDC, we now have the capacity to process samples internally. Last December, the Nigerian Institute of Medical Research, NIMR, launched a new set of COVID-19 test kits that can produce results in 57 minutes. The new kit was designed by Joseph Shaibu, a molecular virologist at the NMIR. These are a few examples of how Nigerian scientists and technologists are answering the demand of the present moment and providing solutions to our problems. As a government, we are committed to providing an enabling environment for the science and technology sector in order to unlock the enormous potential for innovation, for wealth creation and economic growth. We are currently working to bridge the digital divide by increasing access to broadband connectivity with our national broadband plan, which was launched just this year. The plan is aimed at achieving 90 percent broadband penetration by 2025. The plan will give special attention to the unserved and underserved areas when deploying telecom services. To achieve this, the federal government has also engaged with the state governors at the national economic council level on the right of way charges for laying of broadband infrastructure, such as fiber optic cables. This reduces the initial cost for broadband service providers in order for them to lay the infrastructure needed to provide broadband services. Many states have already complied and reduced the rates to as low as 140 naira per meter, while some states have completely removed the charges. We are pursuing this cause because we recognize that internet access and broadband penetration are pillars of the innovation economy. In the past few years, we have also made considerable improvements in the budgetary allocation to the ministry. This has helped increase research and innovation with the aim of achieving sustainable development. We are happy that this has been achieved in line with the decision taken of the African Union's Executive Council in 2006 to establish a target for all member states of one percent of GDP investment in research and development in order to improve innovation, productivity and economic growth. We are aware that only a few African countries have met this target, but as a result of the challenges of this critical sector of the economy, we will allocate a minimum of 0.5 percent of our GDP to research and innovation as a way to fast track meaningful development. In February 2018, I issued Executive Order Number 5, EO5, by which all ministries, departments and agencies of government were directed to engage indigenous professionals in the planning, execution and design of national security projects and maximize in-country capacity in all contracts and transactions with science, engineering and technology components. Executive Order Number 5 was inspired by the recognition of the vital role of science, technology and innovation in national economic development, especially in promoting domestic goods and services. In a statement of our strategic intent to the presidential order for planning and execution of projects, promotion of Nigerian content in contracts in science, engineering and technology, to harness domestic talents and develop indigenous capacities in science and technology, to promote national competitiveness and productivity across all sectors of the economy. This administration will continue to support the science and technology and innovation sector by expanding the opportunities open to those that are working in those fields. This expo is a practical demonstration of our commitment. Today, I urge all researchers, inventors and innovators who are participating in this expo to be steadfast as the government has confidence that your results, your products and services will help make Nigeria a truly great nation, respected all over the world for its exploits in science and technology. I'm confident that through the hard work and determination and by effectively harnessing our potentials in science, technology and innovation, we will overcome the COVID-19 pandemic and build a nation that meets the aspirations of all our citizens and earns respect of the world. It is therefore my very special pleasure to declare open the 2021 Technology and Innovation Expo. Thank you and God bless the Federal Republic of Nigeria.


Simifugian, a component of the root of Sipashikovia divericata, has been shown to have an analgesic effect when administered intrathecally. It was found to reduce the flinch response in both phases of the formalin test, indicating its potential use as an analgesic agent. At lower dosages, it demonstrated an anti-inflammatory effect, while at higher dosages it exhibited a non-inflammatory analgesic effect. This article was authored by Hyeon Young Lee, Young Joon Ki, Soo Young Park, and others.