{"id":406223,"date":"2024-06-29T18:48:04","date_gmt":"2024-06-29T18:48:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=406223"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=406223","title":{"rendered":"<span>Measuring Traffic Rate by Means of U-models<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ko\/ay\/op\/koayopm8caby70zokumllg3xzyk.jpeg\" alt=\"stream rate art\" data-src=\"https:\/\/habrastorage.org\/webt\/ko\/ay\/op\/koayopm8caby70zokumllg3xzyk.jpeg\" data-blurred=\"true\"\/><br \/>  <sup>Measuring of stream rate in an artist&#8217;s impression.<\/sup><\/p>\n<p>  In one of our <a href=\"https:\/\/qratorlabs.medium.com\/rate-detector-21d12567d0b5\">previous publications<\/a>, we talked about a way to measure event stream rate using a counter based on exponential decay. It turns out that the idea of such a counter has an interesting generalization. This paper by Artem Shvorin and Dmitry Kamaldinov, Qrator Labs, reveals it.<br \/>  <a name=\"habracut\"><\/a><br \/>  Our immersion plan is as follows. First, let us look at and analyze a few examples of how events are counted and the rate of the stream is estimated in general. The next step is to see a generalization, namely some class of counters, which we call the u-model. Next, we explore what useful properties u-models have and propose a technique for constructing an adequate rate estimate.<\/p>\n<h1>1\u00a0\u00a0 Examples of Counters<\/h1>\n<p>  Without limiting the generality, we may assume that an event counter is described by its state <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/>, which, upon the arrival of an event at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/>, is updated according to some rule:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d34\/960\/dc1\/d34960dc1c6607e7f21b2d48fa0a18c3.svg\" alt=\"$ s\\mathop{\\mapsto}^t s'. $\" data-tex=\"display\"\/><\/p>\n<p>  The state is not necessarily expressed by a number, but for feasibility reasons we may assume that it is representable by a finite set of bits.<\/p>\n<p>  In some cases, events are weighted, and the weight of the event <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/499\/78e\/f12\/49978ef12ee6820ac7fc4607771a3586.svg\" alt=\"$w$\" data-tex=\"inline\"\/> must be taken into account when updating the state:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/911\/68c\/48f\/91168c48fd04752fe8d6125ebe60f6c8.svg\" alt=\"$ s\\mathop{\\mapsto}^{t,w} s'. $\" data-tex=\"display\"\/><\/p>\n<p>  But at first, we will consider simple unweighted events, and we will add weight later when we need it. That will not be difficult at all.<\/p>\n<p>  In this article, we will limit ourselves to considering only deterministic counters, that is, those for which the update rule is given by a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/11b\/758\/146\/11b758146289a56a53c4ded2891c94e1.svg\" alt=\"$s'=update(s,t)$\" data-tex=\"inline\"\/>. But in general, it may be useful to add some randomness to this mechanism; we recently talked about it [7] and will probably continue to do so.<\/p>\n<p>  It should also be possible, knowing the state of the counter, to estimate the rate of the stream. Generally speaking, the notion of stream rate is non-trivial, and we will discuss it in more detail later. For now, we will just assume that the counter model has some nominal estimate as a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ef8\/052\/74f\/ef805274fb0dceef5255577712da2ea0.svg\" alt=\"$r(s,t)$\" data-tex=\"inline\"\/>, written out of some design considerations.<\/p>\n<h2>1.1\u00a0\u00a0 Linear Counters: Counting All Events<\/h2>\n<p>  The simplest thing one may think of is to just count the number of events that have occurred since we started. That is, when an event arrives, we do this:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/144\/c7e\/d5d\/144c7ed5d7cc33426872872974f3ad06.svg\" alt=\"$ s \\mapsto s + 1. $\" data-tex=\"display\"\/><\/p>\n<p>  We will call such counters <i>linear<\/i>.<\/p>\n<p>  The estimate is the average rate over the entire history:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/5f3\/ceb\/4c0\/5f3ceb4c0ecd27a34cacda5f347d1a54.svg\" alt=\"$ r(s,t) = s\/t. $\" data-tex=\"display\"\/><\/p>\n<p>  Some problem may occur due to counter overflow. There are also questions about defining the estimate: here, very old events have the same effect on the rate estimate as recent ones.<\/p>\n<h3>1.1.1\u00a0\u00a0 Sliding Window Event Counting<\/h3>\n<p>  To eliminate the above drawbacks of linear counters, one may count the number of events not since the creation of the world but only those that occurred no more than <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c6b\/38e\/9e5\/c6b38e9e57593c513299660fe8151d5f.svg\" alt=\"$T$\" data-tex=\"inline\"\/> cycles ago. This time interval of length <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c6b\/38e\/9e5\/c6b38e9e57593c513299660fe8151d5f.svg\" alt=\"$T$\" data-tex=\"inline\"\/> is usually called a window, and it is sliding because it shifts a step forward with each cycle.<\/p>\n<p>  A naive implementation assumes to remember all events in the window, thus requiring <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/81d\/a51\/f3d\/81da51f3d83f4b43a696487190dc9d73.svg\" alt=\"$O(T)$\" data-tex=\"inline\"\/> of memory. However, there are ways to save resources in trade-off for reduced precision, such as described in [6]. The update rule is expressed in a rather complicated way, while the average rate over time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c6b\/38e\/9e5\/c6b38e9e57593c513299660fe8151d5f.svg\" alt=\"$T$\" data-tex=\"inline\"\/> serves as the estimate:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/62a\/77e\/3a3\/62a77e3a3465ce187479319f22f0f3a4.svg\" alt=\"$ r(s,t) = s\/T. $\" data-tex=\"display\"\/><\/p>\n<p>  Unfortunately, such linear counters are unsuitable for our purposes: we can still tolerate a decrease in accuracy, but <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/067\/97e\/ffd\/06797effd37b866e6b91503bd53c58b4.svg\" alt=\"$O(\\log T)$\" data-tex=\"inline\"\/> in memory and complexity is too costly, even for small <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c6b\/38e\/9e5\/c6b38e9e57593c513299660fe8151d5f.svg\" alt=\"$T$\" data-tex=\"inline\"\/>.<\/p>\n<h2>1.2\u00a0\u00a0 EDecay: the Exponential Decay<\/h2>\n<p>  The idea of the decay counter is inspired by the well-known concept of radioactive decay [4]. Its essence is that the amount of undecayed matter decreases over time according to an exponential law:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/db6\/53f\/29a\/db653f29a78ae754868bf1a9f55cc3f8.svg\" alt=\"$v(t) = v_0 e^{-\\lambda t},$\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ef9\/425\/a2a\/ef9425a2a145505855dd8669c7795275.svg\" alt=\"$v_0$\" data-tex=\"inline\"\/> is the amount of matter at the initial (zero) moment of time, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/91b\/9ea\/0de\/91b9ea0dea5c5e29ac154df74d97d53d.svg\" alt=\"$\\lambda$\" data-tex=\"inline\"\/> is some parameter, the so-called decay constant.<\/p>\n<p>  It is more convenient to rewrite this expression in the following form:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/32f\/52d\/69e\/32f52d69ebeb934840db1f8c5f0a4742.svg\" alt=\"$v(t) = v_0 \\alpha^{-t},$\" data-tex=\"display\"\/><\/p>\n<p>  replacing the parameter. For more details on parameterization of counter models, see Section A of the Appendix.<\/p>\n<p>  Relying on this mechanism, we can build an event counter as described in our article [1].  <\/p>\n<blockquote><p>By definition, we will assume that each type of event corresponds to the value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/>, which has a physical meaning of \u201cquantity of matter\u201d and depends on time in such a way that it sharply increases by one at the occurrence of the event and decreases in the remaining time in accordance with the exponential law shown above.  <\/p><\/blockquote>\n<p>  That is, to account for a new event arriving at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/>, one must first apply the decay and then increase the counter by one:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e3f\/1ba\/20a\/e3f1ba20a5754d270e5a9bcf86e3d7a7.svg\" alt=\"$ \\begin{equation*} v_{new}(t) = v(t) + 1 \\equiv v(t_0)\\alpha^{-(t - t_0)} + 1, \\end{equation*} $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a92\/789\/b4e\/a92789b4eafb7478d750779992755ab3.svg\" alt=\"$t_0$\" data-tex=\"inline\"\/> is the arrival time of the previous event.<\/p>\n<p>  To be able to use this, we need to figure out how to store the counter in memory. The simplest way to represent the state of the counter is to use a pair of numbers <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a3b\/08d\/7dc\/a3b08d7dc6d1500e82cb0cc8341a5a2f.svg\" alt=\"$(v, t_0)$\" data-tex=\"inline\"\/>, where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a92\/789\/b4e\/a92789b4eafb7478d750779992755ab3.svg\" alt=\"$t_0$\" data-tex=\"inline\"\/> is the time of the last update, and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> is the amount of matter at that time. In this case, the update rule and estimation may be written as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/67b\/fd7\/78d\/67bfd778d457254cb549e08f1bd74a95.svg\" alt=\"$ \\begin{align*} (v, t_0) &amp;\\mathop{\\mapsto}^t (v \\alpha^{-(t - t_0)} + 1, t) \\\\ r((v, t_0), t) &amp;= v \\alpha^{-(t - t_0)}. \\end{align*} $\" data-tex=\"display\"\/><\/p>\n<p>  In the article [1] we take a detailed look at such counters. An important idea that is relevant to mention here is a lower cost representation of the counter state as a <i>single<\/i> number <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/>, the so-called <i>absolute value<\/i>, which holds all the information needed to work with the counter.  <\/p>\n<blockquote><p>The value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> is not explicitly stored in memory but can be computed at any time. Instead, the value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> is stored, such that at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> the value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> is expressed as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/053\/b7f\/cf8\/053b7fcf8274ca1d2da2b67b2d242bf8.svg\" alt=\"$ v = \\alpha^{s-t}. $\" data-tex=\"display\"\/><\/p>\n<p>  <\/p><\/blockquote>\n<p>  Without going into detail, let us just say that with this approach, the update rule and estimation take the form:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/805\/3c9\/12a\/8053c912a0262f4a4f6a37355f6816ae.svg\" alt=\"$ \\begin{align*} s &amp;\\mathop{\\mapsto}^t t+\\log_\\alpha(1 + \\alpha^{s - t}) \\hspace{10em}(1)\\\\ r(s, t) &amp;= \\alpha^{s - t}.\\nonumber \\end{align*} $\" data-tex=\"display\"\/><\/p>\n<h2>1.3\u00a0\u00a0 QDecay: a Faster Decay<\/h2>\n<p>  When looking at the exponential decay model, we can see that the decay function (in this case, the exponent) satisfies the differential equation:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/868\/cce\/f40\/868ccef40e9f1f914c2b95bf8b8e0ee0.svg\" alt=\"$\\frac{dv}{dt} = -\\lambda v.$\" data-tex=\"display\"\/><\/p>\n<p>  In fact, from a physical point of view, it is instead the other way around: this is the equation describing radioactive decay, and the exponent is its solution.<\/p>\n<p>  Indeed, the meaning of the equation is that the rate of decay is proportional to the amount of matter available. At some point, we intended to improve the model making decay faster, so we tried to take a quadratic law (QDecay) instead of a linear one:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b47\/b84\/2a1\/b47b842a1c9402764a6b0af676158f0f.svg\" alt=\"$\\frac{dv}{dt} = -\\lambda v^2.$\" data-tex=\"display\"\/><\/p>\n<p>  The solution is a new decay function:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8b1\/579\/bca\/8b1579bca016965b7ad9defad7e12e77.svg\" alt=\"$ v(t) = \\frac{1}{\\lambda t + 1\/v_0}, $\" data-tex=\"display\"\/><\/p>\n<p>  and it is really gotten steeper.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">As a matter of fact\u2026<\/b>                         <\/p>\n<div class=\"spoiler_text\">It is hardly correct to say that a hyperbola is steeper than an exponent. However, large values decay indeed faster (and vice versa for small values).  <\/div>\n<\/p><\/div>\n<p>  Similar to the model discussed previously (with exponential decay), here, we can represent the counter state as a single number <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/>. The corresponding update rule and rate estimate look like this:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c60\/c41\/f3a\/c60c41f3ada151d1ae35dcdeeaf9b002.svg\" alt=\"$ \\begin{align*} s &amp;\\mathop{\\mapsto}^t t - \\frac{t-s}{1 + \\lambda(t - s)} \\hspace{10em}(2) \\\\ r(s, t) &amp;= \\frac{1}{\\lambda(t - s)}.\\nonumber \\end{align*} $\" data-tex=\"display\"\/><\/p>\n<p>  The great thing here is that calculating the update function is cheap: it requires only elementary arithmetic operations, with only one division. That is, all we originally wanted was a faster horse (faster decay), but we got a new useful feature (cheaper calculations).<\/p>\n<p>  We could go further by providing a higher degree in the equation defining the decay function: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/9b1\/941\/5e0\/9b19415e0138670283e023c5f5ffc50a.svg\" alt=\"$dv = -\\lambda v^3 dt,$\" data-tex=\"inline\"\/> and so on, but the solution is more complicated, the calculations are more expensive, and the obvious benefit is somehow not noticeable. Rejected<\/p>\n<h2>1.4\u00a0\u00a0 SW: Averaging of Interpacket Interval<\/h2>\n<p>  Consider another approach to constructing counters, namely averaging. In this case, we will average the time interval between neighboring events. We call this value <i>the interpacket interval<\/i>, because we deal with network traffic, where the event is the arrival of a network packet, and the word \u201cinter-event\u201d has somehow not caught on.<\/p>\n<p>  Generally speaking, the point of this approach is that we have a sequence of values of some quantity (in this case, interpacket intervals) that changes too quickly to be used directly, and we want to smooth or average this sequence in some way.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Averaging is\u2026<\/b>                         <\/p>\n<div class=\"spoiler_text\">Let there be a sequence <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b44\/b69\/296\/b44b692967f0d7067f7a4a322177c717.svg\" alt=\"$\\langle p_n\\rangle$\" data-tex=\"inline\"\/>, then its average at the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35b\/a56\/5f3\/35ba565f36734f3a55aa01ac67868762.svg\" alt=\"$n$\" data-tex=\"inline\"\/>th step is defined as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7ce\/e95\/5a4\/7cee955a4cb7c99242c3026e0323899f.svg\" alt=\"$ \\overline{p}_n = \\frac{1}{n} \\sum_{i = 1}^n p_i. $\" data-tex=\"display\"\/><\/p>\n<p>  Here, we get the arithmetic mean of the last <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35b\/a56\/5f3\/35ba565f36734f3a55aa01ac67868762.svg\" alt=\"$n$\" data-tex=\"inline\"\/> members of the sequence.<\/p>\n<p>  This definition may be generalized. The weighted average of a sequence <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b44\/b69\/296\/b44b692967f0d7067f7a4a322177c717.svg\" alt=\"$\\langle p_n\\rangle$\" data-tex=\"inline\"\/> is the sum  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/469\/a87\/050\/469a870502c838c35625726613b4883a.svg\" alt=\"$ \\sum_{i = 1}^n \\omega_i p_i, $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7ae\/76a\/eef\/7ae76aeef39f866800cddc18d1ddbf1d.svg\" alt=\"$\\omega_i$\" data-tex=\"inline\"\/> are some weights such that <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b3b\/ef4\/b56\/b3bef4b5617affac7f15ff403eac03cd.svg\" alt=\"$\\omega_i\\ge 0, \\sum_{i}\\omega_i=1$\" data-tex=\"inline\"\/>.  <\/div>\n<\/p><\/div>\n<p>  Recall that the newer events are, the more interesting we find their contribution to the rate estimate. So it is natural to use weighted averaging instead of usual averaging, giving more weight to recent events. Weights may be chosen in different ways; now, let us try to take the weights as terms of a geometric progression. This way of summing up is called <i>exponential moving average<\/i> (EMA).<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">EMA averaging is\u2026<\/b>                         <\/p>\n<div class=\"spoiler_text\">The exponential moving average of the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b44\/b69\/296\/b44b692967f0d7067f7a4a322177c717.svg\" alt=\"$\\langle p_n\\rangle$\" data-tex=\"inline\"\/> sequence is defined as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/9e3\/56a\/c73\/9e356ac7306f3870862c38d049bafd50.svg\" alt=\"$ \\overline{p}^{EMA}_n = \\frac{1}{B}\\sum_{i = 1}^n (1-\\beta)^{n-i} p_i, $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1e8\/de3\/524\/1e8de35248111414596bcd8efaba119e.svg\" alt=\"$\\beta\\in(0,1)$\" data-tex=\"inline\"\/> is a parameter, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f7b\/426\/99a\/f7b42699aef5abe8bd9cac648cfa9057.svg\" alt=\"$B=\\sum_{i = 1}^n (1-\\beta)^{n-i}$\" data-tex=\"inline\"\/>.<\/p>\n<p>  Since there are very many events, i.e., <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35b\/a56\/5f3\/35ba565f36734f3a55aa01ac67868762.svg\" alt=\"$n$\" data-tex=\"inline\"\/> is large, we may assume that there were some dummy events <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d44\/d00\/b8d\/d44d00b8d713ff2e4c88b3e65be946f6.svg\" alt=\"$p_i$\" data-tex=\"inline\"\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/141\/f2c\/081\/141f2c08102c9425c428f89c1a136a31.svg\" alt=\"$i&lt;0$\" data-tex=\"inline\"\/> in the dim and distant past, whose contributions are taken with negligible weights <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/00e\/756\/88a\/00e75688af732018aa21fb8b2dc4bcd5.svg\" alt=\"$q^{n-i}$\" data-tex=\"inline\"\/>. Then it is more convenient to rewrite the definition as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8ba\/a90\/5fb\/8baa905fb34a99c53948929c9cca70c8.svg\" alt=\"$ \\overline{p}^{EMA}_n = \\beta\\sum_{i = -\\infty}^n (1-\\beta)^{n-i} p_i, $\" data-tex=\"display\"\/><\/p>\n<p>  since in this case <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cf9\/48c\/b05\/cf948cb055fdb8e7e7fa53fc925a2e99.svg\" alt=\"$B=\\sum_{i = -\\infty}^n (1-\\beta)^{n-i} = 1\/\\beta$\" data-tex=\"inline\"\/>.<\/p>\n<p>  One important advantage of EMA over other averaging methods is the ability to collapse a cumbersome sum into a recursive expression:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/070\/32c\/65d\/07032c65d5f4c308356606b1495a3a3a.svg\" alt=\"$ \\overline{p}^{EMA}_n = \\beta\\cdot p_n + (1-\\beta)\\cdot \\overline{p}^{EMA}_{n-1}. $\" data-tex=\"display\"\/><\/p>\n<p>  Thus, it is not necessary to store many old values of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/386\/f83\/e73\/386f83e7307d3935066f87e3f919d08b.svg\" alt=\"$p_n$\" data-tex=\"inline\"\/> for the calculations. By the way, it is the formula (3) is often taken as the definition of EMA [2].  <\/div>\n<\/p><\/div>\n<p>  Applying the exponential averaging formula to the interpacket intervals, we get:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/93a\/cbc\/ffe\/93acbcffe077b7d6c6be33c26d42ce0e.svg\" alt=\"$ v_n = \\beta\\cdot (t_n-t_{n-1}) + (1-\\beta)\\cdot v_{n-1}, $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8da\/1dd\/857\/8da1dd857a31954e50864744893448b0.svg\" alt=\"$v_n$\" data-tex=\"inline\"\/> is the desired EMA-averaged interpacket interval, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/6ed\/2c0\/4d9\/6ed2c04d9c4e6d4320bd22d42168c866.svg\" alt=\"$t_n$\" data-tex=\"inline\"\/> is the moment when the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35b\/a56\/5f3\/35ba565f36734f3a55aa01ac67868762.svg\" alt=\"$n$\" data-tex=\"inline\"\/>th event occurs.<\/p>\n<p>  This model is mentioned again in Section 4.3, where, in particular, we show how to express the counter state by a single number and simplify the calculations. For now, let us just write out the result.<\/p>\n<p>  Update the counter when an event occurs at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/>:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e83\/390\/de8\/e83390de81c94ada65f1f8c761d562cf.svg\" alt=\"$ \\begin{equation*} s \\mathop{\\mapsto}^t t + \\beta\\cdot(s-t).\\hspace{10em}(4) \\end{equation*} $\" data-tex=\"display\"\/><\/p>\n<p>  The reciprocal of the averaged interpacket interval serves as the rate estimate:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b8a\/ae3\/1e5\/b8aae31e500ce354b38c6b9b89f79754.svg\" alt=\"$ r(s,t) = -\\frac{\\beta}{1-\\beta}\\cdot\\frac{1}{s-t}. $\" data-tex=\"display\"\/><\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">Using EMA averaging, we can also obtain a model exactly coinciding with the decay model from Section 1.2. Instead of averaging the interpacket intervals, this deals with the value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/53c\/1ee\/2a0\/53c1ee2a0feb0f0f08783a92c79b31a1.svg\" alt=\"$p_t$\" data-tex=\"inline\"\/>, which could be called the momentary rate:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/333\/659\/ac5\/333659ac5c4e1fd561ef554e4ad3dde5.svg\" alt=\"$ p_t = \\left\\{ \\begin{array}{ll}1, &amp; \\mbox{if at the moment t an event occurred},\\\\ 0, &amp; \\mbox{otherwise}. \\end{array} \\right. $\" data-tex=\"display\"\/><\/p>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h2>1.5\u00a0\u00a0 Probabilistic Counters<\/h2>\n<p>  The idea of probabilistic counters is to change the counter state when an event arrives, not always, but with some probability. This probability may be defined in various ways, e.g.<\/p>\n<ul>\n<li>stay constant (binomial counters);<\/li>\n<li>decrease by a factor of 2 after each successful update (Morris counters);<\/li>\n<li>change after every <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/524\/18e\/c85\/52418ec8584307a92ef3942b0119e932.svg\" alt=\"$X > 1$&#187; data-tex=&#187;inline&#187;\/> of successful updates.<\/li>\n<\/ul>\n<p>  Probability counters make very efficient use of memory. For example, the original 8-bit Morris counters may be used to account for up to <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/937\/611\/9c5\/9376119c5cf364d60723f4f562b39a01.svg\" alt=\"$2^{256}$\" data-tex=\"inline\"\/> events. Their obvious disadvantage, however, is significant inaccuracy in estimating the number of events. We discuss such counters in detail in the article [7], and we also propose some extensions of known algorithms.<\/p>\n<h1>2\u00a0\u00a0 The Idea of the U-model<\/h1>\n<p>  If we look at the counters based on the idea of decay, we may notice this peculiarity: the state is described by a pair of numbers <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/692\/a31\/dc7\/692a31dc7aa39804a104caa6ecebdfe8.svg\" alt=\"$(v, t)$\" data-tex=\"inline\"\/>, but then it miraculously appears to be possible to express the state by a single number <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/>. Let us try to find a general principle by which this becomes possible for any counters of this type.<\/p>\n<p>  Let us temporarily forget the fact that in practice, the counter value must be discrete and represented by a relatively small number of bits, and, staying within the spherical cow concept, let us assume both the counter value and the event arrival time be real numbers, and the transformations over them also are real-valued functions. Later (see Section 3.3) we will learn how to discretize the models, making them usable in practice.<\/p>\n<h2>2.1\u00a0\u00a0 An Invariant of Decay<\/h2>\n<p>  Consider a section of the decay curve (see Fig. 1a). Let at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a92\/789\/b4e\/a92789b4eafb7478d750779992755ab3.svg\" alt=\"$t_0$\" data-tex=\"inline\"\/> an event was registered, and then on the interval <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/5f4\/f4c\/015\/5f4f4c0158f9f4586e2da94ae95071ef.svg\" alt=\"$[t_0, t)$\" data-tex=\"inline\"\/> there were no other events. Now we are at the point <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> going to account for a new event, or just to see what the value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> is, in order to estimate the rate. One may notice that from the point of view of an observer at the moment <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> there is absolutely no difference whether the last event occurred at the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c08\/034\/8fb\/c080348fb97a98f5a5797f279cdee2b3.svg\" alt=\"$(t_0, v_0)$\" data-tex=\"inline\"\/> point on the plot or at <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/545\/fa9\/992\/545fa9992c2be79fbc337274993542ea.svg\" alt=\"$(t'_0, v'_0)$\" data-tex=\"inline\"\/>. This fact seems to hint that storing two numbers as the counter state is redundant. Thus, the two formally different versions of reality are functionally equipotent. That is, they give the same effect:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c81\/95a\/5f8\/c8195a5f8220ae2b6d23bc3923847967.svg\" alt=\"$ (t_0,v_0) \\sim (t'_0, v'_0). $\" data-tex=\"display\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ie\/hy\/mi\/iehymio5xkgqchscsxx_el5p9ba.png\" alt=\"decay curves\" data-src=\"https:\/\/habrastorage.org\/webt\/ie\/hy\/mi\/iehymio5xkgqchscsxx_el5p9ba.png\"\/><br \/>  Generally speaking, we do not have a single decay curve, but a family <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d47\/e7b\/75d\/d47e7b75de4fa65ede594765c54e08db.svg\" alt=\"$v=v_s(t)$\" data-tex=\"inline\"\/> (see Figure 1b). Each of these curves describes a state of the counter. They may be enumerated somehow, and we may take the index of the curve as the counter state.<\/p>\n<p>  Let us now see how such a counter should be updated. Let <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> be the current state of the counter. According to the decay model, this means that in the absence of events, the value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> changes over time, remaining on the curve <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/90e\/d80\/8e6\/90ed808e6147df49219d3e07ff065e58.svg\" alt=\"$v_s(t)$\" data-tex=\"inline\"\/>. Let an event occur at some point <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/>. This means that the value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2ac\/211\/43d\/2ac21143d39638d2322c66f487d3efb6.svg\" alt=\"$v$\" data-tex=\"inline\"\/> increases stepwise by one (see Fig. 1c), that is, among the whole family of curves we must find the one that passes through the point <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/dad\/5a5\/4bf\/dad5a54bf4fc1d50093846dce38ff67c.svg\" alt=\"$(t, v')$\" data-tex=\"inline\"\/> where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e56\/19e\/f87\/e5619ef87c7af88362b152b03dea385c.svg\" alt=\"$v'=v+1$\" data-tex=\"inline\"\/>. Let <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d06\/c38\/120\/d06c3812048471f5f7078be4bfb67ee3.svg\" alt=\"$s'$\" data-tex=\"inline\"\/> be the index of the found curve, i.e.,  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/670\/50e\/020\/67050e02052da3b83aaf073db05bb1f5.svg\" alt=\"$ \\begin{equation*} v_{s'}(t) = v_s(t) + 1,\\hspace{10em}(5) \\end{equation*} $\" data-tex=\"display\"\/><\/p>\n<p>  then this is the value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d06\/c38\/120\/d06c3812048471f5f7078be4bfb67ee3.svg\" alt=\"$s'$\" data-tex=\"inline\"\/> to set as the new counter state.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">If one wants to count weighted events, the stepwise change should be not by one but by the weight of the event: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fcb\/97d\/e29\/fcb97de29222e0dba8ec4e6bcc87eb75.svg\" alt=\"$v'=v+w$\" data-tex=\"inline\"\/>.  <\/div>\n<\/p><\/div>\n<p>  It is not yet clear how to find the index of the desired curve, but it will come to light very soon.<\/p>\n<h2>2.2\u00a0\u00a0 Translational Symmetry<\/h2>\n<p>  In Fig. 1b decay curves <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/90e\/d80\/8e6\/90ed808e6147df49219d3e07ff065e58.svg\" alt=\"$v_s(t)$\" data-tex=\"inline\"\/> are depicted in such a way that they differ from each other only by a horizontal shift. Scientifically, this is called translational symmetry of the time [8]. We want to take this property as an axiom for our counter model. Indeed, it is logical to expect that, within the model, the decay process goes today in exactly the same manner as it did yesterday.<\/p>\n<p>  Mathematically, this property may be written as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8a1\/df4\/b6c\/8a1df4b6cd41ec3a4ce6e46c4e04b7a6.svg\" alt=\"$ \\forall t\\in\\mathbb{R}\\colon v_{s_2}(t) = v_{s_1}(t-\\Delta), $\" data-tex=\"display\"\/><\/p>\n<p>  that is, the curve <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f5e\/491\/ed5\/f5e491ed5e35ed6602f16e4f20863d41.svg\" alt=\"$v_{s_2}(t)$\" data-tex=\"inline\"\/> is obtained from the curve <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/773\/0ca\/53b\/7730ca53b3851c15bf19084686dfd5b0.svg\" alt=\"$v_{s_1}(t)$\" data-tex=\"inline\"\/> by shifting it to the right by some <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e64\/c1f\/f7d\/e64c1ff7d653566bca49c933d313f9e3.svg\" alt=\"$\\Delta$\" data-tex=\"inline\"\/>.<\/p>\n<p>  In general, curves may be enumerated any way you like, and you just need to be able to find the index of the new curve during the update operation. But it is more convenient to enumerate them in order so that the index <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> represents something meaningful, namely, a real number corresponding to the horizontal distance between the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/90e\/d80\/8e6\/90ed808e6147df49219d3e07ff065e58.svg\" alt=\"$v_s(t)$\" data-tex=\"inline\"\/> curve and the curve with zero index <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/534\/20f\/11f\/53420f11fc2b59c72b73274818a6ec49.svg\" alt=\"$v_0(t)$\" data-tex=\"inline\"\/>. Then, due to translational symmetry, any curve from the family may be very simply expressed as a shift of the curve number zero:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/284\/0e1\/7d8\/2840e17d8e38bf4df815763cfef0ac65.svg\" alt=\"$ \\begin{equation*} \\forall t,s\\in\\mathbb{R}\\colon v_s(t) = v_0(t-s)\\equiv \\mu(s-t).\\hspace{10em}(6) \\end{equation*} $\" data-tex=\"display\"\/><\/p>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">Here we introduce the notation <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/dec\/621\/08a\/dec62108a2b836de4c92c2e1a88bf390.svg\" alt=\"$\\mu(x) := v_0(-x)$\" data-tex=\"inline\"\/>, which is convenient because the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/658\/3bf\/7e6\/6583bf7e62f62291a44864774bbafe66.svg\" alt=\"$\\mu$\" data-tex=\"inline\"\/> increases monotonically. This will come in handy later in Section 2.4 in determining the rate.  <\/div>\n<\/p><\/div>\n<p>  Now, the update rule on an event arrival at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> may be expressed from equation (5) as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0a5\/41a\/d95\/0a541ad95ae7e2c3f4940ce395460dc7.svg\" alt=\"$ \\begin{align*} &amp;s' = t + u(s-t),&amp;\\\\ &amp;\\quad \\text{where } u(x) = \\mu^{-1}(\\mu(x) + 1).&amp;\\hspace{10em}(7) \\end{align*} $\" data-tex=\"display\"\/><\/p>\n<p>  Thus, the update rule appears as  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e45\/379\/126\/e4537912616e14ee205cbac5d01feda3.svg\" alt=\"$ \\begin{equation*} s \\mathop{\\mapsto}^t t + u(s-t),\\hspace{10em}(8) \\end{equation*} $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/163\/d33\/458\/163d33458a450077afe64ac18cb8b8f9.svg\" alt=\"$u(\\cdot)$\" data-tex=\"inline\"\/> is some function.<\/p>\n<p>  This rule looks so simple and universal that it may be taken as the definition. That is how we will define the u-model.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">If the decay function is given by a differential equation of such kind:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ef6\/39f\/a21\/ef639fa2154388f2c414e37a450067ab.svg\" alt=\"$ \\frac{dv}{dt} = f(v), $\" data-tex=\"display\"\/><\/p>\n<p>  then it is always easy to find an invariant for that the property (6) holds.<\/p>\n<p>  Indeed, the solution of the differential equation may be written as  <\/p>\n<p><p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e36\/0f8\/402\/e360f8402036e48e121b2407851f25fc.svg\" alt=\"$ F(v) - F(v_0) = t - t_0,\\quad\\mbox{where } F(v) = \\int \\frac{dv}{f(v)}. $\" data-tex=\"display\"\/><\/p>\n<\/p>\n<p>  Thus we can take <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/94a\/c3f\/afa\/94ac3fafae1641154b9e7a3c905a7190.svg\" alt=\"$s = t_0-F(v_0)$\" data-tex=\"inline\"\/> as an invariant, and the corresponding curve is expressed as <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b73\/0c4\/3d4\/b730c43d4850afddcc6066c27f9223e5.svg\" alt=\"$v_s(t)=F^{-1}(t-s)$\" data-tex=\"inline\"\/>.  <\/div>\n<\/p><\/div>\n<p>  Section 3.1 lists the formal properties that the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> must satisfy in order to build a workable counter model on its basis.<\/p>\n<h2>2.3\u00a0\u00a0 Absolute and Relative<\/h2>\n<p>  We may say that <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> is the <i>absolute<\/i> value of the counter, it is stored directly in memory, and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/249\/7d3\/a64\/2497d3a640597f2d68ea8cd6e4134c8a.svg\" alt=\"$x=s-t$\" data-tex=\"inline\"\/> is the <i>relative<\/i> value of the counter at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/>. Then it turns out that the update function works with the relative counter value: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/81b\/4d7\/fd8\/81b4d7fd876e5a20ee4b82bab1eac6e1.svg\" alt=\"$x' = u(x)$\" data-tex=\"inline\"\/>.<\/p>\n<p>  The fact that the update function works with the relative counter value reflects the decay principle: if no events occur, then the absolute value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> does not change, and the relative value automatically decreases over time. And the rate estimate, accordingly, also degrades. From the calculation point of view, it is very convenient: as long as there are no events, there is no need to do anything. It is very similar to inflation in economics: the state of the counter stands for banknotes lying under the pillow, and the rate estimate stands for the purchasing power of these banknotes, which degrade itself.<\/p>\n<h2>2.4\u00a0\u00a0 Rate Estimate<\/h2>\n<p>  For the decay model, the value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fc2\/eda\/47c\/fc2eda47c710d0e82c99afb90c5c4ede.svg\" alt=\"$\\mu(s-t)$\" data-tex=\"inline\"\/> by construction is the rate estimate, see formula (6). However, several problems arise with this definition. First, if we use the definition of the model through the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/>, it would be difficult to construct the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/658\/3bf\/7e6\/6583bf7e62f62291a44864774bbafe66.svg\" alt=\"$\\mu$\" data-tex=\"inline\"\/> (the functional equation (7) would be needed to solve). Secondly, it would be nice to check experimentally how adequately a particular counter <i>measures<\/i> the rate.<\/p>\n<p>  Preserving not the letter (from the formula (6)), but the spirit of the decay idea, we construct the rate estimate as a function of a single argument, namely, the relative value of the counter: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/aff\/1db\/c0f\/aff1dbc0f382f7276b5a1c9eac44b665.svg\" alt=\"$r(s, t) = r(s-t)$\" data-tex=\"inline\"\/>. Thus, the problem is set as follows: having an update function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0c0\/b02\/b0c\/0c0b02b0c0450d5417a1eb3a50293e7a.svg\" alt=\"$u(x)$\" data-tex=\"inline\"\/>, construct a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/25d\/570\/671\/25d570671efbeff5269adc992e9f3161.svg\" alt=\"$r(x)$\" data-tex=\"inline\"\/> that would be an adequate estimator of the rate.<\/p>\n<p>  It turns out that the u-model approach consists of implementing the following plan (yes, it looks a bit punkish).<\/p>\n<ol>\n<li>We take some models built from \u201cphysical considerations\u201d, and for each of them, we express the update rule through a u-function.<\/li>\n<li>Then we abstract away from the physical sense, leaving only the bare u-function. Now we can, without worrying about the sense, boldly change the u-function, for example, by choosing a computationally cheaper one.<\/li>\n<li>Finally, we figure out how to reintroduce meaning, i.e., to construct an adequate estimate of the rate.<\/li>\n<li>PROFIT!<\/li>\n<\/ol>\n<p>  In order to make this plan possible (the snag, obviously, is only clause 3), some constraints on the u-function would have to be imposed, and now let us try to figure out which ones. The reader, however, may skip these motivational considerations and jump directly to the definition of those constraints (9) on the u-function in Section 3.<\/p>\n<h3>2.4.1\u00a0\u00a0 A Uniform Stream<\/h3>\n<p>  Our company studies network traffic, and we may need to count network packets arrivals as items. In this case, they form a stream, and its rate is measured in packets per second (pps). Alternatively, we have to take packet size into account, so the size is considered the weight of an event, and correspondingly, the rate of such a weighted stream is measured in bits per second (bps). It may also be important to distinguish packets by their contents (source and\/or destination IP address, port number, protocol, etc.), then we group events by their type and create separate counters for each type.<\/p>\n<p>  Since we discuss here how to evaluate the rate of an event flow, we must first formalize the notions of the event and the event stream.<\/p>\n<blockquote><p><b>Definition<\/b> (event). Let us call an event a triple <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/18e\/6af\/718\/18e6af7185079854651ba260fcdca793.svg\" alt=\"$(id, w, t)$\" data-tex=\"inline\"\/>, where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> is the event arrival time, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2cf\/fed\/5c1\/2cffed5c1e65809d2bf2f7baa5f7bad5.svg\" alt=\"$w>0$&#187; data-tex=&#187;inline&#187;\/> is the event weight, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/bb5\/7ce\/522\/bb57ce522b43a820f66546c1c7751da2.svg\" alt=\"$id$\" data-tex=\"inline\"\/> is the event type, some stream identifier.  <\/p><\/blockquote>\n<p>  <\/p>\n<blockquote><p><b>Definition<\/b> (event stream). An event stream is defined as a sequence of events <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1f2\/0bb\/c84\/1f20bbc84c2fd24d8923787aa69b848e.svg\" alt=\"$\\mathcal{E}_k=(id_k,w_k,t_k)$\" data-tex=\"inline\"\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/baa\/363\/b5f\/baa363b5f47d8ecb9fa04ee0c46491d7.svg\" alt=\"$k\\in\\mathbb{Z}$\" data-tex=\"inline\"\/>. And the events in the stream must be ordered by time: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0dd\/c73\/b69\/0ddc73b69a9d37f3b8e3d42f3b9bcf4c.svg\" alt=\"$t_i\\le t_j$\" data-tex=\"inline\"\/> at <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/357\/b36\/f4f\/357b36f4ff1ffc35fda61f139bc7e6c9.svg\" alt=\"$i&lt;j$\" data-tex=\"inline\"\/>.  <\/p><\/blockquote>\n<p>  In most implementations of event accounting systems, the time is considered a discrete value: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c65\/22d\/05c\/c6522d05c686cf24ea10c5c3d4171359.svg\" alt=\"$t_k\\in\\mathbb{Z}$\" data-tex=\"inline\"\/>, but for theoretical reasoning, it may be convenient to generalize and consider the time continuous: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/abf\/1f4\/d05\/abf1f4d053dc3964700f7631cd4f788c.svg\" alt=\"$t_k\\in\\mathbb{R}$\" data-tex=\"inline\"\/>.<\/p>\n<p>  If we are interested only in events as such, e.g., we measure the number of packets in pieces per second, then the weight <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/499\/78e\/f12\/49978ef12ee6820ac7fc4607771a3586.svg\" alt=\"$w$\" data-tex=\"inline\"\/> may be assumed to be unity. It is also assumed that a single counter counts events of the same type, i.e., the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/bb5\/7ce\/522\/bb57ce522b43a820f66546c1c7751da2.svg\" alt=\"$id$\" data-tex=\"inline\"\/> field serves to distinguish different streams and does not play a role within a single counter.<\/p>\n<blockquote><p><b>Definition<\/b> (uniform stream). A deterministic uniform stream <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/047\/6a5\/9ce\/0476a59ce46741f2260e99f463fee990.svg\" alt=\"$\\langle t_k\\rangle$\" data-tex=\"inline\"\/> is defined as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d55\/058\/56e\/d5505856edc2a19ce87f2213ccc7cbc6.svg\" alt=\"$ t_k = pk,\\quad k\\in\\mathbb{Z}, $\" data-tex=\"display\"\/><\/p>\n<p>  Where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/aaa\/917\/7ef\/aaa9177efbc32e81750f7a6ea0586c69.svg\" alt=\"$p>0$&#187; data-tex=&#187;inline&#187;\/> is the stream parameter, i.e., the period between events. Then the rate of such a stream, by definition, is expressed as <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/195\/604\/17e\/19560417edf2c01a05239450255e6671.svg\" alt=\"$r=1\/p$\" data-tex=\"inline\"\/>.  <\/p><\/blockquote>\n<p>  Now we can express a way to measure the stream rate for any model. Consider a stream of some known rate <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b88\/ce3\/99f\/b88ce399fda6c8123ab168cb507210f2.svg\" alt=\"$r$\" data-tex=\"inline\"\/> affecting a counter and observe how the relative value of the counter changes; let the measured counter value be <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> after the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35b\/a56\/5f3\/35ba565f36734f3a55aa01ac67868762.svg\" alt=\"$n$\" data-tex=\"inline\"\/>th event.<\/p>\n<p>  We want the stream rate <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b88\/ce3\/99f\/b88ce399fda6c8123ab168cb507210f2.svg\" alt=\"$r$\" data-tex=\"inline\"\/> and the sequence of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> values to be somehow related. Then, being lucky, we could construct a rate estimation function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/25d\/570\/671\/25d570671efbeff5269adc992e9f3161.svg\" alt=\"$r(x)$\" data-tex=\"inline\"\/>.<\/p>\n<h3>2.4.2\u00a0\u00a0 An Attractor<\/h3>\n<p>  Studying with concrete examples the behavior of the u-model under the influence of a deterministic stream, we found that (at least for those examples) there is a notion of an attractor, which is somewhat informally described by the following properties.<\/p>\n<ul>\n<li>For every rate value of the incoming stream <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b88\/ce3\/99f\/b88ce399fda6c8123ab168cb507210f2.svg\" alt=\"$r$\" data-tex=\"inline\"\/>, there exists an attractor, i.e., such a subset of the relative counter values that if any value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/909\/ddf\/bc3\/909ddfbc34de31811c4f1ecbc12a5f6f.svg\" alt=\"$x_N$\" data-tex=\"inline\"\/> ended up in this attractor, then all subsequent values <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e03\/db3\/b2a\/e03db3b2a3ee2bcb98b73397416a9c83.svg\" alt=\"$n\\ge N$\" data-tex=\"inline\"\/> will also end up there. The attractor is an interval <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/da4\/859\/d9d\/da4859d9d269da5f46015f7f1899f87c.svg\" alt=\"$[\\check{x}, \\hat{x}]$\" data-tex=\"inline\"\/> (possibly degenerate, when both ends of it have merged).<\/li>\n<li>There is convergence: even if the relative value of the counter was outside the attractor, after several updates, it will get there or at least get as close to the attractor as possible.<\/li>\n<li>There is monotonicity: the position of the attractor depends monotonically on the rate of the incoming stream. That is, both ends of the segment <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/354\/d4d\/f6c\/354d4df6cfa13aa63e31ea90d74fd299.svg\" alt=\"$\\check{x}(r)$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f23\/2f8\/c42\/f232f8c422bc715d2fecd4338c022366.svg\" alt=\"$\\hat{x}(r)$\" data-tex=\"inline\"\/> are monotonically increasing functions.<\/li>\n<\/ul>\n<p>  Since we need to judge the rate of the stream by the value of the counter, we need to solve the inverse problem. This is possible due to monotonicity and continuity: there exist functions <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fb8\/a69\/d1e\/fb8a69d1e774fab779a0e4c672acda04.svg\" alt=\"$\\check{r}(x), \\hat{r}(x)$\" data-tex=\"inline\"\/> such that if <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4cc\/fd4\/32e\/4ccfd432ea4f2a64f3a5c8c7378517af.svg\" alt=\"$x$\" data-tex=\"inline\"\/> enters the attractor, we can guarantee that the true rate value lies in the interval <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/bc7\/c31\/0be\/bc7c310bec58b9eabfb6bf48bf04bb37.svg\" alt=\"$[\\check{r}(x), \\hat{r}(x)]$\" data-tex=\"inline\"\/>.<\/p>\n<p>  Of course, for these properties to be practically useful, first, the segment (attractor) must be short; otherwise, the accuracy will be low, and second, the convergence must be fast, or one will have to wait for a long time before the counter starts to show an adequate value. In any case, for a particular u-model, it is possible to write down the solution explicitly and evaluate the accuracy and speed of convergence.<\/p>\n<p>  Let us try to pass from the particular to the general. Now, ask a question: What conditions must be imposed on the u-function for the corresponding u-model to have an attractor with the above properties? An exhaustive answer is given in the next section.<\/p>\n<h1>3\u00a0\u00a0 Implementation of the U-model<\/h1>\n<p>  <\/p>\n<h2>3.1\u00a0\u00a0 Definition of the U-model<\/h2>\n<p>  Let the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1fb\/6d8\/c48\/1fb6d8c482677064317976b43d450f09.svg\" alt=\"$u\\colon\\mathbb{R}\\to\\mathbb{R}$\" data-tex=\"inline\"\/> satisfy the following conditions:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a7b\/9e3\/7fb\/a7b9e37fb0a8beb97205b2798df1237c.svg\" alt=\"$ \\begin{align*} &amp;u(x)\\text{ increases},&amp;\\hspace{10em}(9a)\\\\ &amp;\\Delta u(x) \\ge 0\\text{ for all }x,&amp;\\hspace{10em}(9b)\\\\ &amp;\\Delta u(x)\\text{ decreases},&amp;\\hspace{10em}(9c)\\\\ &amp;\\Delta u(+\\infty)=0,&amp;\\hspace{10em}(9d) \\end{align*} $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4fd\/b3a\/781\/4fdb3a781695098988a7d9d186938786.svg\" alt=\"$\\Delta u(x) = u(x)-x$\" data-tex=\"inline\"\/>.<\/p>\n<blockquote><p><b>Definition<\/b> (u-model). Consider a counter update method based on the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/><br \/>  having the properties (9), in which the counter update <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> on<br \/>  event arrival at time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e1d\/b9e\/3af\/e1db9e3af5f03094ab955a83c23b1bf7.svg\" alt=\"$t\\in\\mathbb{R}$\" data-tex=\"inline\"\/> is expressed by the rule (8):  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2a8\/019\/215\/2a80192156d18403563393ae97810fac.svg\" alt=\"$ s\\mathop{\\mapsto}^t t + u(s-t). $\" data-tex=\"display\"\/><\/p>\n<p>  This way of updating the counter will be called the u-model.  <\/p><\/blockquote>\n<p>  A function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> satisfying the conditions (9), has some useful properties. For example, the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> (and also <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/959\/841\/801\/959841801d56ef1fb64f7240c08a003a.svg\" alt=\"$\\Delta u$\" data-tex=\"inline\"\/>) is continuous. This arises from the properties (9a) and (9c) having used the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/66c\/9b7\/0c1\/66c9b70c14c3ce8269093025bf80787d.svg\" alt=\"$\\varepsilon$\" data-tex=\"inline\"\/>&#8212;<img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/838\/b5f\/70c\/838b5f70cdb112be61be395c47fd1420.svg\" alt=\"$\\delta$\" data-tex=\"inline\"\/>-formalism. Second, either <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2f3\/a56\/588\/2f3a5658886aa7714422f5ba95523618.svg\" alt=\"$\\Delta u(x)>0$&#187; data-tex=&#187;inline&#187;\/> on <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/241\/1fb\/b2d\/2411fbb2d52fdf624963d9b88e6dadc2.svg\" alt=\"$\\mathbb{R}$\" data-tex=\"inline\"\/>, or there exists such <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/6be\/5af\/a44\/6be5afa44937d17d69412eb64d6af275.svg\" alt=\"$x_{max}\\in\\mathbb{R}$\" data-tex=\"inline\"\/> that <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2f3\/a56\/588\/2f3a5658886aa7714422f5ba95523618.svg\" alt=\"$\\Delta u(x)>0$&#187; data-tex=&#187;inline&#187;\/> at <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a31\/1c1\/ae1\/a311c1ae1597cc5cb618f97743b71659.svg\" alt=\"$x&lt;x_{max}$\" data-tex=\"inline\"\/>, and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/84d\/bb4\/2a0\/84dbb42a09e5293509f6ddad28f8cbea.svg\" alt=\"$\\Delta u(x)=0$\" data-tex=\"inline\"\/> at <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8c5\/483\/799\/8c54837998166a5b26c2829c9e6c0b49.svg\" alt=\"$x\\ge x_{max}$\" data-tex=\"inline\"\/>.<\/p>\n<h2>3.2\u00a0\u00a0 Rate Measurement<\/h2>\n<p>  Properties (9) are sufficient to ensure the existence of an attractor and to construct upper <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d4e\/a77\/b09\/d4ea77b0999b13c23f3103544af54d02.svg\" alt=\"$\\hat{r}$\" data-tex=\"inline\"\/> and lower <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/980\/e6d\/c7a\/980e6dc7a7ccd964d9451143b523a93e.svg\" alt=\"$\\check{r}$\" data-tex=\"inline\"\/> estimates of the rate. There are several theorems on this point, some of which are presented in this section and some of which are left out.<\/p>\n<h3>3.2.1\u00a0\u00a0 A Strict U-model<\/h3>\n<p>  We can observe that the conditions (9) do not forbid the case when the increment of the update function converts to zero at some point, that is, when <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f75\/389\/e20\/f75389e207fbf51cdeb795c00523b120.svg\" alt=\"$\\exists x_{zero}\\colon \\Delta u(x_{zero})=0$\" data-tex=\"inline\"\/>. In this case, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/959\/841\/801\/959841801d56ef1fb64f7240c08a003a.svg\" alt=\"$\\Delta u$\" data-tex=\"inline\"\/> will also convert to zero at all <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f6a\/96b\/c60\/f6a96bc60797328d4f609af3e82752d7.svg\" alt=\"$x>x_{zero}$&#187; data-tex=&#187;inline&#187;\/>. Let us denote by  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/969\/f79\/dc7\/969f79dc7ed1d7c62803087bbb39dffe.svg\" alt=\"$ \\begin{gather*} X = \\{x\\mid \\Delta u(x)>0\\}\\\\ x_{max}=\\sup X,\\quad x_{max}\\in\\mathbb{R}\\cup\\{+\\infty\\}. \\end{gather*} $&#187; data-tex=&#187;display&#187;\/><\/p>\n<p>  It is easy to prove that if we take <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/72d\/c14\/80b\/72dc1480bd641ac390af05c1cc80cd08.svg\" alt=\"$x_0\\in X$\" data-tex=\"inline\"\/> and apply a series of updates to it, then values larger than <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/943\/799\/1f0\/9437991f0472899d63e5d96759d69796.svg\" alt=\"$x_{max}$\" data-tex=\"inline\"\/> will be unattainable, so the relative counter values will never go beyond <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/096\/ed7\/65c\/096ed765c8bbbc1f1e34d3b19d3550ed.svg\" alt=\"$X$\" data-tex=\"inline\"\/>. That is, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c0d\/bf1\/6fa\/c0dbf16fa36369e96d54ad53d6a912ae.svg\" alt=\"$X=(-\\infty, x_{max})$\" data-tex=\"inline\"\/> may be called the operating range of the u-model. Outside this range, the u-function is arranged trivially, and we are not interested in its behavior. This caveat is needed to introduce the notion of a strict u-model.<\/p>\n<blockquote><p><b>Definition<\/b> (strict u-model). If, in addition to the properties (9) functions <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/959\/841\/801\/959841801d56ef1fb64f7240c08a003a.svg\" alt=\"$\\Delta u$\" data-tex=\"inline\"\/> are strictly monotone on <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/096\/ed7\/65c\/096ed765c8bbbc1f1e34d3b19d3550ed.svg\" alt=\"$X$\" data-tex=\"inline\"\/>, then the corresponding u-model will be called <i>strict.<\/i>  <\/p><\/blockquote>\n<blockquote><p><b>Theorem<\/b> (fixed point theorem). For a strict u-model under the influence of a deterministic uniform rate stream <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b88\/ce3\/99f\/b88ce399fda6c8123ab168cb507210f2.svg\" alt=\"$r$\" data-tex=\"inline\"\/>, a sequence of values <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> is constant if an additional condition is satisfied: the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> is a compressive mapping, that is, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2bb\/15d\/c71\/2bb15dc711f8d51794485243fb186869.svg\" alt=\"$\\exists \\kappa\\in(0,1)$\" data-tex=\"inline\"\/> such that <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f0b\/50b\/16c\/f0b50b16c19245fe5ee9c35676a473c3.svg\" alt=\"$\\forall a \\forall b\\colon |u(a) - u(b)| &lt; \\kappa|a-b|$\" data-tex=\"inline\"\/>.  <\/p><\/blockquote>\n<p>  This directly follows from the Banach fixed-point theorem [5], which guarantees the existence and uniqueness of a fixed point in a compressible mapping. Then all terms of the sequence <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> will be equal to the value of this fixed point.<\/p>\n<p>  It turns out that in a strict u-model, the attractor consists of a single point.<\/p>\n<p>  In fact, not for all u-models we use the update function is a compressible mapping. For example, the EDecay model has an \u201calmost\u201d compressible update function, as for it, the constant <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8d2\/e81\/ad8\/8d2e81ad81f46cd6bd1ba4e161f204ae.svg\" alt=\"$\\kappa$\" data-tex=\"inline\"\/> is equal to one. That means the Banach theorem does not work. But this is not a problem from the practical application point of view because there are other useful theorems.<\/p>\n<p>  For example, the following statement holds.  <\/p>\n<blockquote><p><b>Statement.<\/b> If at some point in time the counter was in a state where its relative value was <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c8f\/2e7\/040\/c8f2e7040e831a8d4987f7340f4cec52.svg\" alt=\"$x_0$\" data-tex=\"inline\"\/>, and a deterministic stream of events began to arrive at it, then the sequence of its relative values <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fc3\/442\/9f4\/fc34429f4afcc17ec4b731cbe19ec1a8.svg\" alt=\"$x_k$\" data-tex=\"inline\"\/> tends to some value of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/089\/cbf\/4a0\/089cbf4a06e37980c6158e4207caa85d.svg\" alt=\"$x^*$\" data-tex=\"inline\"\/>, and the convergence rate is known. In particular, for the EDecay model, the convergence looks like this: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e31\/c6e\/bd4\/e31c6ebd4eb5425e00d72542762e8ba4.svg\" alt=\"$|x_k-x^*|\\le C\\alpha^{-(t_k-t_0)}$\" data-tex=\"inline\"\/>, which, from a practical point of view, allows us to evaluate how quickly and adequately the model responds to changes in the traffic pattern.  <\/p><\/blockquote>\n<p>  <\/p>\n<h3>3.2.2\u00a0\u00a0 A Non-strict U-model<\/h3>\n<p>  As for discretized models (see Section 3.3), they lose strict monotonicity, so instead of the fixed point theorem, a set of assertions (not given here) that require weaker conditions and give weaker, though still useful, results for rate estimation helps. For the non-strict model, instead of a one-to-one correspondence between the rate of the stream and the relative value of the counter, there is an interval estimate. That is, the attractor is a nondegenerate segment.<\/p>\n<p>  Using the proposed methodology, for a given u-model, all that remains is to construct upper <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d4e\/a77\/b09\/d4ea77b0999b13c23f3103544af54d02.svg\" alt=\"$\\hat{r}$\" data-tex=\"inline\"\/> and lower <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/980\/e6d\/c7a\/980e6dc7a7ccd964d9451143b523a93e.svg\" alt=\"$\\check{r}$\" data-tex=\"inline\"\/> estimates of the rate and find out how rapidly the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c70\/0be\/d3d\/c700bed3d108f692ea95868495b776b6.svg\" alt=\"$x_n$\" data-tex=\"inline\"\/> sequence converges to the attractor.<\/p>\n<h2>3.3\u00a0\u00a0 Discretization<\/h2>\n<p>  In order to use the u-model in practice, it must be discretized. That is, to make the set of counter states finite and preferably small in size. Why small? We need to keep billions of counters in memory; the more of them, the higher will be the quality of service. Indeed, why should we waste 64 bits per counter when we can do with 16?<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">One may go for the trick of complicating the state representation by assuming it as a pair <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/d4c\/714\/ee4\/d4c714ee44b80f1b5075cc9424ed701e.svg\" alt=\"$s=(s_{local}, s_{global})$\" data-tex=\"inline\"\/>, where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f9c\/4aa\/b5e\/f9c4aab5e261055f1e1e5a6e5aa61bb1.svg\" alt=\"$s_{local}$\" data-tex=\"inline\"\/> refers to a particular counter, and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e06\/00a\/9c1\/e0600a9c164b01d4833613cd7c0a1354.svg\" alt=\"$s_{global}$\" data-tex=\"inline\"\/> is the common part of the state of a whole group of counters. We do use this technique, in particular, to deal with counter overflows, but we do not consider it in this paper.  <\/div>\n<\/p><\/div>\n<p>  One obvious way to discretize is to select a finite subset of consecutive integers from the continuum of relative counter values and modify the u-function slightly to become an integer.<\/p>\n<p>  First, let us construct a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1c6\/950\/1d7\/1c69501d7edb30cfec17ab5bf1b34317.svg\" alt=\"$u^\\sqcup\\colon \\mathbb{R}\\to\\mathbb{R}$\" data-tex=\"inline\"\/> such that:<\/p>\n<ul>\n<li>it has integer values at integer points: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2d1\/faa\/bc4\/2d1faabc44edb9ab5d3994bcf020dc98.svg\" alt=\"$u^\\sqcup(n) \\in \\mathbb{Z}$\" data-tex=\"inline\"\/> for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1ac\/123\/390\/1ac1233900bb2372dfc18e3aec243947.svg\" alt=\"$n\\in\\mathbb{Z}$\" data-tex=\"inline\"\/>,<\/li>\n<li>is in some sense close to <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/>: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/9c7\/2ed\/c89\/9c72edc898fc93a6c24e7d6f6fc7be30.svg\" alt=\"$u^\\sqcup(n)\\approx u(n)$\" data-tex=\"inline\"\/> for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1ac\/123\/390\/1ac1233900bb2372dfc18e3aec243947.svg\" alt=\"$n\\in\\mathbb{Z}$\" data-tex=\"inline\"\/>,<\/li>\n<li>satisfies the conditions (9).<\/li>\n<\/ul>\n<p>  Apparently, this problem may be solved in different ways. Below is one particular way of constructing <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/>.<\/p>\n<p>  The basic idea of this construction is to set the values of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> at integer points by rounding down, that is, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4d9\/6f1\/164\/4d96f11646b8129940ab9a94a7e67230.svg\" alt=\"$u^\\sqcup(n):=\\lfloor u(n)\\rfloor$\" data-tex=\"inline\"\/> for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1ac\/123\/390\/1ac1233900bb2372dfc18e3aec243947.svg\" alt=\"$n\\in\\mathbb{Z}$\" data-tex=\"inline\"\/>, then complete <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> at intermediate points so that continuity and monotonicity (conditions (9)).<\/p>\n<p>  It is more convenient to first construct <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/9df\/9fc\/281\/9df9fc28142fbda45a4e3a927a012607.svg\" alt=\"$\\Delta u^\\sqcup$\" data-tex=\"inline\"\/> and then determine <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> through it. To do this, fix <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/9df\/9fc\/281\/9df9fc28142fbda45a4e3a927a012607.svg\" alt=\"$\\Delta u^\\sqcup$\" data-tex=\"inline\"\/> at integer points, and do linear interpolation at intermediate points. That may be written as follows:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a12\/f28\/025\/a12f280255eadc627d08d7979101c618.svg\" alt=\"$ \\Delta u^\\sqcup(x) = (1-\\varepsilon)\\Delta u(n) + \\varepsilon\\Delta u(n+1), $\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/93d\/435\/9e8\/93d4359e878b5926eba9ccff2baf5844.svg\" alt=\"$n=\\lfloor x\\rfloor,$\" data-tex=\"inline\"\/> <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8b5\/dc6\/16b\/8b5dc616bca8b2b4ddb470ec55628de1.svg\" alt=\"$\\varepsilon = \\{x\\}$\" data-tex=\"inline\"\/> are the integer and fractional parts of the argument, respectively.<\/p>\n<p>  All that remains is to determine the function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/891\/5ad\/59b\/8915ad59ba5ea73b58714b14fc73b61f.svg\" alt=\"$u^\\sqcup(x)$\" data-tex=\"inline\"\/> itself:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b80\/788\/385\/b807883854a1edccea9604adab4550e1.svg\" alt=\"$ u^\\sqcup(x) = \\Delta u^\\sqcup(x) + x. $\" data-tex=\"display\"\/><\/p>\n<blockquote><p><b>Statement.<\/b> The function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> thus constructed satisfies the conditions (9) and thus defines the u-model.  <\/p><\/blockquote>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">Generally speaking, the u-model gets a bit screwed up with this operation (switching from <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> to <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/>): if it was strict, it ceases to be so after the transformation.  <\/div>\n<\/p><\/div>\n<p>  A legitimate question arises: why do we need to add <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> at intermediate (non-integer) points if we plan to perform calculations only over integer counter values? The point is that in addition to the update rule, we need to build another rate estimate, and the easiest way to do that is to apply a \u201clazy approach\u201d: first, extend <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> at non-integer points, gaining a new u-model, then use theorems relating the observed counter value to rate estimates, thus reducing the problem to the solved one.  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">Remark<\/b>                         <\/p>\n<div class=\"spoiler_text\">There seems to be some meta theorem to claim that, regardless of the way <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> is constructed at intermediate points, the methodology for constructing the estimates gives the same result.  <\/div>\n<\/p><\/div>\n<p>  Now we have a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> that generates a u-model and takes integer values at integer points. It remains to take care of limiting it on a finite interval, so that the counter values do not spread to infinity. To do this, take the integer interval <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7d2\/f26\/4e5\/7d2f264e58b497909c987270fb913f3a.svg\" alt=\"$X^\\square=\\{x_{min},\\dots, x_{max}\\}$\" data-tex=\"inline\"\/> and limit <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> on it, that is, we get a function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c1c\/f3c\/957\/c1cf3c95776438d963e7c1fdfdf92619.svg\" alt=\"$u^\\square\\colon X^\\square\\to X^\\square$\" data-tex=\"inline\"\/> that matches <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/938\/011\/35e\/93801135e00f50ee3072d2e0485a5789.svg\" alt=\"$u^\\sqcup$\" data-tex=\"inline\"\/> on the area of definition.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">How to choose the interval bounds<\/b>                         <\/p>\n<div class=\"spoiler_text\">Take as <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/943\/799\/1f0\/9437991f0472899d63e5d96759d69796.svg\" alt=\"$x_{max}$\" data-tex=\"inline\"\/> such a number that <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7bd\/9a8\/f43\/7bd9a8f43824c8aedfa3924f612c5931.svg\" alt=\"$\\Delta u^\\square(x_{max})=0$\" data-tex=\"inline\"\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7c7\/b22\/0a1\/7c7b220a113e4226076793eae8618496.svg\" alt=\"$\\Delta u^\\square(x_{max}-1)>0$&#187; data-tex=&#187;inline&#187;\/>. (By virtue of the condition (9d), such a number exists.) Then the result of the update will never exceed the right bound: for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/752\/9e8\/b53\/7529e8b531e1cc917c837e1a09be0cc6.svg\" alt=\"$\\forall x\\in X^\\square$\" data-tex=\"inline\"\/> we have <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/163\/2d2\/30a\/1632d230ae68b22abb80cd7efeced1c2.svg\" alt=\"$u^\\square(x)\\le x_{max}$\" data-tex=\"inline\"\/>. As for the left boundary, it may be chosen arbitrarily (any <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0c8\/522\/0b8\/0c85220b8493c42bec76a595d63a670b.svg\" alt=\"$x_{min} &lt; x_{max}$\" data-tex=\"inline\"\/> will do). Indeed, due to non-negativity of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/973\/acf\/760\/973acf76037f595e9673196de9ab0c1e.svg\" alt=\"$\\Delta u^\\square$\" data-tex=\"inline\"\/> for <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/752\/9e8\/b53\/7529e8b531e1cc917c837e1a09be0cc6.svg\" alt=\"$\\forall x\\in X^\\square$\" data-tex=\"inline\"\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fad\/12a\/3d0\/fad12a3d0d13433604a5d1443e10198e.svg\" alt=\"$u^\\square(x)\\ge x \\ge x_{min}$\" data-tex=\"inline\"\/> will be satisfied, that is, the result of the update will not exceed the left boundary. Thus, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/448\/21d\/c1d\/44821dc1d6814a5367aca25b9da6e211.svg\" alt=\"$x_{min}$\" data-tex=\"inline\"\/> may be chosen based on counter size considerations: the larger the counter capacity, the more left-hand boundary may be moved, and the more accurate the estimate of low-intensity streams will be.  <\/div>\n<\/p><\/div>\n<p>  It is this function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1ae\/d20\/743\/1aed2074301a95dc854de9061ba56c0c.svg\" alt=\"$u^\\square$\" data-tex=\"inline\"\/> (more precisely, its numerical implementation) that we will use in the counter update algorithm.<\/p>\n<p>  Section B of the Appendix shows the discretization of the EDecay model as an example.<\/p>\n<h1>4\u00a0\u00a0 Examples of U-model Counters<\/h1>\n<p>  As shown above, the counters introduced in Section 1 (except for linear ones) are represented as u-models. Here we consider them again, now as u-models: first, take the u-function, then construct the estimators.<\/p>\n<p>  Figures 2,3, and 4 illustrate the properties of the models: shades of yellow show the function graphs <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/0c0\/b02\/b0c\/0c0b02b0c0450d5417a1eb3a50293e7a.svg\" alt=\"$u(x)$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c51\/302\/565\/c51302565166ee7eacc0d332fb95bedb.svg\" alt=\"$\\Delta u(x)$\" data-tex=\"inline\"\/>, and the remaining graphs are rate estimates. The parameters of the models were chosen in such a way as to show the difference between the upper and lower estimates. In practice, we use such parameter values so that the estimates are more accurate. If, for example, for the EDecay model we take <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7f9\/e85\/1fc\/7f9e851fcce04167d29cc3158936ebd6.svg\" alt=\"$\\tau$\" data-tex=\"inline\"\/> larger (for example, in our working code <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7f9\/e85\/1fc\/7f9e851fcce04167d29cc3158936ebd6.svg\" alt=\"$\\tau$\" data-tex=\"inline\"\/> is about <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/f59\/efe\/d80\/f59efed805a595459bc0ac03fb61b6e6.svg\" alt=\"$10^8$\" data-tex=\"inline\"\/>), the graphs of the estimates will visually merge, which obviously indicates the high accuracy of the model.<\/p>\n<h2>4.1\u00a0\u00a0 EDecay<\/h2>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/b2\/bn\/c9\/b2bnc9qrf3aqxy_oej5w9uedgf0.png\" alt=\"EDecay\" data-src=\"https:\/\/habrastorage.org\/webt\/b2\/bn\/c9\/b2bnc9qrf3aqxy_oej5w9uedgf0.png\"\/><br \/>  The update rule (1) looks like this:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/351\/7db\/d14\/3517dbd14b9bca64c9a859398d3d6b8e.svg\" alt=\"$u(x) = \\log_\\alpha(1+\\alpha^x),$\" data-tex=\"display\"\/><\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a92\/f3f\/70d\/a92f3f70ddf28b4f78ec424d1fc2785c.svg\" alt=\"$\\alpha>0$&#187; data-tex=&#187;inline&#187;\/> is a parameter (see Section A of the Appendix).<\/p>\n<p>  This model has an interesting feature: there is an estimating function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/719\/fd1\/7d9\/719fd17d92dfac220bde941225f34377.svg\" alt=\"$r^*(x) = \\alpha^x$\" data-tex=\"inline\"\/> (its graph is indicated by the blue line in Fig. 2), which has the following property. Let there be two counters that account for two different event streams and a third counter that accounts for both streams at once. Then for the EDecay model, there exists an estimator function <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cfc\/97e\/e36\/cfc97ee36af4ffd8dfeecc6d617419bc.svg\" alt=\"$r^*(x)$\" data-tex=\"inline\"\/> such that at each time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> the equality holds:  <\/p>\n<p><p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/6b3\/e56\/137\/6b3e56137bed4be024946d38a6151c64.svg\" alt=\"$r^*(s_1-t) + r^*(s_2-t) = r^*(s-t),$\" data-tex=\"display\"\/><\/p>\n<\/p>\n<p>  where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/118\/f35\/9cf\/118f359cf32df6ac855f6ccf79da0e32.svg\" alt=\"$s_1$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/019\/b00\/bbd\/019b00bbd6ac6b0cf5e00494c45b338d.svg\" alt=\"$s_2$\" data-tex=\"inline\"\/> are the absolute value of the first two counters, and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> is the absolute value of the third. It makes sense to call this property of the model additivity. It turns out that EDecay is the only one among all u-models that has this property. For other u-models, this equality can be satisfied only approximately. Here, by the way, there is a clear analogy with radioactive decay: we may say that this estimate <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/cfc\/97e\/e36\/cfc97ee36af4ffd8dfeecc6d617419bc.svg\" alt=\"$r^*(x)$\" data-tex=\"inline\"\/> plays the role of mass or amount of matter.<\/p>\n<h2>4.2\u00a0\u00a0 QDecay<\/h2>\n<p>  The corresponding rule (2) the update function looks like this:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b65\/41b\/df5\/b6541bdf55212b2445a95c0cc8c2ec95.svg\" alt=\"$u(x) = \\frac{x}{1-x\/\\tau}.$\" data-tex=\"display\"\/><\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/nf\/km\/uj\/nfkmujtajkfregeftjp8g3soiiy.png\" alt=\"QDecay\" data-src=\"https:\/\/habrastorage.org\/webt\/nf\/km\/uj\/nfkmujtajkfregeftjp8g3soiiy.png\"\/><\/p>\n<h2>4.3\u00a0\u00a0 SW<\/h2>\n<p>  The update rule (4) is equivalent within the u-model through the update function  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/c43\/11d\/b49\/c4311db4932506238b11dc1ce0a424ed.svg\" alt=\"$u(x) = \\beta x.$\" data-tex=\"display\"\/><\/p>\n<p>  A useful property of this model is the computational simplicity of the update function; we can directly write this formula into code without any table approximations.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/tb\/io\/md\/tbiomd4xfphacca5eavsml9zyqi.png\" alt=\"SW\" data-src=\"https:\/\/habrastorage.org\/webt\/tb\/io\/md\/tbiomd4xfphacca5eavsml9zyqi.png\"\/>  <\/p>\n<h2>4.4\u00a0\u00a0 Summary Table<\/h2>\n<p>  Table 1 lists the characteristics of the mentioned models.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/xh\/az\/cq\/xhazcqlf_ndjvzqlkgdveiler_k.png\" alt=\"summary table\" data-src=\"https:\/\/habrastorage.org\/webt\/xh\/az\/cq\/xhazcqlf_ndjvzqlkgdveiler_k.png\"\/><br \/>  One may notice that for some models, the formula for the lower estimate <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b49\/76d\/ac1\/b4976dac19ba233fd876d7e1938a846e.svg\" alt=\"$r^-$\" data-tex=\"inline\"\/> becomes meaningless at some values of the argument. That means that for such (too small) relative counter values, we cannot say anything about how small the rate may be, so we assume that the lower estimate simply equals zero (no rate is less than zero). Theoretically, for some u-models, it may happen that the upper estimate <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35a\/d71\/35b\/35ad7135b7ce62cafcfd2aa7d4d26cf2.svg\" alt=\"$r^+$\" data-tex=\"inline\"\/> makes no sense for some reason. In such cases, it should be assumed to be infinite.<\/p>\n<p>  In addition to the rigorous rate estimates <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b49\/76d\/ac1\/b4976dac19ba233fd876d7e1938a846e.svg\" alt=\"$r^-$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35a\/d71\/35b\/35ad7135b7ce62cafcfd2aa7d4d26cf2.svg\" alt=\"$r^+$\" data-tex=\"inline\"\/> derived from the general u-model methodology, an estimate of <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/a95\/cee\/cb4\/a95ceecb44f1604f061eb1ec0fb13445.svg\" alt=\"$r^*$\" data-tex=\"inline\"\/> constructed \u201cfrom physical considerations\u201d (the blue line in the graphs) is also indicated. It was expected that it would always be between the lower and upper estimates (<img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/b49\/76d\/ac1\/b4976dac19ba233fd876d7e1938a846e.svg\" alt=\"$r^-$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/35a\/d71\/35b\/35ad7135b7ce62cafcfd2aa7d4d26cf2.svg\" alt=\"$r^+$\" data-tex=\"inline\"\/>), but with the QDecay model, this is not the case, as there is an area where it is smaller than the lower estimate. This example shows the usefulness of the approach described here: whatever the considerations on which the counter model is built, it is always useful to double-check how a stream of a known rate affects the state of the counter.<\/p>\n<h1>Conclusions<\/h1>\n<p>  The general principles of event counters have been shown in several examples. As a rather universal generalization, the u-model scheme has been proposed. A methodology for constructing rate estimates for any u-model has been proposed.<\/p>\n<p>  In addition, a lot of interesting things were left out of the picture.<\/p>\n<ul>\n<li>Probability Counters. What happens if we replace the <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1d6\/e3d\/c60\/1d6e3dc60633569bb3f51249e1a4ee2c.svg\" alt=\"$u$\" data-tex=\"inline\"\/> function in the u-model update rule with a random variable that depends on the relative value of the counter?<\/li>\n<li>Representation and maintenance of large arrays of identical counters. The update and evaluation functions depend on the relative counter value <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/249\/7d3\/a64\/2497d3a640597f2d68ea8cd6e4134c8a.svg\" alt=\"$x=s-t$\" data-tex=\"inline\"\/>, where <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/8bc\/837\/5dc\/8bc8375dc6b8abeff08d6da9da469b5d.svg\" alt=\"$s$\" data-tex=\"inline\"\/> and <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/4cc\/fd4\/32e\/4ccfd432ea4f2a64f3a5c8c7378517af.svg\" alt=\"$x$\" data-tex=\"inline\"\/> may be in a relatively narrow range of values, while <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/915\/acb\/b16\/915acbb16ed63f15541d3e0bda30d453.svg\" alt=\"$t$\" data-tex=\"inline\"\/> runs over a wide (potentially infinite) range. How can we make sure that the counters do not overflow?<\/li>\n<li>Algorithms detecting heavy streams. Individual counters allow us to <i>measure<\/i> the rate of streams, but how do we organize them to <i>reveal<\/i> the most intense streams?<\/li>\n<\/ul>\n<p>  <\/p>\n<h1>Appendix<\/h1>\n<p>  <\/p>\n<h2>A\u00a0\u00a0 Parameterization<\/h2>\n<p>  All of the counter models discussed in this article are single-parameter. But we use different values in different places to make the formulas look more convenient. Below is a list of quantities that may be equally used as a model parameter, with an indication of their physical meaning and the relationship between them.<\/p>\n<ul>\n<li><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/626\/5cf\/b62\/6265cfb6298a7ded1d412911477c0a81.svg\" alt=\"$\\lambda>0$&#187; data-tex=&#187;inline&#187;\/> is the so-called decay constant from the law of radioactive decay [4]\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/656\/0ee\/90b\/6560ee90b9b44c3234dd30509f44101c.svg\" alt=\"$v(t) = v_o e^{-\\lambda t}.$\" data-tex=\"display\"\/><\/p>\n<\/li>\n<li><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/ca9\/b2f\/f7e\/ca9b2ff7eca060a22483c9e2945f93d2.svg\" alt=\"$\\tau>0$&#187; data-tex=&#187;inline&#187;\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1af\/1be\/be7\/1af1bebe7321eb91e4a5497e390293b1.svg\" alt=\"$\\tau=1\/\\lambda$\" data-tex=\"inline\"\/> is a value characterizing the average lifetime in the same model. It is also true that during the time <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7f9\/e85\/1fc\/7f9e851fcce04167d29cc3158936ebd6.svg\" alt=\"$\\tau$\" data-tex=\"inline\"\/> the amount of decaying matter decreases <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/e64\/b30\/6c5\/e64b306c55dd73fcf1b1b798af007d78.svg\" alt=\"$e$\" data-tex=\"inline\"\/> times, and the half-life is expressed through <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7f9\/e85\/1fc\/7f9e851fcce04167d29cc3158936ebd6.svg\" alt=\"$\\tau$\" data-tex=\"inline\"\/> as follows: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/069\/ad7\/b6e\/069ad7b6e482c68065031181f86763e1.svg\" alt=\"$T_{1\/2}=\\tau\\ln2$\" data-tex=\"inline\"\/>.<\/li>\n<li><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/2e5\/644\/fbc\/2e5644fbc04ee205ebc886ccd3b882f9.svg\" alt=\"$\\alpha>1$&#187; data-tex=&#187;inline&#187;\/>, <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/419\/add\/ab0\/419addab0e3e95b48b7d48fde4f7eb49.svg\" alt=\"$\\alpha=e^\\lambda$\" data-tex=\"inline\"\/>.<\/li>\n<li><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/1e8\/de3\/524\/1e8de35248111414596bcd8efaba119e.svg\" alt=\"$\\beta\\in(0,1)$\" data-tex=\"inline\"\/> is the smoothing parameter in the EMA [2]<br \/> \n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/5aa\/93e\/998\/5aa93e99898301ebad2997292a30ac3a.svg\" alt=\"$v_n = \\beta\\cdot (t_n-t_{n-1}) + (1-\\beta)\\cdot v_{n-1}.$\" data-tex=\"display\"\/><\/p>\n<p>  The exponential decay model may be expressed in two ways: through radioactive decay and through EMA smoothing. Here is the relationship between these parameters: <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/fa4\/ec1\/5c7\/fa4ec15c7cf8ff3b0b781a5099ab72f6.svg\" alt=\"$\\beta = 1-1\/\\alpha$\" data-tex=\"inline\"\/>.<\/li>\n<\/ul>\n<p>  <\/p>\n<h2>B\u00a0\u00a0 An Example of EDecay Discretization<\/h2>\n<p>  The EDecay model is defined by the following update function:  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/bdb\/024\/8cb\/bdb0248cb5536d675bb47110f506fd9e.svg\" alt=\"$ u(x) = \\log_\\alpha(1 + \\alpha^x). $\" data-tex=\"display\"\/><\/p>\n<p>  Consider in Fig. 5 how the update function changes with sampling.<br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/s-\/tp\/t7\/s-tpt7pw0memx371oizdvfiswzo.png\" alt=\"interpolated EDecay\" data-src=\"https:\/\/habrastorage.org\/webt\/s-\/tp\/t7\/s-tpt7pw0memx371oizdvfiswzo.png\"\/>  <\/p>\n<ol>\n<li>There is a perfect real-valued update function that exactly exponential decay model (the smooth green line in the graph).<\/li>\n<li>It has to be discretized for practical applications. It is possible to use a floating-point representation (obviously, it is also discretized, only not uniform) or take an integer representation. In this case, rounding down applies, although it is not crucial (blue line).<\/li>\n<li>Finally, It is possible to overload the update function even more. In [1] to speed up calculations, it was suggested that instead of calculating the real-valued function with logarithms and exponents, a table approach should be used. It was assumed that the size of the table would be small if a low-digit counter was used. However, nothing prevents us from thinning the table by reducing its size a few more times and implementing linear interpolation. The resulting update function will be slightly different (the red dotted line on the graph).<\/li>\n<\/ol>\n<p>  Of course, as a result of sampling, the update function is distorted, which is not a problem in itself, but we have to take it into account when constructing the rate estimate. In addition, strict monotonicity of the model is inevitably lost, which reduces the accuracy of the estimate. The degree of distortion depends on the parameter <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/formulas\/7f9\/e85\/1fc\/7f9e851fcce04167d29cc3158936ebd6.svg\" alt=\"$\\tau$\" data-tex=\"inline\"\/>: the larger it is, the closer the discretized function is to the original one.<\/p>\n<h1>References<\/h1>\n<p>  [1] Our article about the decay model: <a href=\"https:\/\/qratorlabs.medium.com\/rate-detector-21d12567d0b5\">https:\/\/qratorlabs.medium.com\/rate-detector-21d12567d0b5<\/a><br \/>  [2] Exponential moving average: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Moving_average#Exponential_moving_average\">https:\/\/en.wikipedia.org\/wiki\/Moving_average#Exponential_moving_average<\/a><br \/>  [3] Weighted moving average: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Moving_average#Weighted_moving_average\">https:\/\/en.wikipedia.org\/wiki\/Moving_average#Weighted_moving_average<\/a><br \/>  [4] The radioactive decay law: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Exponential_decay\">https:\/\/en.wikipedia.org\/wiki\/Exponential_decay<\/a><br \/>  [5] Banach fixed-point theorem: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Banach_fixed-point_theorem\">https:\/\/en.wikipedia.org\/wiki\/Banach_fixed-point_theorem<\/a><br \/>  [6] Ayur Datar et al. \u2014 Maintaining Stream Statistics Over Sliding Windows \u2014 Society for Industrial and Applied Mathematics, Vol. 31, No. 6: <a href=\"http:\/\/www-cs-students.stanford.edu\/~datar\/papers\/sicomp_streams.pdf\">http:\/\/www-cs-students.stanford.edu\/~datar\/papers\/sicomp_streams.pdf<\/a><br \/>  [7] Our overview of Morris&#8217;s counters: <a href=\"https:\/\/habr.com\/ru\/company\/qrator\/blog\/559858\/\">https:\/\/habr.com\/ru\/company\/qrator\/blog\/559858\/<\/a><br \/>  [8] Translational symmetry: <a href=\"https:\/\/en.wikipedia.org\/wiki\/Translational_symmetry\">https:\/\/en.wikipedia.org\/wiki\/Translational_symmetry<\/a><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/566288\/\"> https:\/\/habr.com\/ru\/articles\/566288\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ko\/ay\/op\/koayopm8caby70zokumllg3xzyk.jpeg\" alt=\"stream rate art\" data-src=\"https:\/\/habrastorage.org\/webt\/ko\/ay\/op\/koayopm8caby70zokumllg3xzyk.jpeg\" data-blurred=\"true\"\/><br \/>  <sup>Measuring of stream rate in an artist&#8217;s impression.<\/sup><\/p>\n<p>  In one of our <a href=\"https:\/\/qratorlabs.medium.com\/rate-detector-21d12567d0b5\">previous publications<\/a>, we talked about a way to measure event stream rate using a counter based on exponential decay. It turns out that the idea of such a counter has an interesting generalization. This paper by Artem Shvorin and Dmitry Kamaldinov, Qrator Labs, reveals it.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-406223","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/406223","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=406223"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/406223\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=406223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=406223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=406223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}