So, before we embark in the analysis, what are we hoping to understand? Well, it seems intuitively clear is that there is going to be some trade off between the two resources of the bloom filter. One resource is space consumption, the other resource is essentially correctness so the more space we use, the larger number of bits, we'd hope that we'd make fewer and fewer errors. And then as we compress the table more and more, we use bits more and more for different objects then presumably the error rate is going to increase. So, the goal of the analysis that we're about to do is to understand this trade off precisely at qualitative level. Once we understand the trade off occur between these two resources, then we can ask is there is a sweet spot which gives us a useful data structure? Quite small space and quite manageable error probability. So the way we're going to proceed with the analysis, we'll be familiar to those of you who watched the open addressing video about hash tables so to make the mathematical analysis tractable, I'm going to make a heuristic assumption The strong assumption which is not really satisfied by hash functions you would use in the practice. We're going to use that assumption to derive a performance guarantee for bloom filters but as all as any implementation you should check that your implementation actually is getting performance comparable to what the idealizing analysis suggest. That said, if you use a good hash function and if you have a non-pathological data, the hopes and this is going out many empirical studies is that you will see performance comparable to what this heuristic analysis will suggest. So, what is the heuristic assumption? Well, it's going to be again familiar from my hashing discussions. We're just going to assume that all the hashing is totally random. So, for each choice of a hash function hi and for each possible object ax, the slots, the position of the array which the hash functions gives for that object is uniformly random and first of all and it's independen t from all other outputs of all hash functions on all objects. So the set up then is we have n bits. We have a data set, S which we have inserted into our bloom filter. Now our eventual goal is to understand the error rate or the false positive probability. That is the chance that an object which we haven't inserted into the bloom filter looks as if it has been inserted into the bloom filter but as a preliminary step, I want to ask about the population of 1s after we've inserted this data set S into the bloom filter. So, specifically let's focus on a particular position of the array and by symmetry it doesn't matter which one. And let's ask what is the probability that a given bit, a given position on this array has been set to one after we've inserted this entire data set S? Alright, so this, this is a somewhat difficult quiz question actually. The correct answer is the second answer. It's one - quantity one - 1/n raised to the number of hash functions k the number of objects cardinality of S, that's the probability let's say the first bit of the bloom filter has been set to one after the data set S has been inserted. So the, maybe the easiest way to see this is to first focus on the first answer. So, the first answer is going to be the probability I claim that the first bit is zero after the entire data set has been inserted. Then of course it's probably it's a one, is just the one - its quantity which is equal to the second answer. So we just seem to understand why the first choice is probably the first bit = zero. Well, it's initially zero, remember stuff is only set from zero to one. So we really need to analyze the probability that this first bit survives all of these darts that are getting thrown to the bloom filter over the course of this entire data set being inserted. So there, the cardinality of these objects each get inserted on an insertion k darts uniformly at random and independent from each other or effectively thrown at the array at the bloom filter. Any position of the dart hits, gets set to one. Maybe it was one already but if it was zero, it gets set to one. If it's one then it stays one. So, how is this first pick going to stay zero? We'll have to be missed by all of the darts. A given dart, a given bit flick is uniformly likely to be any of the n bits so the probability of the ones that being this bit is only 1/n but, if it even it's fortunately somebody else? Well, that's one - 1/n so you have a chance of surviving a single dart with probably one - 1/n There is the number of hash functions k the number of objects cardinality that's a dart being thrown. Right k per object that gets inserted so the overall probability of eluding all of the darts is one - one or n raised to the number of hash functions k the number of insertions cardinality of S. Again, the probability that is one which is the one - that quantity which is the second option in the quiz. So, let's go ahead and resume our analysis using the answer to that quiz. So, what do we discover, discover the probability that a given bit is one, is one - quantity one - 1/n or n is the number of position raised to the number of hash functions k the number of insertions cardinality of S. So, that's the kind of messy quantity so let's recall a simple estimation facts that we used once earlier. You saw this when we analyzed cardinals construction algorithm and the benefit of multiple repetitions or cardinals contraction algorithm. And the trick here is to estimate a quantity that's on the form of one + x or one - x by either the x or the - x as the case maybe. So you take the function one + x which goes through the points -ten and 01. And of course it's a straight line and then you also look at the function e to the x. Well, those two functions are going to kiss at the point 0,1 and everywhere else e to the x is going to be above one + x. So for any real value of x we can always upper bound the quantity one + x by either the - x. So let's apply this fact to this quantity here, one - 1/n raise to the k cardinality of S. We're going to take x to the - 1/n so that gives us an upper bound on this probability of one - e to th e - k the number of insertions over n, okay? So that's taking x to the - 1/n. Let's simplify and finalize a little bit further by introducing some notation. So, I'm going to let b denote the number of bits that were using per object. So this is the quantity I was telling you to think about as eighth previously. This is the ratio n, the total number of bits divided by the cardinality of S. So, this green expression becomes one - e^k where b is the number of bits per object. And now we're already seeing this type of trade off that we're expecting. Remember we're expecting that as we use more and more space, then the error rate we think should go down so if you can press the table a lot or use bits for lots of different objects that's when you start going to see a lot of false positives so in this light blue expression if you take the number of bits per objects with the number space, the amount of space, little b if you take that going very large expanding to infinity, this exponent to zero. So either the -zero is one. So overall, this probability of a given bit being one is turning to zero. So, that is, the more bits you have, the bigger space you have. The, well, the smaller of the fraction of 1s. The bigger the faction of 0s. That should translate to a smaller false positive probability unless we will make precise on the next and final slot. So let's, let's rewrite the upshot form the last slide but probability that a given bit is equal to one is that at above by one - e to the - k over b where k is the number of hash functions and b is the number of bits we're using per object. Now this is not the quantity that you care about. The quantity we care about is a false positive probability where something looks like it's in the bloom filter even though it's never been inserted so it's focused on some object like some IP address which is never ever been inserted into this bloom filter. So for a given object x which is not in the data set, that this has not been inserted into the bloom filter or what has to happen for us to have a success ful look up for false positive for this object? Well each one of its k bits has to be set to one. So, we already computed the probability that a given bit is set to one. So, what has to happen for all k of the bits that indicates x's membership in the bloom filter all k of them has to be set to one. So we just take the quantity we computed on the previous slide and we raise that to the kth power. Indicating that it has to happen k different times. So believe it or not we now have exactly what we wanted. What we set out to do which is derive a qualitative understanding of the intuitive trade off between the one hand space used and on the other hand on the error probability. The false positive of probability. So, we're going to call this green circle quantity and name it. We'll call it epsilon for the error rate and again all errors are false positives. And again as b goes to infinity, as we use more and more space, this exponent goes to zero so one - e to that quantity is going to zero as well. And of course, once we power it through the kth power, it gets even closer to zero. So if the bigger b gets the small of this error rate epsilon gets. So now let's get to the punch line. So remember the question is, is this data structure actually useful? Can we actually set all of the parameters in a way that we could both really usefully small space but a tolerable error epsilon? And, of course we wouldn't be giving this video if the answer wasn't yes. Now one thing I've been alluding all along is how do we set k? How do we choose the number of hash functions? I told you at the very beginning We think of k as a small constant like 2345. And now that we have this really nice qualitative version of how the error rate in the space trade off with each other. We can answer how to set k. Namely set k optimally so what do I mean? Well, fix the number of bits that you're using per object. Eight, sixteen, 24, whatever. For fixed b, you can just choose the k that minimize the screen quantity. That minimizes the error rate epsilon. So, how do you minimize t his quantity? Well, you do it just like you learn in calculus and I'll leave this as an exercise for you to do in the privacy of your own home. But for fixed b, the way to get this green quantity epsilon as small as possible is to set the number of hash functions k to be roughly the natural log of two. That's a number of < one notice that's like .693 b. So, in other words the number of hash functions for the optimal implementation of the bloom filter is scaling linearly than the number of bits that you're using per object. It's about .693 the bits per object. Of course this is generally not going to be an integer so you just pick k either this number rounded up or this number rounded down. But, continuing the heuristic analysis, now that we know how to set k optimally to minimize the error for a given amount of space we can plug that value of k back in and see well, how does the space and the error rate trade off against each other and we get a very nice answer. Specifically, we get that the error rate epsilon is just under an optimal trades to the number of hash functions k decreases exponentially in the number of bits that you use per object. So, it's roughly one half raised to the natural log of two or .693 roughly the number of bits per object b. But, again the key qualitative point here is notice that epsilon is going down really quickly as you scale b. If you double the number of bits that you're allocating per object, you're squaring the error rate and for small error rates, squaring it makes it much, much, much smaller. And of course this is just one equation in two variables. If you prefer, you can solve this equation to express b, the space requirement as a function of an error requirement. So if you know that the tolerance for false positives in your application is one percent you can just solve this for b and figure out how many bits per object you need to allocate. And so rewriting what you get is that the number of bits per object that you need is roughly 1.44 the log base two of one over epsilon. So, as expected as epsilon gets smaller and smaller, you want fewer and fewer errors, the space requirements will increase. So, the final question is, is it a useful data structure? Can you set all the parameters so that you get you know, really interesting space error trade off and the answer is totally. So, let me give you an example. Let's go back to having eight bits of storage per object so that corresponds to b = eight. Then, what this pick formula indicates is we should use five or six hash functions and already you have an error probability of something like two percent which for a lot of the motivating applications we talked about is already good enough. And again, if you double the number of bits to say sixteen per object, then this error probability would be really small. Pushing you know one in 5,000 or something like that. So, to conclude at least in this idealized analysis which again, you should check against at any real world implementation although empirically, it is definitely achievable with well implemented bloom filter in nonpathological data to get this kind of performance even with really a ridiculously minuscule amount of space per object much less generally than storing the object itself, you can get fast inserts, fast look ups, you do have to have false positives but with a very controllable amount of error rates and that what's make bloom filters a win in a number of applications.