<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
<title type="text">Notes</title>
<generator uri="https://github.com/mojombo/jekyll">Jekyll</generator>
<link rel="self" type="application/atom+xml" href="https://danielpollithy.github.io/feed.xml" />
<link rel="alternate" type="text/html" href="https://danielpollithy.github.io" />
<updated>2024-04-06T12:28:27+02:00</updated>
<id>https://danielpollithy.github.io/</id>
<author>
  <name>Daniel Pollithy</name>
  <uri>https://danielpollithy.github.io/</uri>
  <email>daniel@pollithy.com</email>
</author>


<entry>
  <title type="html"><![CDATA[Popoviciu's inequality]]></title>
  <link>https://danielpollithy.github.io/general/popovicius-inequality</link>
  <id>https://danielpollithy.github.io/general/popovicius-inequality</id>
  <published>2021-01-14T00:00:00+01:00</published>
  <updated>2021-01-14T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;Suppose you have a neural network with a function as its last layer that squashes
its outputs to a fixed interval [a,b]. Popoviciu’s inequality can give us an upper bound
to the sample variance.&lt;/p&gt;

&lt;p&gt;If we knew the distribution where the samples stem from, then it would be easy
to answer this question. Consider the most simple case of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_uniform_distribution&quot;&gt;uniform distribution&lt;/a&gt;:
\(p(x) \sim U(a,b), Var[p(x)]=\frac{1}{12}(b-a)^2\)&lt;/p&gt;

&lt;p&gt;The upper bound derived from Popoviciu’s inequality is \(\frac{1}{4}(b-a)^2\).
Interestingly, Mihaly Bencze and Florin Popovici write in their &lt;a href=&quot;https://www.researchgate.net/publication/267072994_A_simple_proof_of_Popoviciu%27s_inequality&quot;&gt;proof&lt;/a&gt; that
“Popoviciu’s inequality is a refinement of Jensen’s inequality”.&lt;/p&gt;

&lt;p&gt;In the following, I am going to adapt the proof by &lt;a href=&quot;https://stats.stackexchange.com/questions/45588/variance-of-a-bounded-random-variable&quot;&gt;Zen&lt;/a&gt; with minor notational changes:&lt;/p&gt;

&lt;p&gt;Let \(g(x) = E[(X - t)^2]\) where X is our random variable and \(t\) to be determined such that we find the minimum of g.&lt;/p&gt;

&lt;p&gt;Therefore we derive g with respect to t: \(\frac{d}{dt} g(x) = \frac{d}{dt} E[X^2 - 2Xt + t^2]\)&lt;/p&gt;

\[= \frac{d}{dt} E[X^2] - E[2Xt] + E[t^2] = 0 - \frac{d}{dt} E[2Xt] + \frac{d}{dt} E[t^2]\]

\[= -2 E[X] + 2t\]

&lt;p&gt;… and set it to zero:&lt;/p&gt;

\[-2 E[X] + 2t \stackrel{!}{=} 0\]

\[t = E[X]\]

&lt;p&gt;The second derivative is $2$ which is larger than zero. $E[X]$ is therefore the global minimum. \(g(\cdot)\) was constructed such that \(g(E[X]) = Var[X]\)&lt;/p&gt;

&lt;p&gt;Now we choose \(t = \frac{a+b}{2}\) seemingly arbitrary in the middle of our interval but of course it is chosen on purpose.&lt;/p&gt;

&lt;p&gt;Since \(g(\cdot)\) has its global minimum at $E[X]$, we know that our chosen \(t\) cannot make the function smaller:&lt;/p&gt;

\[g(E[X]) \le g(\frac{a+b}{2})\]

&lt;p&gt;By having a closer look at \(g(\frac{a+b}{2})\) we can derive an upper bound for it:&lt;/p&gt;

\[g(\frac{a+b}{2}) = E[(X - \frac{a+b}{2})^2]\]

\[= E[(\frac{1}{2}(2X - (a + b))^2] = E[\frac{1}{4}(2X - (a - b))^2]\]

\[= \frac{1}{4} E[(X+X - a - b)^2] = \frac{1}{4} E[(X - a + X - b)^2]\]

\[= \frac{1}{4} E[(\underbrace{(X - a)}_{\ge 0} + \underbrace{(X - b)}_{\le 0})^2]\]

&lt;p&gt;Since every sample from X has to be greater than \(a\) and smaller than \(b\), these observations are true. While the left part increases the value, the right part decreases it. Our upper bound can thus be constructed by simply flipping the sign such that the right part is not subtracted but added:&lt;/p&gt;

\[\frac{1}{4} E[((X - a) + (X - b))^2] \le \frac{1}{4} E[((X - a) - (X - b))^2]\]

&lt;p&gt;Modifying the right hand side:&lt;/p&gt;

\[\frac{1}{4} E[((X - a) + (X - b))^2] \le \frac{1}{4} E[(X - a - X + b))^2]\]

&lt;p&gt;The X is eradicated:&lt;/p&gt;

\[\frac{1}{4} E[((X - a) + (X - b))^2] \le \frac{1}{4} E[(b-a)^2]\]

\[\underbrace{\frac{1}{4} E[((X - a) + (X - b))^2]}_{g(\frac{a+b}{2})} \le \frac{1}{4} (b-a)^2\]

&lt;p&gt;Recalling that \(Var[X] = g(E[X]) \le g(\frac{a+b}{2})\) we see that:&lt;/p&gt;

\[Var[X] \le \frac{1}{4} (b-a)^2\]

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/popovicius-inequality&quot;&gt;Popoviciu's inequality&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on January 14, 2021.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Deviation between rotations]]></title>
  <link>https://danielpollithy.github.io/general/deviation-between-rotations</link>
  <id>https://danielpollithy.github.io/general/deviation-between-rotations</id>
  <published>2021-01-13T00:00:00+01:00</published>
  <updated>2021-01-13T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;In visual localization, the accuracy of a system is determined by comparing
predicted poses to ground truth poses.&lt;/p&gt;

&lt;p&gt;The position in R³ is a euclidean space. But the orientations can be given in
multiple ways, like axis and angle, rotations matrices or quaternions.&lt;/p&gt;

&lt;p&gt;Du Q. Huynh describes in &lt;a href=&quot;https://www.cs.cmu.edu/~cga/dynopt/readings/Rmetric.pdf&quot;&gt;Metrics for 3D Rotations: Comparison and Analysis&lt;/a&gt;
five metrics on SO(3):&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Euclidean Distance between Euler Angles: This is only a metric on SO(3) if further restrictions are made.&lt;/li&gt;
  &lt;li&gt;Norm of the Difference of Quaternions: Since every rotation is covered twice by unit-quaternions, one property of metrics does not hold. Which is the property that states, if the distance between two entities is zero then the two entities are the same. This is not true for the positive and the negative quaternion who have a rotational difference of zero. This makes it a pseudometric which can be alleviated by adding a further restriction.&lt;/li&gt;
  &lt;li&gt;Inner Product of Unit Quaternions: Also pseudometrics on the unit quaternion.&lt;/li&gt;
  &lt;li&gt;Deviation from the Identity Matrix: \(\lVert I - R_1 R_2^T \rVert_F\)&lt;/li&gt;
  &lt;li&gt;Geodesic on the Unit Sphere: the magnitude of the angle of the rotation matrix necessary to transform
\(R_1\) into \(R_2\)&lt;/li&gt;
&lt;/ul&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/deviation-between-rotations&quot;&gt;Deviation between rotations&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on January 13, 2021.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Expenses during Master studies]]></title>
  <link>https://danielpollithy.github.io/general/master-study-expenses</link>
  <id>https://danielpollithy.github.io/general/master-study-expenses</id>
  <published>2021-01-01T00:00:00+01:00</published>
  <updated>2021-01-01T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This post is a summary of my expenses during two years of studying at Karlsruhe Institute of Technology (KIT).
I collected the data with Splitwise because I am sharing expenses with my girlfriend. It contains my regular
meals at the university’s canteen, my share of the rent, regular visits at a coffee-store, personal gifts,
travels and vacations. I am sure that some expenses are missing but the broad picture should be correct.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/expenses/Accumulated expenses of two years of studying.svg&quot; alt=&quot;Accumulated expenses since the start of my master&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I spent a total of € 20,965.40. This corresponds to € 873.55 per month. I assume that the missing expenses won’t increase
this number to more than € 900. Just for the reference, a student could apply for
a maximum BAföG of € 861 in 2020 if she or he is not living at parent’s house and has to
 pay insurances. &lt;a href=&quot;https://www.bafög.de/de/welche-bedarfssaetze-sieht-das-bafoeg-vor--375.php&quot;&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The COVID-19 pandemic does not become visible in the expenses although I could not go to
the canteen in the last seven months and did order less at restaurants etc.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/expenses/Expenses of two years grouped by categories.svg&quot; alt=&quot;Expenses of two years grouped by categories&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The total euros spent on each category can be read from the following chart:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/expenses/Monthly spendings by categories.svg&quot; alt=&quot;Monthly spendings by categories&quot; /&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/master-study-expenses&quot;&gt;Expenses during Master studies&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on January 01, 2021.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Jensen's inequality]]></title>
  <link>https://danielpollithy.github.io/general/jensens-inequality</link>
  <id>https://danielpollithy.github.io/general/jensens-inequality</id>
  <published>2020-09-09T00:00:00+02:00</published>
  <updated>2020-09-09T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This is an illustrative explanation of Jensen’s inequality applied to probability.&lt;/p&gt;

&lt;h2 id=&quot;jensens-inequality&quot;&gt;Jensen’s inequality&lt;/h2&gt;

&lt;p&gt;Remember that a convex function is a function whose area above the graph (called epi graph)
is a convex set. Informally speaking, a convex function can be identified by having
positive curvature everywhere.
A concave function has the opposite attributes.&lt;/p&gt;

&lt;p&gt;Jensen’s inequality states for \(\theta \in [0,1]\) and \(f\) convex:&lt;/p&gt;

\[f(\theta x_1 + (1 - \theta) x_2) \le \theta f(x_1) + (1 - \theta) f(x_2)\]

&lt;p&gt;The following image illustrates the inequality:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/jensen.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is usable to define and show convexity of functions analogously to the
definition of convex sets.&lt;/p&gt;

&lt;h3 id=&quot;in-probability&quot;&gt;In probability&lt;/h3&gt;

&lt;p&gt;If we have a random variable X with probability distribution p(x) over x, then we could set \(x_1=x_2=E[X]\).
For this case the Jensen’s inequality displays itself as:&lt;/p&gt;

\[f(E[X]) \le E[f(X)]\]

&lt;p&gt;&lt;img src=&quot;/images/jensen_gap.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For affine functions f the equality holds. Which tells us that they are concave
and convex.&lt;/p&gt;

&lt;h3 id=&quot;derivation-of-the-elbo&quot;&gt;Derivation of the ELBO&lt;/h3&gt;

&lt;p&gt;\(log p(X)\) is the log evidence, X the observed variables and Z the latent variables.
q denotes a variational approximation of p(Z|X):&lt;/p&gt;

\[log p(X) = log \int_{Z} p(X,Z)\]

\[= log \int_{Z} p(X,Z) \frac{q(Z)}{q(Z)} = log \int_{Z}  \frac{p(X,Z)}{q(Z)} q(Z)\]

&lt;p&gt;This is the definition of the expected value wrt q(Z):&lt;/p&gt;

\[= log(E[\frac{p(X,Z)}{q(Z)}])\]

&lt;p&gt;Here comes the inverted Jensen’s inequality in to play (it holds for concave functions).
We can confirm ourselves easily that the log() is a concave function by noting that
the area under its curve is convex.&lt;/p&gt;

\[log(E[\frac{p(X,Z)}{q(Z)}]) \ge E[log( \frac{p(X,Z)}{q(Z)} )]\]

&lt;p&gt;This can be brought into a nicer form by realizing that the definition of
entropy is \(H(p) = E_{x\sim p(x)}[log(\frac{1}{p(x)})] = -E_{x\sim p(x)}[log ~ p(X)]\)&lt;/p&gt;

\[E[log( \frac{p(X,Z)}{q(Z)} )] = E[log(p(X,Z)) - log(q(Z))]\]

\[E[log(p(X,Z)) - log(q(Z))] = E[log(p(X,Z))] - E[log(q(Z))]\]

\[E[log(p(X,Z))] - E[log(q(Z))] = E[log(p(X,Z))] + H(q(Z))\]

&lt;h3 id=&quot;proof-kullback-leibler-divergence-is-always--0&quot;&gt;Proof Kullback-Leibler divergence is always &amp;gt;= 0&lt;/h3&gt;

&lt;p&gt;The KL between p(x) and q(x) is defined as:&lt;/p&gt;

\[KL(p(x);q(x)) = -E_{x \sim p(x)}[log(\frac{q(x)}{p(x)})]\]

&lt;p&gt;We can apply the concave version of Jensen’s inequality. q/p is the distribution and log the concave function.&lt;/p&gt;

\[-E_{x \sim p(x)}[log(\frac{q(x)}{p(x)})] \le - log(E_{x \sim p(x)}[\frac{q(x)}{p(x)}])\]

&lt;p&gt;Multiply by (-1):&lt;/p&gt;

\[E_{x \sim p(x)}[log(\frac{q(x)}{p(x)})] \ge log(E_{x \sim p(x)}[\frac{q(x)}{p(x)}])\]

\[log(E_{x \sim p(x)}[\frac{q(x)}{p(x)}])  = log(\int p(x)\frac{q(x)}{p(x)} ~ dx) = log(\int q(x) ~ dx)\]

&lt;p&gt;q is a pdf therefore this integral has to be 1. log(1) = 0. As a result:&lt;/p&gt;

\[E_{x \sim p(x)}[log(\frac{q(x)}{p(x)})] \ge 0\]

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/jensens-inequality&quot;&gt;Jensen's inequality&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on September 09, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[LOTUS]]></title>
  <link>https://danielpollithy.github.io/general/LOTUS</link>
  <id>https://danielpollithy.github.io/general/LOTUS</id>
  <published>2020-08-20T00:00:00+02:00</published>
  <updated>2020-08-20T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;If you want to calculate the expected value of a continuous random variable
which was transformed by a monotonic function, then the law of the unconscious
statistician provides a convenient shortcut.&lt;/p&gt;

&lt;h2 id=&quot;transforming-a-random-variable&quot;&gt;Transforming a random variable&lt;/h2&gt;

&lt;p&gt;We have a continuous random variable \(X\) with a probability density function \(f_{X}(x)\).
This could for example be our last knowledge about the position of a robot.&lt;/p&gt;

&lt;p&gt;Now, we apply a continuous, monotonic function \(g(\cdot)\) to the random variable.
This could be a simple motion model for the robot.&lt;/p&gt;

&lt;p&gt;If we want to calculate \(E[g(X)]\) then LOTUS tells us that we don’t have to
solve \(g(X)\) but instead we can write:&lt;/p&gt;

\[E[g(X)] = \int_{+\infty}^{+\infty}{g(x) \cdot f_{X}(x)  dx}\]

&lt;h2 id=&quot;proof&quot;&gt;Proof&lt;/h2&gt;

&lt;p&gt;For the proof let’s assume \(g\) to be strictly increasing (decreasing would also
  be possible). And due to its continuity, \(g(x)\) therefore has a positive
  derivative for every x.
This results in \(g(\cdot)\) being bijective therefore g is invertible. We call
its inverse \(g^{-1}\). With \(g^{-1}: Y \rightarrow X\)&lt;/p&gt;

&lt;h3 id=&quot;prepare-change-of-variable&quot;&gt;Prepare change of variable&lt;/h3&gt;

&lt;p&gt;The derivative of a function and its inverse are related. They are reciprocal:&lt;/p&gt;

\[\frac{dx}{dy} \cdot \frac{dy}{dx} = 1\]

\[\frac{dx}{dy}  = \frac{1}{\frac{dy}{dx}}\]

&lt;p&gt;First we replace \(y\) with \(g(x)\) on the right side:&lt;/p&gt;

\[\frac{dx}{dy}= \frac{1}{\frac{d g(x)}{dx}}\]

&lt;p&gt;Second we replace \(x\) with \(g^{-1}(y)\) on the right side:&lt;/p&gt;

\[\frac{dx}{dy}= \frac{1}{\frac{d g(g^{-1}(y))}{dx}}\]

&lt;p&gt;Multiplying with dy on both sides:&lt;/p&gt;

\[dx = \frac{1}{\frac{d g(g^{-1}(y))}{dx}} dy\]

&lt;h3 id=&quot;expected-value-with-exchanged-variable&quot;&gt;Expected value with exchanged variable&lt;/h3&gt;

&lt;p&gt;We start with the result:&lt;/p&gt;

\[\int_{+\infty}^{+\infty}{g(x) \cdot f_{X}(x)  dx}\]

&lt;p&gt;And now we can switch from x to y.
First, replace g(x) with y.
Second, replace \(f_{X}(x)\) with \(f_{X}(g^{-1}(y))\).
And third, replace dx with the right hand side from “dx = …” above:&lt;/p&gt;

\[\int_{+\infty}^{+\infty}{g(x) \cdot f_{X}(x)  dx} = \int_{+\infty}^{+\infty}{y \cdot f_{X}(g^{-1}(y)) \frac{1}{\frac{d g(g^{-1}(y))}{dx}} dy}\]

&lt;p&gt;We have now switched to integrating over y.&lt;/p&gt;

&lt;h3 id=&quot;cumulative-density-function&quot;&gt;Cumulative density function&lt;/h3&gt;

\[F_{Y}(y) = Pr(Y \le y)\]

&lt;p&gt;Apply g:&lt;/p&gt;

\[F_{Y}(y) = Pr(g(X) \le y)\]

&lt;p&gt;Apply \(g^{-1}\) on both sides&lt;/p&gt;

\[F_{Y}(y) = Pr(X \le g^{-1}(y))\]

\[F_{Y}(y) = F_{X}(g^{-1}(y))\]

&lt;h3 id=&quot;derivative-of-cdf&quot;&gt;Derivative of CDF&lt;/h3&gt;

&lt;p&gt;Now we can get the derivative of \(F_{Y}(y)\) for y in order to get \(f_{Y}(y)\).
The chain rule is used. Note that this is the place where we need the derivative
of \(g^{-1}(y)\) which is \(\frac{1}{\frac{d g(g^{-1}(y))}{dx}}\) !&lt;/p&gt;

&lt;p&gt;Apply the CDF solution from above:&lt;/p&gt;

\[f_{Y}(y) = \frac{d}{dy}  F_{Y}(y) = \frac{d}{dy} F_{X}(g^{-1}(y))\]

&lt;p&gt;Apply the chain rule of derivation:&lt;/p&gt;

\[= f_{x}(g^{-1}(y)) \cdot \frac{d}{dy} g^{-1}(y)\]

\[= f_{X}(g^{-1}(y)) \cdot \frac{1}{\frac{d g(g^{-1}(y))}{dx}} =\]

&lt;h3 id=&quot;plug-in&quot;&gt;Plug-in&lt;/h3&gt;

&lt;p&gt;Two sections before, we got to this point:&lt;/p&gt;

\[E[g(X)] = \int_{+\infty}^{+\infty}{y \cdot f_{Y}(y)  dy} = \int_{+\infty}^{+\infty}{y \cdot f_{X}(g^{-1}(y)) \frac{1}{\frac{d g(g^{-1}(y))}{dx}} dy}\]

&lt;p&gt;Looking at the last formula from the section “Prepare change of variable”, we find that
\(f_{X}(g^{-1}(y)) \cdot \frac{1}{\frac{d g(g^{-1}(y))}{dx}} dy\) to be the same as \(f_{X}(g^{-1}(y)) dx\)&lt;/p&gt;

\[E[g(X)] = \int_{+\infty}^{+\infty}{y \cdot f_{X}(g^{-1}(y)) dx}\]

&lt;p&gt;Per definition \(g^{-1}(y)\) can be replaced by x.&lt;/p&gt;

\[E[g(X)] = \int_{+\infty}^{+\infty}{y \cdot f_{X}(x) dx}\]

&lt;p&gt;And also \(y\) can be replaced by g(x).&lt;/p&gt;

\[E[g(X)] = \int_{+\infty}^{+\infty}{g(x) \cdot f_{X}(x) dx}\]

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/LOTUS&quot;&gt;LOTUS&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on August 20, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[LogSumExp]]></title>
  <link>https://danielpollithy.github.io/general/logsumexp</link>
  <id>https://danielpollithy.github.io/general/logsumexp</id>
  <published>2020-04-19T00:00:00+02:00</published>
  <updated>2020-04-19T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This is a short note to show the difference between softmax and softargmax.&lt;/p&gt;

&lt;p&gt;It is common to use a “Softmax” layer as an activation function for a neural network used for classification. But this is actually a wrong name. The layer should be called softargmax.&lt;/p&gt;

&lt;h2 id=&quot;softmax&quot;&gt;Softmax&lt;/h2&gt;

&lt;p&gt;Given a vector x = [20, 5, 0.1, 300]. The softmax (also called LogSumExp) is a approximation to the maximum of the vector. Let’s apply the three steps in the name:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;exp: exp([20, 5, 0.1, 300]) -&amp;gt; [4.8e+008, 1.4e+002, 1.1e+000, 1.9e+130]&lt;/li&gt;
  &lt;li&gt;sum: ~1.9e+130&lt;/li&gt;
  &lt;li&gt;log: 299.97&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note: If there were two “300” in the input vector, then the sum in the second step was 2 * 1.9e+130. Third step: log(2 * 1.9e+130) = log(2) + log(1.9e+130) = 300.67&lt;/p&gt;

&lt;h2 id=&quot;softargmax&quot;&gt;Softargmax&lt;/h2&gt;

&lt;p&gt;The softargmax divides each entry of the input vector x by the softmax. Therefore it can be seen as a probability measure. The probability of each entry to be the maximum of the vector.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Calculate softmax s=299.97&lt;/li&gt;
  &lt;li&gt;x’ = x/s = [20, 5, 0.1, 300] / 299.97 ~= [0.066, 0.016, 0.0003, 1.0001]&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the classification framework we would choose the fourth class as a prediction.&lt;/p&gt;

&lt;h2 id=&quot;addendum&quot;&gt;Addendum&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Maximum rewritten:\(max(x) = log(exp(max(x)))\)&lt;/li&gt;
  &lt;li&gt;Softargmax definition: \(logsumexp(x) = log(exp(x_1) + ... + exp(x_n))\)&lt;/li&gt;
  &lt;li&gt;Upper bound for Softargmax: \(log(exp(x_1) + ... + exp(x_n)) \le log(exp(max(x)) + ... + exp(max(x)))\)&lt;/li&gt;
  &lt;li&gt;Factor out n: \(log(exp(max(x)) + ... + exp(max(x))) = log(n \cdot exp(max(x)))\)&lt;/li&gt;
  &lt;li&gt;Log rule: \(log(n \cdot exp(max(x))) = log(n) +  log(exp(max(x)))\)&lt;/li&gt;
  &lt;li&gt;Insert defintion of max: \(log(n) +  log(exp(max(x))) = log(n) + max(x)\)&lt;/li&gt;
  &lt;li&gt;Result: \(logsumexp(x) \le max(x) + log(n)\)&lt;/li&gt;
&lt;/ol&gt;


  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/logsumexp&quot;&gt;LogSumExp&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on April 19, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Stochastic Information Processing]]></title>
  <link>https://danielpollithy.github.io/general/lecture/stochastic-information-processing</link>
  <id>https://danielpollithy.github.io/general/lecture/stochastic-information-processing</id>
  <published>2020-04-17T00:00:00+02:00</published>
  <updated>2020-04-17T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This is a summary of the lecture Stochastic Information Processing which I
attended in the winter semester 2019/2020. The content has overlaps with
LMA (localization of mobile agents), i.e. Kalman Filter.
In SI it is taught how to convert a generative model into a probabilistic one
and how to confront parametric integrals by means of approximations.&lt;/p&gt;

&lt;h2 id=&quot;si&quot;&gt;SI&lt;/h2&gt;

&lt;p&gt;Unfortunately, I wrote this in German. But the derivations could be interesting
nevertheless.&lt;/p&gt;

&lt;h3 id=&quot;statische-systeme&quot;&gt;Statische Systeme&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Statische Systeme&lt;/strong&gt; sind besonders einfache wertediskrete Systeme, in denen die
Ausgabe y nur von der Eingabe u abhängt. Wobei u und y diskrete Zufallsvariablen
sind. Ein statisches System S stellt eine bedingte Wahrscheinlichkeitsverteilung
dar: $P(y=i|u=j)$. Von der Verteilung u zur Verteilung y. Da beide diskreten ZV auf endlichen Mengen definiert sind, können wir S als &lt;strong&gt;stochastische Matrix&lt;/strong&gt; A darstellen.
Diese enthält per Konvention $(P(y=i|u=j))_{i,j}$, also pro Zeile die Verteilung
für ein konkretes u. A enthält nur nicht negative Einträge, jede Zeilensumme ist
eins. Wenn zusätzlich auch noch die Spaltensummen ein ergeben, dann spricht man
von einer doppelt-stochastischen Matrix.&lt;/p&gt;

&lt;p&gt;Möchte man nun y aus u errechnen, so kann man so vorgehen:&lt;/p&gt;

\[P(y=i) \stackrel{(1)}{=}  \sum_{j=1}^{J}{P(y=i, u=j)}   
          \stackrel{(2)}{=}  \sum_{j=1}^{J}{ P(y=i|u=j) \cdot P(u=j)}
          \stackrel{(3)}{=}  A^T \cdot P(u)\]

&lt;p&gt;(1) Satz der totalen W’keit. (2) Konditionierung. (3) Summe als Matrix.&lt;/p&gt;

&lt;p&gt;Man sieht also, dass das System nicht deterministisch ist. Unsicherheiten werden
weiter propagiert.&lt;/p&gt;

&lt;h3 id=&quot;dynamische-systeme-diskret&quot;&gt;Dynamische Systeme (diskret)&lt;/h3&gt;

&lt;p&gt;Der Ausgang $\boldsymbol{y_k}$ hängt von Eingabe $\boldsymbol{u_k}$ und Zustand $\boldsymbol{x_k}$ ab.
Der Zustand fasst die gesamte Historie zusammen. Man unterteilt dyn. Systeme in die &lt;strong&gt;Systemabbildung&lt;/strong&gt; (dynamischer Teil) und die statische &lt;strong&gt;Messabbildung&lt;/strong&gt;.
Diskrete ZV $\boldsymbol{x_k}$ ist Markov-Kette erster Ordnung, falls gilt:&lt;/p&gt;

&lt;h4 id=&quot;systemabbildung&quot;&gt;Systemabbildung&lt;/h4&gt;

\[P(\boldsymbol{x_{k+1}}|\boldsymbol{x_{k}}, ... \boldsymbol{x_{0}}, \boldsymbol{u_{k}}, ...\boldsymbol{x_{0}}) = P(\boldsymbol{x_{k+1}}|\boldsymbol{x_{k}})\]

&lt;p&gt;(1. Markoweigenschaft)&lt;/p&gt;

&lt;p&gt;Man sagt: $\boldsymbol{x_{k+1}}$ ist bedingt unabhängig von $\boldsymbol{x_{k-1}}$ … $\boldsymbol{x_{0}}$. Wobei die Bedingung ist, dass $\boldsymbol{x_{k}}$ bekannt ist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achtung!&lt;/strong&gt; $\boldsymbol{x_{k+1}}$ ist &lt;strong&gt;nicht unabhängig&lt;/strong&gt; von $\boldsymbol{x_{0}}$. Nur bedingt unabhängig. Es folgt also, dass die zukünftige Entwicklung bedingt unabhängig von alten Zuständen ist, falls der aktuelle Zustand bekannt ist.
Man betrachte zum Beispiel einen fallenden Ball. Kennt man den Zustand (Position, Geschwindigkeit, Beschleunigung, etc.) des Balles, so kann man seinen nächsten Zustand ohne Wissen über die Vergangenheit prädizieren.&lt;/p&gt;

&lt;h4 id=&quot;messabbildung&quot;&gt;Messabbildung&lt;/h4&gt;

&lt;p&gt;Der Zustand ist meist &lt;strong&gt;nicht verfügbar&lt;/strong&gt; (Wortwahl ist Absicht). Man spricht von
einer “latenten Variable”. Stattdessen kann man meist modellieren, wie $y_k$ sein müsste, wenn man einen gewissen Zustand $x_k$ und einen gewissen Eingang $u_k$ hätte.
Diese Abbildung kann man ebenfalls als bedingte W’keit formulieren: $P(y_k=j|x_k=i, u_k=m)$.
Der Einfluss von $u_k$ wird als “Durchgriff” bezeichnet, aber oft weggelassen.
Wenn $y_k$ bedingt unabhängig von allen anderen ZV ist, falls $x_k$ gegeben ist,
so nennt man dies die 2. Markoweigenschaft.&lt;/p&gt;

&lt;p&gt;Die diskrete Messabbildung wird als Messmatrix B(i,j) bezeichnet (analog zu A.).&lt;/p&gt;

&lt;h4 id=&quot;hidden-markov-model-hmm&quot;&gt;Hidden Markov Model (HMM)&lt;/h4&gt;

&lt;p&gt;Mit folgenden Zutaten kann nun also ein HMM beschrieben werden:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Initialer Zustandsvektor&lt;/li&gt;
  &lt;li&gt;Systemabbildung&lt;/li&gt;
  &lt;li&gt;Messabbildung&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;prädiktion-filterung-und-glättung&quot;&gt;Prädiktion, Filterung und Glättung&lt;/h4&gt;

&lt;p&gt;Die Aufgabe eines Schätzers in einem solchen System läge zum Beispiel darin,
gegeben die Messungen bis zu einem Zeitpunkt t1, einen einzelnen oder mehrere
Zustände zu einem beliebigen Zeitpunkt t2 zu schätzen.&lt;/p&gt;

&lt;p&gt;Dabei unterscheidet man:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Prädiktion: t2 &amp;gt; t1&lt;/li&gt;
  &lt;li&gt;Filterung: t2 = t1 (Man prädiziert von (t2-1) zum aktuellen Zeitschritt und korriegiert
dann seine Schätzung mit der ebenfalls bekannten Messung)&lt;/li&gt;
  &lt;li&gt;Glättung: t2 &amp;lt; t1.
    &lt;ul&gt;
      &lt;li&gt;“Fixed-Lag smoothing” ähnlich zu Filterung bloß kleiner Lag.&lt;/li&gt;
      &lt;li&gt;“Fixed-Point Smoothing”: Der Zeitpunkt, der geschätzt werden soll, steht fest. Es kommen aber immer noch mehr Daten hinein.&lt;/li&gt;
      &lt;li&gt;“Fixed-interval smoothing”: Man schätzt alle Zustände bis zum t2=t1-1, verwendet aber nur die Messungen, die bei den aktuellen Zeitpunkten zur Verfügung standen.&lt;/li&gt;
      &lt;li&gt;“Fixed-interval prediction”: Man hat nur die Messungen in einem festen Interval, es kommt nicht neues mehr dazu. Diese feste Anzahl an Punkten verwendet man dann um beliebige Prädiktionen zu machen.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;wonham-filter&quot;&gt;Wonham Filter&lt;/h4&gt;

&lt;p&gt;Komplettes rekursives, diskretes Filter unter Verwendung von Einschrittprädiktion.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Dynamikmodell: $x_{t+1} = A^T x_t$&lt;/li&gt;
  &lt;li&gt;Messmodell: $y_t = B^T x_t$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aus einer Messung auf den Zustand zu schließen, funktioniert wie folgt:&lt;/p&gt;

\[P(x_k|y_{0:k})
    \stackrel{(1)}{=} P(x_k|y_k, y_{0:{k-1}}) \\
    \stackrel{(2)}{=} \frac{P(y_k|x_k, y_{0:{k-1}}) P(x_k|y_{0:{k-1}})}{P(y_k|y_{0:{k-1}})} \\
    \stackrel{(3)}{=} \frac{P(y_k|x_k, y_{0:{k-1}}) P(x_k|y_{0:{k-1}})}{\sum_{i}{P(y_k, x_k=i|y_{0:{k-1}})}} \\
    \stackrel{(4)}{=} \frac{P(y_k|x_k, y_{0:{k-1}}) P(x_k|y_{0:{k-1}})}{\sum_{i}{P(y_k|x_k=i,y_{0:{k-1}}) P(x_k=i|y_{0:{k-1}})}} \\
     \stackrel{(5)}{=} \frac{P(y_k|x_k) P(x_k|y_{0:{k-1}})}{\sum_{i}{P(y_k|x_k=i) P(x_k=i|y_{0:{k-1}})}} \\\]

&lt;p&gt;(1) Nur andere Schreibweise&lt;/p&gt;

&lt;p&gt;(2) Bayes Regel&lt;/p&gt;

&lt;p&gt;(3) Satz der totalen W’keit&lt;/p&gt;

&lt;p&gt;(4) Konditionierung&lt;/p&gt;

&lt;p&gt;(5) 2. Markovannahme&lt;/p&gt;

&lt;p&gt;Für ein konkret beobachtetes Symbol y’ bedeutet das, dass man aus der Matrix B die beobachtete Spalte entnimmt. Diese enthält die Likelihood von y’ unter allen möglichen Zuständen. Diesen multipliziert man dann mit vom Systemmodell prädizierten Zuständen und normiert. So erhält man einen durch die Beobachtungen verbesserte Schätzung über den Zustand.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;# Beispiel: Wie viele Sterne (1-5) hat ein Buch wirklich verdient?
#           Böse Bots bewerten Bücher entweder mit 5 oder 1 Stern.
#           Menschen tendieren zu &quot;nicht extremen&quot; Bewertungen.
#              Also lieber 4 als 5 Sterne geben, obwohl das Buch sehr gut war.
#              Und wenn ein Buch schon gut bewertet wird, dann ist man umso kritischer.
&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Starte gleichverteilt
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newaxis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Messungen, wenn das Buch 5 Sterne hätte
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Messungen, wenn das Buch 4 Sterne hätte
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Messungen, wenn das Buch 3 Sterne hätte
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.70&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Messungen, wenn das Buch 2 Sterne hätte
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.09&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Messungen, wenn das Buch 1 Sterne hätte
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Wie viele Sterne sollen wir auf unserer Website darstellen, wenn wir folgende
#    Bewertungen erhalten haben
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;star_ratings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;# Rekursive Filterung
&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Kunde bewertet: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 1 Stern &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 2 Sterne &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 3 Sterne &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 4 Sterne &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; 5 Sterne&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;star_rating&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;star_ratings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    
    &lt;span class=&quot;c1&quot;&gt;# step prediction
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# filter.
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# select the column of B for our observed measurement
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;B_col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;star_rating&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ones&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;diag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B_col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;  

    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{} Sterne &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; {:.2f} &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; {:.2f} &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; {:.2f} &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; {:.2f} &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; {:.2f}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;star_rating&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Kunde bewertet: 		 1 Stern 	 2 Sterne 	 3 Sterne 	 4 Sterne 	 5 Sterne
--------------------------------------------------------------------------------------------------------------
5 Sterne 		-&amp;gt;	 0.09 		 0.09 		 0.09 		 0.10 		 0.62
1 Sterne 		-&amp;gt;	 0.40 		 0.07 		 0.06 		 0.07 		 0.40
3 Sterne 		-&amp;gt;	 0.28 		 0.05 		 0.34 		 0.05 		 0.28
5 Sterne 		-&amp;gt;	 0.11 		 0.02 		 0.13 		 0.02 		 0.72
3 Sterne 		-&amp;gt;	 0.06 		 0.01 		 0.54 		 0.01 		 0.38
4 Sterne 		-&amp;gt;	 0.01 		 0.00 		 0.06 		 0.08 		 0.85
4 Sterne 		-&amp;gt;	 0.00 		 0.00 		 0.00 		 0.25 		 0.74
1 Sterne 		-&amp;gt;	 0.00 		 0.00 		 0.00 		 0.25 		 0.74
3 Sterne 		-&amp;gt;	 0.00 		 0.00 		 0.02 		 0.25 		 0.73
4 Sterne 		-&amp;gt;	 0.00 		 0.00 		 0.00 		 0.54 		 0.46
2 Sterne 		-&amp;gt;	 0.00 		 0.00 		 0.00 		 0.54 		 0.46
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;wertekontinuierliche-systeme&quot;&gt;Wertekontinuierliche Systeme&lt;/h3&gt;

&lt;h4 id=&quot;wertekontinuierliche-lineare-systeme&quot;&gt;Wertekontinuierliche lineare Systeme&lt;/h4&gt;

&lt;p&gt;Linearität eines System ($A:x\rightarrow y$) besteht dann, wenn folgende zwei Eigenschaften vorliegen:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Skalierung: $A(c \cdot x) = c \cdot A(x)$&lt;/li&gt;
  &lt;li&gt;Superposition: $A(x_1 + x_2) = A(x_1) + A(x_2)$&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In der Realität existieren lineare Systeme nur in gewissen Grenzen.&lt;/p&gt;

&lt;h4 id=&quot;statisches-system&quot;&gt;Statisches System&lt;/h4&gt;

&lt;p&gt;$ y_k = f(u_k) $, wobei $u_k \in R^{P}$ und $y_k \in R^{M}$&lt;/p&gt;

&lt;p&gt;Für $f$ linear kann man schreiben: $y_k = A_k u_k$ mit $A \in R^{MxP}$.&lt;/p&gt;

&lt;p&gt;Dieses generative Modell wird stochastisch, wenn $u_k$ eine W’keitsverteilung ist oder man endogenes Rauschen hinzufügt (also Rauschen im System). Dafür erweitert man $u_k$ zu $u_{k}^{*} = [u_k, w_k]$, wobei $w_k$ das Rauschen zusammenfasst.&lt;/p&gt;

&lt;p&gt;Die Unsicherheiten in $u_k$ und $y_k$ beschreibt man oft mit den ersten beiden Momenten dieser vektoriellen ZV (Erwartungswert und Kovarianzmatrix).&lt;/p&gt;

&lt;p&gt;Wir definieren $\hat{u}_k = E[u_k]$ und $C_k^u = Cov[u_k]$&lt;/p&gt;

&lt;h4 id=&quot;wichtige-erinnerung&quot;&gt;Wichtige Erinnerung&lt;/h4&gt;

&lt;p&gt;Die Linearität des Erwartungswertes liefert für ein lineares System: $E[y_k] = E[A_k u_k] = A_k E[u_k] = A_k \hat{u}_k$.&lt;/p&gt;

&lt;p&gt;Und die Kovarianz: $Cov[y_k] = Cov[y_k] = E[(E[y_k] - y_k)^2] = E[ (\hat{y}_k - y_k)^2 ] = E[ (A \hat{u}_k - A u_k)^2 ] = E[(A (\hat{u}_k - u_k))^2] = E[A ( \hat{u}_k - u_k)^2 A^T] = A E[ ( \hat{u}_k - u_k)^2 ] A^T = A Cov_k^u A^T$&lt;/p&gt;

&lt;h4 id=&quot;dynamische-systeme&quot;&gt;Dynamische Systeme&lt;/h4&gt;

&lt;p&gt;Lineare Entwicklung des Zustandes: $x_{k+1} = A_k x_k + B_k u_k$ (Markovkette 1. Ordnung, zeitvariant, ohne k wäre es zeitinvariant).&lt;/p&gt;

&lt;p&gt;Additives Rauschen: $u_k = \hat{u}_k + w_k$, wobei $w_k$ ein Zufallsvektor mit $E[w_k]=0$ und $Cov[w_k]=C_k^w$&lt;/p&gt;

&lt;p&gt;Messmodell: Zustand nicht &lt;strong&gt;verfügbar&lt;/strong&gt;. Achtung: Verfügbarkeit heißt, dass man eine Größe nicht messen kann, wobei &lt;strong&gt;Beobachtbarkeit&lt;/strong&gt; bedeutet, dass man mit Messungen auf die Größe schließen kann. Der verdeckte Zustand ist nicht verfügbar, aber beobachtbar. Beispiel: Position eines Autos in Foto ist verfügbar, Geschwindigkeit nur über mehrere Frames beobachtbar.&lt;/p&gt;

&lt;p&gt;Lineare Messabbilung: $y_k = H_k x_k + v_k$ wobei $v_k$ wieder additives Rauschen ist.&lt;/p&gt;

&lt;h3 id=&quot;kalman-filter&quot;&gt;Kalman Filter&lt;/h3&gt;

&lt;h4 id=&quot;prädiktionsschritt&quot;&gt;Prädiktionsschritt&lt;/h4&gt;

&lt;p&gt;$x_{k+1} = A_k x_k + B_k (\hat{u}_k + w_k)$&lt;/p&gt;

&lt;p&gt;$E[x_{k+1}] = E[A_k x_k + B_k (\hat{u}_k + w_k)] = E[A_k x_k] + E[B_k (\hat{u}_k + w_k)] = A_k \hat{x}_k + B_k E[\hat{u}_k + w_k] = A_k \hat{x}_k + B_k E[\hat{u}_k + w_k] = A_k \hat{x}_k + B_k \hat{u}$&lt;/p&gt;

&lt;p&gt;Notiz: $E[w_k] = 0$ per Definition. Wenn er nicht null wäre, aber bekannt, so könnte man ihn von $w_k$ abziehen. Wenn er nicht bekannt wäre, dann müsste man diesen ebenfalls schätzen.&lt;/p&gt;

&lt;p&gt;$Cov[x_{k+1}] = Cov[A_k x_k + B_k (\hat{u}_k + w_k)] = A_k C_k^x A_k^T + B_k C_k^w B_k^T$&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trick:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um die Kovarianz zu berechnen, definiert man $A_k^{&lt;em&gt;} = [A_k, B_k]$ und $x_k^{&lt;/em&gt;} = [x_k, u_k]^T$.&lt;/p&gt;

&lt;p&gt;Rauschen sei unabhängig von Zustand. Dann sieht $Cov[x_k^{*}]$ wie folgt aus: $\begin{bmatrix}C_k^x &amp;amp; 0\0 &amp;amp; C_k^w\end{bmatrix}$&lt;/p&gt;

&lt;p&gt;Dann geht:&lt;/p&gt;

\[Cov[x_{k+1}^{*}] = E[(x_k^{*} - \hat{x_k^{*}})^2] = E[(x_k^{*} - \hat{x_k^{*}}) (x_k^{*} - \hat{x_k^{*}})^T]\]

\[= E[A_k^{*} \cdot \begin{bmatrix} x_k - \hat{x_k} \\ u_k - \hat{u_k} \end{bmatrix} \cdot [(x_k - \hat{x_k})^T , (u_k - \hat{u_k})^T] \cdot {A_k^{*}}^T ]\]

\[= A_k^{*}  \cdot  E[\begin{bmatrix} x_k - \hat{x_k} \\ u_k - \hat{u_k} \end{bmatrix} \cdot [(x_k - \hat{x_k})^T , (u_k - \hat{u_k})^T]  ]  \cdot  {A_k^{*}}^T\]

&lt;p&gt;Da die Kovarianz mittelwertbefreit ist, folgt:&lt;/p&gt;

\[= A_k^{*}  \cdot  Cov[ \begin{bmatrix} x_k \\ u_k \end{bmatrix} ]  \cdot  {A_k^{*}}^T\]

\[= A_k^{*}  \cdot  \begin{bmatrix}C_k^x &amp;amp; 0\\0 &amp;amp; C_k^w\end{bmatrix}  \cdot  {A_k^{*}}^T\]

\[= [A_k, B_k]  \cdot  \begin{bmatrix}C_k^x &amp;amp; 0\\0 &amp;amp; C_k^w\end{bmatrix}  \cdot  \begin{bmatrix}A_k^T \\ B_k^T \end{bmatrix}\]

\[= A_k C_k^x A_k^T + B_k C_k^w B_k^T\]

&lt;h4 id=&quot;kalman-filterschritt&quot;&gt;Kalman Filterschritt&lt;/h4&gt;

&lt;p&gt;Lineare Messabbildung: $y_k = H_k x_k + v_k$ “Was für eine Messung erwarte ich?”&lt;/p&gt;

&lt;p&gt;Die Kombination von Vorwissen und Messung ermöglicht es, auf einen höherdimensionalen verdeckten Zustand zu schließen:&lt;/p&gt;

&lt;p&gt;$x_k^p = K_k^1 x_k + K_k^2 y_k$ (Der Filterschritt ist eine gewichtete Linearkombination)&lt;/p&gt;

&lt;p&gt;Gesucht ist das BLUE filter (Best linear unbiased estimator). Linear ist er ja schon.&lt;/p&gt;

&lt;p&gt;Unbiased: $E[x_k] = \tilde{x_k}$ Wobei $\tilde{x_k}$ die Grundwahrheit ist.&lt;/p&gt;

\[E[x_k^p] = E[K_k^1 x_k + K_k^2 y_k] = K_k^1 E[x_k] + K_k^2 E[y_k] = K_k^1 E[x_k] + K_k^2 H_k E[x_k] + E[v_k] = K_k^1 E[x_k] + K_k^2 H_k E[y_k] = K_k^1 \tilde{x_k} + K_k^2 H_k \tilde{x_k}\]

\[K_k^1 \tilde{x_k} + K_k^2 H_k \tilde{x_k} = \tilde{x_k}\]

\[K_k^1 + K_k^2 H_k = I\]

\[K_k^1 = I - K_k^2 H_k\]

&lt;p&gt;=&amp;gt; Dadurch kann man die Linearkombination mit nur einer Matrix $K_k$ ausdrücken:&lt;/p&gt;

\[x_k^p = (I - K_k^2 H_k) x_k + K_k^2 y_k = (I - K_k H_k) x_k + K_k y_k\]

&lt;p&gt;Die Frage ist nun, wie bestimmen wir das optimale K? Wir suchen das K, für das die prädizierte Kovarianz $C_k^e$ minimal wird.&lt;/p&gt;

\[C_k^e = Cov[x_k^p] = (I - K_k H_k) C_k^x (I - K_k H_k)^T + K_k C_k^y K_k^T\]

&lt;p&gt;$C_k^e$ ist abhängig von $K_k$. Daher schreiben wir: $C_k^p(K_k)$&lt;/p&gt;

&lt;p&gt;$C_k^p(K_k)$ ist positiv definit und symmetrisch, das heißt, es handelt sich um eine Kovarianzmatrix.
Wie minimiert man das?&lt;/p&gt;

&lt;p&gt;Man könnte $det(C_k^p(K_k))$ oder $trace(C_k^p(K_k))$ minimieren. Beide sind proportional zum Flächeninhalt der Kovarianzellipse. Die Determinante ist 1/4 des umschließenden Rechteckes. Die Spur hat die Größe des größten Quaders, der in die Ellipse hineinpasst.&lt;/p&gt;

&lt;p&gt;Wenn man die Determinante minimiert, dann ist es theoretisch möglich, dass eine Richtung 0 wird. Dadurch wird der Flächeninhalt null und die Covarianz ist minimal. Das ist unschön, weil man die Unsicherheit in alle Richtungen minimieren will.&lt;/p&gt;

&lt;p&gt;Daher verwenden wir die Projektion der Matrix auf alle möglichen Einheitsvektoren e. Diese Projektion P(K) liefert ein skalares Gütemaß, welches wir minimieren.&lt;/p&gt;

&lt;p&gt;\(P(K_k) = e^T C_k^e(K_k) e\).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ableitungsregeln für Matrizen:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Matrix C:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;$ d/dC (a^T C b) = a^T b $  ($a^T b$ ist diadisches Produkt, also eine singuläre Matrix. Rang=1. det=0. nicht invertierbar.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;$ d/dK (a^T K C K^T b) = ab^T K C^T + ba^T K C $ (KCK^T ist ein lineare Propagation, evtl. Basiswechsel. a^T … b  ist eine Projektion.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;wenn a=b=e und C symm., dann: $ d/dK (e^T K C K^T e) = 2 ee^T KC $&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;jetzt können wir $P(K_k)$ ableiten:&lt;/p&gt;

\[\frac{d}{dK_k} e^T C_k^e(K_k) e =\]

\[\frac{d}{dK_k} e^T ((I - K_k H_k) C_k^x (I - K_k H_k)^T + K_k C_k^y K_k^T) e =\]

\[\frac{d}{dK_k} e^T ( (I C_k^x I^T) - (I C_k^x H_k^T K_k^T) - (K_k H_k C_k^x I^T) + (K_k H_k C_k^x H_k^T K_k^T)  +   K_k C_k^y K_k^T) e =\]

&lt;p&gt;Erster Summand fällt weg, weil er kein K enthält.&lt;/p&gt;

\[\frac{d}{dK_k} e^T ( - (I C_k^x H_k^T K_k^T) - (K_k H_k C_k^x I^T) + (K_k H_k C_k^x H_k^T K_k^T)  +   K_k C_k^y K_k^T) e =\]

&lt;p&gt;Projektion auf alle Summanden anwenden:&lt;/p&gt;

\[\frac{d}{dK_k} - e^T (I C_k^x H_k^T K_k^T) e - e^T (K_k H_k C_k^x I^T) e + e^T (K_k H_k C_k^x H_k^T K_k^T) e  +  e^T ( K_k C_k^y K_k^T) e\]

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Summand (Mit $D^T = C_k^x H_k^T$ und)
 \(\frac{d}{dK_k} - e^T (I C_k^x H_k^T K_k^T) e =\)&lt;/p&gt;

\[(\frac{d}{dK_k^T} - (e^T (D^T K_k^T) e))^T = - (D ee^T)^T = - (H_k C_k^x ee^T)^T\]
  &lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;2 Summand:
  \(- ee^T (H_k C_k^x)^T\)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;3 Summand:
  \(2 ee^T K_k H_k C_k^x H_k^T\)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;4 Summand:
  \(2 ee^T K_k C_k^y\)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Daraus folgt:&lt;/p&gt;

\[\frac{d}{dK_k} - e^T (I C_k^x H_k^T K_k^T) e - e^T (K_k H_k C_k^x I^T) e + e^T (K_k H_k C_k^x H_k^T K_k^T) e  +  e^T ( K_k C_k^y K_k^T) e\]

\[= - (H_k C_k^x ee^T)^T  - ee^T (H_k C_k^x)^T   + 2 ee^T K_k H_k C_k^x H_k^T  + 2 ee^T K_k C_k^y\]

&lt;p&gt;Setzen wir Null:&lt;/p&gt;

\[- (H_k C_k^x ee^T)^T  - ee^T (H_k C_k^x)^T   + 2 ee^T K_k H_k C_k^x H_k^T  + 2 ee^T K_k C_k^y  \stackrel{!}{=}  0\]

\[= ee^T [-{C_k^x}^T H_k^T  - {C_k^x}^T H_k^T  + 2 K_k H_k C_k^x H_k^T  + 2 K_k C_k^y ]\]

\[= ee^T [-2{C_k^x}^T H_k^T  + 2 K_k H_k C_k^x H_k^T  + 2 K_k C_k^y ]\]

&lt;p&gt;Wir multiplizieren beidseitig mit $({ee^T})^{-1}$:&lt;/p&gt;

\[-2{C_k^x}^T H_k^T  + 2 K_k H_k C_k^x H_k^T  + 2 K_k C_k^y  = 0\]

\[+ 2 K_k H_k C_k^x H_k^T  + 2 K_k C_k^y = +2{C_k^x}^T H_k^T\]

&lt;p&gt;Teilen durch 2:&lt;/p&gt;

\[K_k H_k C_k^x H_k^T  + K_k C_k^y = {C_k^x}^T H_k^T\]

&lt;p&gt;Klammern $K_k$ aus:&lt;/p&gt;

\[K_k (H_k C_k^x H_k^T + C_k^y) = {C_k^x}^T H_k^T\]

&lt;p&gt;Und multiplizieren rechtseitig mit  $(H_k C_k^x H_k^T + C_k^y)^{-1}$, um $K_k$ alleine zu stellen:&lt;/p&gt;

\[K_k = (C_k^x)^T H_k^T (H_k C_k^x H_k^T + C_k^y)^{-1}\]

&lt;p&gt;Das Transponierte der Kovarianzmatrix ist immernoch die Kovarianzmatrix, da sie symmetrisch ist:&lt;/p&gt;

\[K_k = C_k^x H_k^T (H_k C_k^x H_k^T + C_k^y)^{-1}\]

&lt;p&gt;$K_k$ heißt &lt;strong&gt;Kalman Gain&lt;/strong&gt; und ist optimal, wenn:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;das Filter linear ist und&lt;/li&gt;
  &lt;li&gt;die Zufallsvariablen normalverteilt sind (zum Beispiel additives, normalverteiltes Rauschen)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Somit ergibt sich:&lt;/p&gt;

\[E[x_k^e] = (I - K_k H_k) E[x_k^p] + K_k E[y_k]\]

&lt;p&gt;Und:&lt;/p&gt;

&lt;p&gt;\(C_k^e = Cov[x_k^p] = (I - K_k H_k) C_k^x (I - K_k H_k)^T + K_k C_k^y K_k^T\)
\(...\)
\(C_k^e = C_k^p - K_k H_k C_k^p\)&lt;/p&gt;

&lt;p&gt;Für intuitive Anschauungen eignet es sich die &lt;strong&gt;Feedback Form&lt;/strong&gt; zu betrachten:&lt;/p&gt;

\[\hat{x_k^e} = \hat{x_k^p} + K_k (\hat{y_k} - H_k \hat{x_k^p})\]

&lt;p&gt;Hieran lässt sich erkennen, dass der geschätzte Zustand nach einem Messupdate eine Kombination des priori Zustandes mit dem neuen Wissen aus der Messung ist. Wenn das Kalman Gain hoch ist, dann wird die Messung mit geringer Unsicherheit gesehen und somit werden starke Abweichungen der Messung von der erwarteten Messung stark auf den neuen Zustand einfließen. Wenn das Messrauschen unendlich groß wäre, dann wäre $K_k=0.$&lt;/p&gt;

&lt;h2 id=&quot;allgemeine-systeme&quot;&gt;Allgemeine Systeme&lt;/h2&gt;

&lt;h3 id=&quot;statische-systeme-1&quot;&gt;Statische Systeme&lt;/h3&gt;

&lt;p&gt;Generatives Modell (Werte abgebildet auf Werte):
\(\underline{\mathbf{y}_k} = a(\underline{\mathbf{u}_k})\)&lt;/p&gt;

&lt;p&gt;Jetzt sind aber $u_k$ und $y_k$ durch die W’keitsverteilungsdichtefunktionen (kurz “Dichten”) $f_k^u(\underline{\mathbf{u}_k})$ und $f_k^y(\underline{\mathbf{y}_k})$&lt;/p&gt;

&lt;p&gt;Würde man nun einfach trotzdem mit Erwartungswert und Kovarianz weiterrechnen, anstatt die Dichten zu betrachten, dann wäre das eine Linearisierung, wie sie beim EKF vorgenommen wird.&lt;/p&gt;

&lt;p&gt;Gesucht ist also die Dichte $f_k^y(\underline{\mathbf{y}_k})$ zur gegebenen Dichte $f_k^u(\underline{\mathbf{u}_k})$. Ein Abbildung von einer Dichte zu einer anderen Dichte nennen wir probabilistisches Modell.&lt;/p&gt;

&lt;h3 id=&quot;dynamische-systeme-1&quot;&gt;Dynamische Systeme&lt;/h3&gt;

&lt;p&gt;Diese zerfallen wieder in das Beobachtungsmodell und die Systemabbildung.&lt;/p&gt;

&lt;p&gt;Ein “einfacheres” nichtlineares Systemmodell: \(x_{k+1} = a_k(x_k, \hat{u}_k, w_k)\)&lt;/p&gt;

&lt;p&gt;Es wäre schwieriger, wenn $x_{x+1}$ auch auf der rechten Seite vorkäme, dann spricht man von einem impliziten System. Dieser Fall wurde in LMA behandelt.)&lt;/p&gt;

&lt;p&gt;Für additives Rauschen kommt man leicht vom generativen zu einem probabilistischen Modell:&lt;/p&gt;

\[x_{k+1} = a(x_k, \hat{u}_k) + w_k\]

&lt;p&gt;Das Systemrauschen \(w_k\) ist hier additiv und wird beschrieben durch die Dichte $f_k^w(w_k)$.&lt;/p&gt;

&lt;p&gt;Zusätzlich gehen wir davon aus, dass das Systemrauschen:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Gaussverteil ist mit bekannten Parametern.&lt;/li&gt;
  &lt;li&gt;$f_k^w(w_k)$ für unterschiedliche k unabhängig voneinander sind. Im Falle von Gaußverteilung reicht &lt;strong&gt;unkorreliert&lt;/strong&gt;, da in diesem Fall unabhängig daraus folgt. Dann gilt für die gemeinsame Verteilung zweier  Rauschdichten: $f_{1,2}^w(w_1, w_2) = f_1^w(w_1) \cdot f_2^w(w_2)$&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bei der Messabbildung kann genauso verfahren werden: \(y_k = h_k(x_k) + v_k\)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Was für Dichten können wir verwenden?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Kontinuierliche analytische Dichten
    &lt;ul&gt;
      &lt;li&gt;Gaußdichte&lt;/li&gt;
      &lt;li&gt;GMM&lt;/li&gt;
      &lt;li&gt;Exponentialdichte (Exponenten komplexer machen)&lt;/li&gt;
      &lt;li&gt;Edgeworth-Entwicklungen (Gaußdichte mit Polynom multipliziert. Nichts globales, aber lokal bekommt man ein paar Hügel rein).&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Diskrete Dichten auf kontinuierlichen Domänen
    &lt;ul&gt;
      &lt;li&gt;Dirac-Mixture Densities&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;blick-auf-gaußdichte&quot;&gt;Blick auf Gaußdichte&lt;/h3&gt;

&lt;p&gt;2d:
\(f_{x,y}(x,y) = N(\begin{bmatrix}x\\y\end{bmatrix} - \begin{bmatrix}\hat{x}\\\hat{y}\end{bmatrix}, \begin{bmatrix}\sigma_x^2 &amp;amp; \rho \sigma_x \sigma_y \\ \rho \sigma_x \sigma_y &amp;amp; \sigma_y^2  \end{bmatrix})\)&lt;/p&gt;

&lt;p&gt;Wobei $\rho \in [-1, +1]$ als Korrelationskoeffizient bezeichnet wird. Wenn dieser =+1 ist, dann lieft eine deterministische Abhängigkeit vor.&lt;/p&gt;

&lt;p&gt;Man schreibt manchmal:
\(f_{x,y}(x,y) = \frac{1}{2 \pi \sigma_x \sigma_y \sqrt{(1-\rho^2)}} \exp(-\frac{1}{2}Q(x,y))\)&lt;/p&gt;

&lt;p&gt;mit \(Q(x,y) = \frac{1}{1-\rho} \Big(  \frac{(x-\hat{x})^2}{\sigma_x^2} +  \frac{(y-\hat{y})^2}{\sigma_y^2}   - 2 \rho \frac{x-\hat{x}}{\sigma_x} \frac{y-\hat{y}}{\sigma_y}    \Big)\)&lt;/p&gt;

&lt;p&gt;Maßgrößen für Kovarianzen:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;die Determinante von Cov det(C) ist proportional zum Volumen der Kovarianz-Körpers, da die Determinante das Produkt der Eigenwerte ist. Somit ist im 2d-Fall zum Beispiel 4*det(C) die Fläche des umschließenden Rechtecks.&lt;/li&gt;
  &lt;li&gt;Spur (Summe der Quadrate der Diagonale): Nach Pythagoras ist die Spur einer diagonalen Kovarianzmatrix das Quadrat der der Länge … -&amp;gt; Wurzel … Vorteil: Spur invariant ggü. unitärer Rotation. Selbst wenn ein Eigenwert mal 0 sein sollte, dann ist die Spur immernoch nicht null.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;moment-matching&quot;&gt;Moment Matching&lt;/h3&gt;

&lt;p&gt;Berechne die Verteilung einer Population anhand ihrer Momente. Angenommen wir haben eine Stichprobe aus der Population genommen. Nun könnten wir zum Beispiel die empirischen 1. und 2. Momente berechnen. Empirischer Mittelwert und empirische Varianz. Nun wählen wir eine beliebige Verteilungsfunktion. Jetzt können wir Parameter für die Verteilung bestimmen, die empirischen Momente liefern. Diese Methode ist besser per Hand zu rechnen und kann zum Beispiel auch als Initialisierung für eine Maximum-Likelihood-Schätzung verwendet werden.&lt;/p&gt;

&lt;p&gt;Theorem: Für eine gegebene Dichte $\tilde{f}(x)$ führt die Wahl von $m=E_{\tilde{f}}[x]$ und $\sigma^2=Cov_{\tilde{f}}[x]$, zu einer Minimierung der Kullback-Leibler-Divergenz zwischen $\tilde{f}$ und der Normalverteilung.&lt;/p&gt;

\[KL = \int_{R} {  \tilde{f}(x) log\big( \frac{\tilde{f}(x)}{f(x)}  \big)  } dx\]

&lt;p&gt;&lt;strong&gt;Offene Frage:&lt;/strong&gt; Warum $\tilde{f}(x)$ als Vorfaktor?&lt;/p&gt;

&lt;p&gt;Das i-te zentrale Momente einer Gaußdichte lautet:&lt;/p&gt;

\[C_i = E[(x-x)^{i}]\]

&lt;p&gt;Ein zentrales Moment ist das gleiche, wie ein “normales” Moment, bloß, dass man die Dichte um Null zentriert hat.&lt;/p&gt;

&lt;p&gt;ToDo: Beschreibe, wie man Momente generell berechnen kann.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GMM&lt;/strong&gt;: $f(x) = \sum_{i=1}^{L}{w_i N(\hat{x}_i, \sigma_i)}$&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Anzahl Moden ist ungleich Anzahl Komponenten -&amp;gt; Maximum bestimmen nicht trivial&lt;/li&gt;
  &lt;li&gt;Wir akzeptieren nur $w_i &amp;gt; 0$. Theoretisch geht es aber auch anders. Und Summe der Gewichte muss 1 sein.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Ein GMM mit L Komponenten hat 3L-1 Freiheitsgrade&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;diracsche-deltafunktion&quot;&gt;Diracsche Deltafunktion&lt;/h3&gt;

&lt;p&gt;$\delta(x-x_0) = $ …&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;nicht definiert, für $x=x_0$&lt;/li&gt;
  &lt;li&gt;0, für alles andere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mit $\int_{R}{\delta(x-x_0) dx} = 1$&lt;/p&gt;

&lt;p&gt;Sie besitzt die &lt;strong&gt;Ausblendeigenschaft&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;$\int f(x) \delta(x-x_0) dx = f(x_0)$&lt;/li&gt;
  &lt;li&gt;Auch: $f(x) \cdot \delta(x-x_0) = f(x_0) \cdot \delta(x-x_0)$
    &lt;ul&gt;
      &lt;li&gt;Fall $x=x_0$: $f(x_0) = f(x_0)$&lt;/li&gt;
      &lt;li&gt;Sonst: 0&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Allgemein gilt:&lt;/p&gt;

\[\delta(f(x)) = \sum_{i=1}^{N}{\frac{1}{|f'(x_i)|} \delta(x-x_i) }\]

&lt;p&gt;$x_i$ sind die N Nullstellen der Funktion f(x). $f(x) \ne 0$&lt;/p&gt;

&lt;p&gt;Beweis dazu: https://math.stackexchange.com/questions/276583/dirac-delta-function-of-a-function.&lt;/p&gt;

&lt;p&gt;(Eine sehr umfassende Sammlung von Eigenschaften der diracschen Delta-Funktion: https://mathworld.wolfram.com/DeltaFunction.html)&lt;/p&gt;

&lt;p&gt;Beispiele generatives Modell zu bedingter Dichte:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;$y = 3 * x$ —–&amp;gt; $f(y&lt;/td&gt;
      &lt;td&gt;x) = \delta(y-3x)$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;$y = a(x) + w$ —–&amp;gt; $f(y&lt;/td&gt;
      &lt;td&gt;x,w) = \delta(y-a(x)-w)$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Bei den bedingten Dichten handelt es sich also um dirac distributionen, die nur dort ungleich Null sind, wo die Funktion wahr ist.&lt;/p&gt;

&lt;h4 id=&quot;additives-rauschen&quot;&gt;Additives Rauschen&lt;/h4&gt;

\[x_{k+1} = a_k(x_k) + w_k\]

\[f^{x_{k+1}}(x_{k+1}| x_k, w_k) = \delta(a_k(x_k) + w_k - x_{k+1})\]

\[f^{x_{k+1}}(x_{k+1}| x_k) = \int{f^{x_{k+1}, w_k}(x_{k+1}, w_k| x_k) d w_k}\]

\[f^{x_{k+1}}(x_{k+1}| x_k) = \int{f^{x_{k+1}}(x_{k+1}|x_k, w_k) \cdot f^w(w_k|x_k) d w_k}\]

&lt;p&gt;Hier nehmen wir jetzt an, dass das Rauschen unabhängig von den Daten ist.&lt;/p&gt;

\[f^{x_{k+1}}(x_{k+1}| x_k) = \int{f^{x_{k+1}}(x_{k+1}|x_k, w_k) \cdot f^w(w_k) d w_k}\]

&lt;p&gt;Jetzt Dirac einsetzen:&lt;/p&gt;

\[f^{x_{k+1}}(x_{k+1}| x_k) = \int{\delta(a_k(x_k) + w_k - x_{k+1}) \cdot f^w(w_k) d w_k}\]

&lt;p&gt;Für welches $w_k$ ist der Dirac-Stoß ungleich Null? (vgl. $\delta(w_k - w_{k,0})$)&lt;/p&gt;

\[a_k(x_k) + w_k - x_{k+1} = 0\]

\[w_k  = x_{k+1} - a_k(x_k)\]

&lt;p&gt;Durch Siebeigenschaft des Dirac folgt:&lt;/p&gt;

\[f^{x_{k+1}}(x_{k+1}| x_k) = f^w(x_{k+1} - a_k(x_k) )\]

&lt;p&gt;Was eine bequeme Form für additives Rauschen ist. Wenn das Rauschen zum Beispiel normalverteilt ist, dann ist die Transitionsdichte für ein gegebens x_k ebenfalls normalverteilt.&lt;/p&gt;

&lt;h4 id=&quot;multiplikatives-rauschen&quot;&gt;Multiplikatives Rauschen&lt;/h4&gt;

&lt;p&gt;$ x_{k+1} = x_k \cdot w_k $ mit $w_k \sim f_k^w(w_k)$&lt;/p&gt;

\[f(x_{k+1}|x_k, w_k) = \delta(g(w_k))\]

\[g(w_k) = x_k w_k - x_{k+1}\]

&lt;p&gt;Finde Nullstellen von g:&lt;/p&gt;

\[x_k w_k - x_{k+1} = 0\]

\[x_k w_k  = x_{k+1}\]

\[w_k  = \frac{x_{k+1}}{x_k}\]

\[\frac{d}{d w_k} g(w_k) = x_k\]

&lt;p&gt;Daraus folgt:&lt;/p&gt;

\[\delta(g(w_k)) = \frac{1}{|x_k|} \delta(w_{k} - \frac{x_{k+1}}{x_k})\]

\[f(x_{k+1}|x_k) = \int{f(x_{k+1}|x_k, w_k) f_k^w(w_k) d w_k}\]

\[f(x_{k+1}|x_k) = \int{\delta(g(w_k)) f_k^w(w_k) d w_k}\]

\[f(x_{k+1}|x_k) = \int{\frac{1}{|x_k|} \delta(w_{k} - \frac{x_{k+1}}{x_k}) f_k^w(w_k) d w_k}\]

\[f(x_{k+1}|x_k) = \frac{1}{|x_k|} f_k^w(\frac{x_{k+1}}{x_k})\]

&lt;h3 id=&quot;visualisierung-der-transitionsdichte&quot;&gt;Visualisierung der Transitionsdichte&lt;/h3&gt;

&lt;p&gt;y = a(x) + w&lt;/p&gt;

&lt;p&gt;y = x + N(0, 1)&lt;/p&gt;

\[f(y|x) = \int{f(y|x,w) \cdot f(w) dw} = f^w(y - a(x)) = f^w(y - x)\]

\[f(y|x) = N(y - x)\]

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;scipy.stats&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;norm&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matplotlib&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;notebook&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meshgrid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;norm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;



&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;figure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gca&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;projection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'3d'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;surf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot_surface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coolwarm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                       &lt;span class=&quot;n&quot;&gt;linewidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;antialiased&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Add a color bar which maps values to colors.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;colorbar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;surf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shrink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aspect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xlabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$x_k$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ylabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$y_k$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_zlabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;$P(y|x)$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;IPython.core.display.Javascript object&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;data:image/png;base64,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fk+ePFG8O0hERG8OA5CIiIhIZBiARERERCLDACQiIiISGQYgERERkcgwAImIiIhEhgFIREREJDIMQCIiIiKRYQASERERiQwDkIiIiEhkGIBEREREIsMAJCIiIhIZBiARERGRyDAAiYiIiESGAUhEREQkMgxAIiIiIpFhABIRERGJDAOQiIiISGQYgEREREQiwwAkIiIiEhkGIBEREZHIMACJiIiIRIYBSERERCQyDEAiIiIikWEAEhEREYkMA5CIiIhIZBiARERERCLDACQiIiISGQYgERERkcgwAImIiIhEhgFIREREJDIMQCIiIiKRYQASERERiQwDkIiIiEhkGIBEREREIsMAJCIiIhIZBiARERGRyDAAiYiIiESGAUhEREQkMgxAIiIiIpFhABIRERGJDAOQiIiISGQYgEREREQiwwAkIiIiEhkGIBEREZHIMACJiIiIRIYBSERERCQyDEAiIiIikWEAEhEREYkMA5CIiIhIZBiARERERCLDACQiIiISGQYgERERkcgwAImIiIhEhgFIREREJDIMQCIiIiKRYQASERERiQwDkIiIiEhkGIBEREREIsMAJCIiIhIZBiARERGRyDAAiYiIiESGAUhEREQkMgxAIiIiIpFhABIRERGJDAOQiIiISGQYgEREREQiwwAkIiIiEhkGIBEREZHIMACJiIiIRIYBSERERCQyDEAiIiIikWEAEhEREYkMA5CIiIhIZBiARERERCLDACQiIiISGQYgERERkcgwAImIiIhEhgFIREREJDIMQCIiIiKRYQASERERiQwDkIiIiEhkGIBEREREIsMAJCIiIhIZBiARERGRyDAAiYiIiESGAUhEREQkMgxAIiIiIpH5/7hsKg08ijc9AAAAAElFTkSuQmCC&quot; width=&quot;640&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Dieser Plot ist so zu sehen, dass für jedes gegeben $\hat{x}_k$ eine Normalverteilung vorliegt. Die Verbundwahrscheinlichkeit von $P(x,y)$ im Diskreten oder $f^{x,y}(x,y)$ im Kontinuierlichen hängt von $x_k$ ab.
Im Diskreten kann man folgenden Satz nutzen: $P(X \cap Y) = P(X|Y) \cdot P(Y) = P(Y|X) \cdot P(X)$.&lt;/p&gt;

&lt;h3 id=&quot;chapman-kolmogorov-integral-cki&quot;&gt;Chapman-Kolmogorov-Integral (CKI)&lt;/h3&gt;

&lt;p&gt;Betrachten wir einen stochastischen Prozess $(x)_k$ bei dem wir die 1. Markov-Eigenschaft annehmen.&lt;/p&gt;

\[f(x_{k+1}) = \int_{R}{ f(x_{k+1}|x_k) \cdot f(x_k)  d x }\]

&lt;p&gt;Wir berechnen die Transitionsdichte zunächst weiterhin mit der dirachsen Delta-Funktion.
Für den Trivialfall, dass $f(x_k)$ deterministisch (also dirac-verteilt) ist, löst sich das Intergral noch von selbst auf.&lt;/p&gt;

&lt;p&gt;Das Hauptproblem ist, dass es sich beim CKI um ein Parameterintegral handelt.
Das heißt, es ist nicht nur abhängig von der Integriervariable $x_k$, sondern auch noch von anderen “freien” Variablen. In diesem Fall $x_{k+1}$.&lt;/p&gt;

&lt;h3 id=&quot;beobachtungen-einfließen-lassen&quot;&gt;Beobachtungen einfließen lassen&lt;/h3&gt;

&lt;p&gt;Gegeben einer Beobachtung $\hat{y}$ müssen wir uns entscheiden, was für eine Art von Schätzer wir haben wollen:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Maximum-Likelihood: $$arg_x max f(\hat{y}&lt;/td&gt;
      &lt;td&gt;x)$$&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Maximum-A-Posteriori: $$arg_x max f(x&lt;/td&gt;
      &lt;td&gt;\hat{y})$$&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Angenommen wir haben das folgende generative Modell: $y = x^2 + v$
Dann erhalten wir \(f(y|x,v) = \delta(y-x^2-v)\)&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Interessieren wir uns für $f(x&lt;/td&gt;
      &lt;td&gt;\hat{y})$:&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

\[f(x|\hat{y}) = \frac{f(x, \hat{y})}{f(\hat{y})} = \frac{f(\hat{y}|x) f(x)}{f(\hat{y})}\]

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/lecture/stochastic-information-processing&quot;&gt;Stochastic Information Processing&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on April 17, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Nearest Neighbour in DBs]]></title>
  <link>https://danielpollithy.github.io/general/nearest-neighbour-in-database</link>
  <id>https://danielpollithy.github.io/general/nearest-neighbour-in-database</id>
  <published>2020-02-22T00:00:00+01:00</published>
  <updated>2020-02-22T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This post explains iDistance and R-Trees for k Nearest Neighbour (kNN) matching.
Both are using regular database indices to solve the problem.&lt;/p&gt;

&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Assume you want to use kNN in a live system with many data points.&lt;/li&gt;
  &lt;li&gt;The data points are rows in your relational database.&lt;/li&gt;
  &lt;li&gt;Problem: The classic kNN algorithm would have to scan your whole table.&lt;/li&gt;
  &lt;li&gt;Solution: Build an index.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following I am going to explain two possible solutions using indices
which are implemented in most database systems.&lt;/p&gt;

&lt;h2 id=&quot;r-trees&quot;&gt;R-Trees&lt;/h2&gt;

&lt;p&gt;We have the following point cloud:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, depending on the exact tree implementation (for example x-tree), the space
get separated into multiple layers of containing rectangles.
Every rectangle is a minimum bounding rectangle for either another rectangle or
points of a lower layer.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The recursive structure of the rectangles containing rectangles or points forms
a tree: &lt;strong&gt;the R-tree&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now let us say that you are here:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And want to find the k=4 nearest points.&lt;/p&gt;

&lt;p&gt;We start by calculating the distance to the closest objects in the highest layer.
The highest layer only contains rectangles, therefore we calculate the shortest
distance to the rectangles.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We traverse the rectangles by ascending distance until a rectangle is more distant
than our furthest nearest neighbour.
All of the points in a rectangle are scanned sequentially.&lt;/p&gt;

&lt;p&gt;The next image shows the best k=4 candidates.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The largest distance within the group of candidates determines whether we can
exclude rectangles. The distance is illustrated as a red circle in the next image.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Having finished the right rectangle. We proceed to the left, small rectangle.
The nearest neighbours change, because there are closer ones. This results in a
red circle with a smaller diameter.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finished! The yellow rectangle is out of reach. It was not processed but it could
neither supply a point close enough to become a nearest neighbour.
This “exclusion” is what saves us from doing a whole sequential scan.&lt;/p&gt;

&lt;h3 id=&quot;the-problem-with-r-trees&quot;&gt;The problem with R trees&lt;/h3&gt;

&lt;p&gt;According to the curse of dimensionality: With increasing dimensionality, the
distance between two points grows exponentially.&lt;/p&gt;

&lt;p&gt;This results in larger minimum bounding rectangles which tend to span the whole
space diagonal. But these rectangles are not a good partitioning of the space
anymore. To many intersections between them result in scanning most of them.
This can become even worse than the sequential scan, because now we use an index
which takes up space, but only supports sequential scans.&lt;/p&gt;

&lt;h2 id=&quot;idistance&quot;&gt;iDistance&lt;/h2&gt;

&lt;p&gt;The main idea of iDistance is to partition the space into spheres. And then
reduce the points which have to be scanned by using the distance of the points
to their closest sphere center in a B+ tree.&lt;/p&gt;

&lt;p&gt;We visualize the algorithm with the following point cloud again.
This time we look for k=3.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;First of all we have to partition the data. For example using k-Means or DBSCAN.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Every point is only part of one partition (sphere). For every partition we calculate
the distance to the center and use this information as an index for the partition.
This is where the B+ tree is used. (Note: It is also possible to use a single
  B+ tree for all partitions. It just necessary to shift the centers with an offset
  large enough to disable intersections. The space diagonal should be enough.)&lt;/p&gt;

&lt;p&gt;It is time for a new query at the same position:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Opposed to the procedure of the R trees which shrank the radius of the red circle,
iDistance starts with a small radius and increases it incrementally.
These are two hyperparameters: &lt;strong&gt;initial_radius&lt;/strong&gt; and &lt;strong&gt;radius_growth_factor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The initial_radius was too small. We found no partition.
As long as we don’t have enough points, we increase the initial_radius by
multiplying it with the radius_growth_factor.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We find three intersections with  three partitions. Here comes the “trick”.
For every partition we can calculate the ring which intersects with the red
query circle. Only the points in the ring can be in the intersection. The rest
of the partition does not have to be scanned (marked with black).
This saves us time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the case of our example for k=3 we would already be done:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/kNN/kNN_13.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Attention: All points in the ring have to be scanned.&lt;/p&gt;

&lt;p&gt;In the case of the left, small circle, another speedup comes in handy, too.
The B+ tree of this partition allows us to early abort the search.
We can order the points in descending distance from the center. This way we start
with the closest point first. Fortunately it is also closest to our point and we
can stop the search. Note however, that it does not have to be that way.
The point with the largest distance to the center of this partition could also have
been on the left side of the center.&lt;/p&gt;

&lt;p&gt;iDistance is not a mitigation to the problem introduced by the curse of dimensionality
but it can restrict the search space within a partition. This leads to a better
behaviour compared to the R tree.&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/nearest-neighbour-in-database&quot;&gt;Nearest Neighbour in DBs&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on February 22, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Partitioned Normal Form]]></title>
  <link>https://danielpollithy.github.io/general/partitioned-normal-form</link>
  <id>https://danielpollithy.github.io/general/partitioned-normal-form</id>
  <published>2020-02-21T00:00:00+01:00</published>
  <updated>2020-02-21T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;What is the Partitioned Normal Form (PNF) in the context of databases?&lt;/p&gt;

&lt;h2 id=&quot;nf&quot;&gt;NF²&lt;/h2&gt;

&lt;p&gt;NF² = NFNF = ¬NF = Non-First-Normal-Form.&lt;/p&gt;

&lt;p&gt;The First Normal Form (1NF) is too restrictive. 
NF² allows attributes themselves to be relations. 
Attribute values can be sets.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;A&lt;/th&gt;
      &lt;th&gt;D&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;3&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;(Table 1: NF² and PNF)&lt;/p&gt;

&lt;p&gt;The construction of an algebra which has the same expressive strength as relational algebra is more possible, but more complicated and it employs the operators \(nest_{...}{(Relation)}\) and \(unnest_{...}{(Relation)}\).
Each of them is generally not commuative.&lt;/p&gt;

&lt;h2 id=&quot;pnf&quot;&gt;PNF&lt;/h2&gt;

&lt;p&gt;PNF is a subset of NF² with nicer properties. The construction of the algebra is easier.&lt;/p&gt;

&lt;p&gt;The special properties are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;In the partitioned normal form the nest operator is commutative!&lt;/li&gt;
  &lt;li&gt;The PNF can be unnested into a 1NF.&lt;/li&gt;
  &lt;li&gt;On every nesting layer there exists a flat key. (In table 1 the key is the attribute A)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The table above is also in PNF.&lt;/p&gt;

&lt;p&gt;More formally expressed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recursive definition of PNF&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A relation R has a set of unnested (atomic) attributes A. A is not the empty set.&lt;/li&gt;
  &lt;li&gt;The relation can also have nested (composite) attributes X. X can be the empty set.&lt;/li&gt;
  &lt;li&gt;There exists a functional dependency: A -&amp;gt; X&lt;/li&gt;
  &lt;li&gt;for every tuple in R:
    &lt;ul&gt;
      &lt;li&gt;for every complex attribute x in X:
        &lt;ul&gt;
          &lt;li&gt;value of the complex attribute t.x is in PNF again.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last point means, that we can construct a PNF from PNFs.&lt;/p&gt;

&lt;h2 id=&quot;nf-but-not-pnf&quot;&gt;NF² but not PNF?&lt;/h2&gt;

&lt;p&gt;Constructing a relation, which is not in PNF but in NF², can be achieved by breaking the recursive construction rules. The easiest is the “flat key” rule. If we change the values of the column A from (1,2,3) to (1,1,2) then we removed the total functional dependency between A and D.&lt;/p&gt;

&lt;p&gt;A -&amp;gt; D is now an incorrect statement, therefore the relation is not in PNF anymore. Due to the fact that we have not changed anything about the structure of the relation, it is still in NF².&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;A&lt;/th&gt;
      &lt;th&gt;D&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;A&lt;/td&gt;
      &lt;td&gt;B&lt;/td&gt;
      &lt;td&gt;C&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;(Table 2)&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/partitioned-normal-form&quot;&gt;Partitioned Normal Form&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on February 21, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Last timestep in masked sequence]]></title>
  <link>https://danielpollithy.github.io/keras/python/last-timestep-in-masked-sequence</link>
  <id>https://danielpollithy.github.io/keras/python/last-timestep-in-masked-sequence</id>
  <published>2020-01-26T00:00:00+01:00</published>
  <updated>2020-01-26T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;This is just a short piece of code which I have needed multiple times when training a LSTM with masked inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;: Seq2seq training with additional loss&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: How to get the last time step which is not masked&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why&lt;/strong&gt;: Calculating loss only at this timestep&lt;/p&gt;

&lt;h2 id=&quot;example-data&quot;&gt;Example data&lt;/h2&gt;

&lt;p&gt;The input batches are masked like with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;input = [ # mini-batch
	[ # 1st time series
    	[0.1, 0.00],
        [0.2, 0.01],
        [0.3, 0.01], # &amp;lt;--- we want this timestep
        [0.0, 0.0 ],
        [0.0, 0.0 ]
    ], 
	[ # 2nd time series
    	[0.5, 0.32], # &amp;lt;--- we want this timestep
        [0.0, 0.0 ],
        [0.0, 0.0 ],
        [0.0, 0.0 ],
        [0.0, 0.0 ]
    ], 
    ...
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The labels for the seq2seq training are the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt;s but shifted one time step.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;masking_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;point_dim&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# example: is 2 for (x,y) points 
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 1. Find entries which are equal to the masking_value 
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;equal_zero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masking_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 2. Count the zeros in the row
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros_per_row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;equal_zero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 3. Find the rows which only contain masking_values
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;correct_rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros_per_row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_dim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# (The following code is argmin which is forced to return the first occurence)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 4. Set the wrong rows to the maximum value (-&amp;gt; not selected by argmin)
#        (timesteps**2 is an upper bound for step 5)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrong_rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;correct_rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 5. Build enumerations for every track
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range_np&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# [0,1,2,3...]
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range_np_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range_np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;batch_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;range_keras&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;range_np_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# [
#   [0,1,2,3...],
#   [0,1,2,3...],
#   ...
# ]
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 6. Enumerate the correct values ascending + add the infinities of step 4
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search_space&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;correct_rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range_keras&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wrong_rows&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;last_timesteps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argmin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search_space&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 7. Build a mask for selection
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mask_last_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;one_hot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_timesteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dtype&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on_value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;off_value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;mask_last_step&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mask_last_step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 8. Use the mask for loss calc
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loss_per_track&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keras&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;losses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean_squared_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y_label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_hat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mask_last_step&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;loss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;loss_per_track&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;why-not-only-argmin&quot;&gt;Why not only argmin?&lt;/h2&gt;

&lt;p&gt;The tensorflow documentation for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tf.math.argmin&lt;/code&gt; &lt;a href=&quot;https://www.tensorflow.org/api_docs/python/tf/math/argmin&quot;&gt;(doc)&lt;/a&gt; states:&lt;/p&gt;

&lt;p&gt;“Note that in case of ties the identity of the return value is not guaranteed.”&lt;/p&gt;

&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range_np&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range_np_batch&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;range_keras&lt;/code&gt; should only be created once.&lt;/li&gt;
  &lt;li&gt;Insted of using the ultimate mask a solution with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tf.gather_scatter_nd&lt;/code&gt; is possible&lt;/li&gt;
  &lt;li&gt;The sum in step 2 could be replaced by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;K.all(K.equal(inp, mask_value), axis=-1)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/keras/python/last-timestep-in-masked-sequence&quot;&gt;Last timestep in masked sequence&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on January 26, 2020.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Generating Behavior for Vehicles]]></title>
  <link>https://danielpollithy.github.io/demo/Generating-Behaviour-for-Vehicles</link>
  <id>https://danielpollithy.github.io/demo/Generating-Behaviour-for-Vehicles</id>
  <published>2019-11-06T00:00:00+01:00</published>
  <updated>2019-11-06T00:00:00+01:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This post is a loose collection of JavaScript demos I made while studying for
the course “Generating Behavior for Vehicles”.&lt;/p&gt;

&lt;p&gt;The following two gifs show you how two of the demos work:&lt;/p&gt;

&lt;p&gt;**Planning a path through a city map with A star **&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/A_star.gif&quot; alt=&quot;A* A star&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A drifting car&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/dyn_track.gif&quot; alt=&quot;linearized dynamic one track&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;kinematic-one-track-model&quot;&gt;Kinematic One Track Model&lt;/h2&gt;

&lt;p&gt;A car is controlled by its steering angle \(\delta\) and its acceleration.
If we want a vehicle to perform any kind of maneuver then we have to relate
the input commands (steering and acceleration) with future positions of the car.&lt;/p&gt;

&lt;p&gt;For this purpose we use dead reckoning. In the following example we assume to
have a car with constant velocity. You can control its steering angle with the
slider below. It starts to drive once you change the steering angle a little bit.&lt;/p&gt;

&lt;p&gt;
  &lt;figure&gt;
    &lt;div class=&quot;videoWrapper&quot;&gt;
      &lt;div class=&quot;slidecontainer&quot;&gt;
        Steering angle: &lt;input type=&quot;range&quot; min=&quot;-0.5&quot; max=&quot;0.5&quot; value=&quot;0.1&quot; step=&quot;0.01&quot; id=&quot;myRange&quot; /&gt;
      &lt;/div&gt;

      &lt;canvas id=&quot;canvas&quot; width=&quot;800&quot; height=&quot;400&quot; style=&quot;border:1px solid #000000;&quot;&gt;&lt;/canvas&gt;      
    &lt;/div&gt;
  &lt;/figure&gt;
&lt;/p&gt;

&lt;script&gt;
let canvas = document.getElementById(&quot;canvas&quot;);
let ctx = canvas.getContext(&quot;2d&quot;);
let slider = document.getElementById('myRange');

let x = 250, y = 250, length = 20, width=length/2, theta = 0, dlt = -2, v = 1, angle=0.1, l=length;
let running = false;

slider.oninput = function() {
  angle = parseFloat(this.value);
  if (!running) {
    running = true;
    animate1();
  }
};

function animate1() {

  //clear
  // ctx.clearRect(0, 0, canvas.width, canvas.height);

  // forward euler
  x += v * Math.cos(theta);
  y += v * Math.sin(theta);
  theta += v * Math.tan(angle) / length;

  ctx.filter = 'opacity(0.1)';
  ctx.beginPath();
  drawCar(ctx, x, y, length, theta, width);

  requestAnimationFrame(animate1);
}

function drawCar(ctx, x1, y1, length, angle, width) {
  var x2 = x1 + length * Math.cos(angle),
  y2 = y1 + length * Math.sin(angle);

  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);

  ctx.lineWidth = width;
  ctx.stroke();

  return {x: x2, y: y2};
}
&lt;/script&gt;

&lt;p&gt;The model is called kinematic because we only model the geometry and not the
dynamics. This will be our next step.
It is called One-Track because we assume that the two wheels on both axis can
be modelled by averaged wheels in the center of both axis.&lt;/p&gt;

&lt;p&gt;The simple differential equations are:&lt;/p&gt;

\[\dot{x} = v \cdot \frac{\cos(\delta)}{l}\]

\[\dot{y} = v \cdot \frac{\sin(\delta)}{l}\]

\[\dot{\theta} = v \cdot \frac{\tan(\delta)}{l}\]

&lt;p&gt;Assuming constant inputs we use the Forward Euler to calculate the new state:&lt;/p&gt;

\[x = x + \Delta x\]

\[y = y + \Delta y\]

\[\theta = \theta + \Delta \theta\]

&lt;p&gt;This model is in general unrealistic because it assumes that the car can change
its direction instantaneously. But it works good enough as long as the velocity
of the car is low. Therefore we could use it to build a parking assistant.&lt;/p&gt;

&lt;h2 id=&quot;linearized-dynamic-one-track-model&quot;&gt;Linearized Dynamic One Track Model&lt;/h2&gt;

&lt;p&gt;Now we consider a car which is driving with a regular speed like 50 km/h. In this
model we accept that there can be a difference between the steering angle and the
real angle in which direction the mass of the vehicle moves.
Usually we want this discrepancy to be as low as possible because it is difficult
to control the car then. Think of a drifting car.&lt;/p&gt;

&lt;p&gt;In the following demo you can control the steering angle again (velocity is constant).
Because it is easy to loose control and leave the screen, the car will come back into
the screen if that happens.&lt;/p&gt;

&lt;p&gt;
  &lt;figure&gt;
    &lt;div class=&quot;videoWrapper&quot;&gt;
      &lt;div class=&quot;slidecontainer&quot;&gt;
        Steering angle: &lt;input type=&quot;range&quot; min=&quot;-0.3&quot; max=&quot;0.3&quot; value=&quot;0.0&quot; step=&quot;0.02&quot; id=&quot;myRange2&quot; /&gt;
      &lt;/div&gt;

      &lt;p id=&quot;info&quot; style=&quot;display: none&quot;&gt;&lt;/p&gt;

      &lt;canvas id=&quot;canvas2&quot; width=&quot;800&quot; height=&quot;400&quot; style=&quot;border:1px solid #000000;&quot;&gt;&lt;/canvas&gt;      
    &lt;/div&gt;
  &lt;/figure&gt;
&lt;/p&gt;

&lt;script&gt;

let canvas2 = document.getElementById(&quot;canvas2&quot;);
let ctx2 = canvas2.getContext(&quot;2d&quot;);
let slider2 = document.getElementById('myRange2');
let info = document.getElementById('info');

let x2 = 250,
    y2 = 250,
    length2 = 12,
    width2=length2/2,
    dlt2 = -2,
    l2=length2,
    t2=0,
    start_time = null;

let length_v = 6;
let length_h = 4;

let angle2=0.001; // lenkwinkel delta
let v2 = 10; // geschwindigkeit im Schwerpunkt
let psi = 0; // Fahrzeugausrichtung
let alpha_v = 0, alpha_h = 0; // Schräglaufwinkel vorne und hinten
let beta = 0; // Schwimmwinkel
let gierrate = 0; // r

let J = 2800; // Gierträgheit [kg m^2]
let m = 1550; // Masse [kg]
let c_v = 7; // 75000 Schräglaufsteifigkeit Vorderachse  [N/rad]
let c_h = 15; // 150000 Schräglaufsteifigkeit Hinterachse [N/rad]

let F_vq = 0, F_vl = 0, F_hq = 0, F_hl = 0;

let theta2 = 0; // Bewegungsrichtung des Schwerpunktes

let frame_width = canvas2.width,
    frame_height = canvas2.height;

let running2 = false;

slider2.oninput = function() {
  angle2 = parseFloat(this.value);

  if (!running2) {
    running2 = true;
    animate2();
  }
};


function animate2(timestamp) {

  if (!start_time) start_time = timestamp;
  let progress = timestamp - start_time;

  if (!angle2) angle2 = 0;

  info.innerText = &quot;delta=&quot; + angle2 + '\n';

  //clear
  // ctx2.clearRect(0, 0, canvas2.width, canvas2.height);

  // Schräglaufwinkel
  alpha_v = angle2 - Math.atan((length_v * gierrate + v2 * Math.sin(beta)) / v2 * Math.cos(beta));
  alpha_h = Math.atan( (length_h * gierrate - v2 * Math.sin(beta)) / v2 * Math.cos(beta));

  // Vernachlässigt man Windkräfte und Windmomente, so wirken als äußere Kräfte
  // die Achsseitenkräfte S v {\displaystyle S_{v}} S_{v} und S h {\displaystyle S_{h}} {\displaystyle S_{h}} auf das Fahrzeug ein.
  // Diese sind beim linearen Einspurmodell proportional zu den Schräglaufwinkeln.
  // Proportionalitätsfaktoren sind die Schräglaufsteifigkeiten c v {\displaystyle c_{v}} c_{v} und c h {\displaystyle c_{h}}
  // {\displaystyle c_{h}} der Achsen:
  F_vq = c_v * alpha_v;
  F_hq = c_h * alpha_h;

  info.innerText += 'F_vq='+F_vq + '\n';
  info.innerText += 'F_hq='+F_hq + '\n';


  // Annahme v const.
  F_vl = 0;
  F_hl = 0;

  // forward euler
  psi += gierrate;
  info.innerText += 'psi='+psi + '\n';

  gierrate += (F_vl * length_v * Math.sin(angle2) - F_hq * length_h + F_vq * length_v * Math.cos(angle2)) / J;
  info.innerText += 'gierrate='+gierrate + '\n';

  beta += -gierrate + ( F_vq * Math.cos(angle2-beta) + F_vl * Math.sin(angle2 - beta) + F_hq * Math.cos(beta) - F_hl * Math.sin(beta) ) / m * v2;
  info.innerText += 'beta='+beta + '\n';

  v2 += (-F_vq * Math.sin(angle2-beta) + F_vl * Math.cos(angle2 - beta) + F_hq * Math.sin(beta) + F_hl * Math.cos(beta) ) / m;
  info.innerText += 'v='+v2 + '\n';

  // Fortschreibung des Schwerpunktes und der Orientierung
  theta2 = psi + beta;
  info.innerText += 'theta='+theta2 + '\n';

  x2 += v2 * Math.cos(theta2);
  y2 += v2 * Math.sin(theta2);

  if (x2 &gt;= frame_width || y2 &gt;= frame_height) {
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
  }

  if (x2 &lt; 0) {
    x2 += frame_width;
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
  }

  if (y2 &lt; 0) {
    y2 += frame_height;
    ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
  }

  x2 %= frame_width;
  y2 %= frame_height;


  ctx2.filter = 'opacity(0.8)';
  ctx2.beginPath();
  drawCar2(ctx2, x2, y2, length, psi, width);

   setTimeout(function() {
     requestAnimationFrame(animate2);
   }, 100);

}

function drawCar2(ctx, x1, y1, length, angle, width) {

  var x2 = x1 + length * Math.cos(angle),
    y2 = y1 + length * Math.sin(angle);

  ctx.beginPath();
  ctx.strokeStyle = &quot;#FF0000&quot;;
  ctx.arc(x1, y1, length/10, 0, Math.PI * 2, true);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);

  ctx.strokeStyle = &quot;#000000&quot;;
  ctx.lineWidth = width;
  ctx.stroke();

  return {x: x2, y: y2};
}

&lt;/script&gt;

&lt;p&gt;This linearized dynamic one track model can be used in ESP systems to estimate
the yaw rate of the car. If it is higher than the driver might expect it then
it is becoming dangerous because the control over the car can be lost easily.
Starting from this the ESP regulator can break tires or accelerate others to
reduce the yaw rate to keep the car controllable.&lt;/p&gt;

&lt;p&gt;ToDo: Add equations for dynamic one track model and show how to linearize&lt;/p&gt;

&lt;h2 id=&quot;planning&quot;&gt;Planning&lt;/h2&gt;

&lt;p&gt;We want our car to perform a maneuver. But what should it actually do?
Let’s think about the scenario when a car wants to drive from one point in a
city to another point. We assume that we have an HD (high definition) city map
and we want to plan an optimal path.&lt;/p&gt;

&lt;p&gt;First we should discretize the world to make the planning feasible and assume
that the robot is a point:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;building a Voronoi graph around the obstacles&lt;/li&gt;
  &lt;li&gt;polygon fitting into the free room&lt;/li&gt;
  &lt;li&gt;Growing a tree structure into the space (Quad/Octree, something like
Rapidly Exploring Random Trees, although they already search)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we convert the problem into a graph search with Dijkstra or A&lt;em&gt;.
This results in a trajectory.
In the following demo every pixel is a node in the graph. You can click on the
left canvas to draw obstacles (black). The robot starts in the left upper position
and wants to drive to the right lower corner. It will search for the shortest path with A&lt;/em&gt;.
All the expanded pixels are colored in blue.&lt;/p&gt;

&lt;p&gt;
  &lt;figure&gt;
    &lt;div class=&quot;videoWrapper&quot;&gt;
      &lt;p&gt;Left canvas: Map input. Right canvas: A* visualization&lt;/p&gt;
      &lt;canvas id=&quot;canvas_map&quot; width=&quot;200&quot; height=&quot;200&quot; style=&quot;border:1px solid #000000;&quot;&gt;&lt;/canvas&gt;
      &lt;canvas id=&quot;canvas3&quot; width=&quot;200&quot; height=&quot;200&quot; style=&quot;border:1px solid #000000;&quot;&gt;&lt;/canvas&gt;   
      &lt;br /&gt;
      &lt;button id=&quot;map_done&quot;&gt;Start planning!&lt;/button&gt;
      &lt;button id=&quot;map_clear&quot;&gt;Clear map&lt;/button&gt;
    &lt;/div&gt;
  &lt;/figure&gt;
&lt;/p&gt;

&lt;script&gt;

let canvas_map = document.getElementById(&quot;canvas_map&quot;);
let canvas3 = document.getElementById(&quot;canvas3&quot;);
let ctx_map = canvas_map.getContext(&quot;2d&quot;);
let ctx3 = canvas3.getContext(&quot;2d&quot;);

let btn_done = document.getElementById('map_done');
let btn_clear = document.getElementById('map_clear');

let frame_width2 = canvas3.width, frame_height2 = canvas3.height;
let rect_size = 50;

let car_x = 0, car_y = 0, car_theta = 0;
let target_x = frame_width2, target_y = frame_height2;

let map = null;


function getMousePos(canvas, evt) {
    var rect = canvas.getBoundingClientRect();
    return {
        x: evt.clientX - rect.left,
        y: evt.clientY - rect.top
    };
}

window.addEventListener('load', function(){  
  console.log(&quot;load&quot;)
  $(&quot;#canvas_map&quot;).mousedown(function(e){
    var mousePos = getMousePos(canvas_map, e);



    let mouseX = mousePos.x;
    let mouseY = mousePos.y;

    let x = mouseX - rect_size/2 - 1,
        y = mouseY - rect_size/2 - 1;

    ctx_map.fillRect(x, y, rect_size, rect_size);
  });
});


btn_done.addEventListener('click', (event =&gt; {
  console.log(&quot;start planning&quot;);

  map = ctx_map.getImageData(0, 0, frame_width2, frame_height2).data;
  map = map.filter(function(value, index, Arr) {
    return (index+1) % 4 === 0;
  });

  ctx3.drawImage(canvas_map, 0, 0);

  plan_path();
}));

btn_clear.addEventListener('click', (event =&gt; {
  console.log(&quot;btn_clear&quot;);

  ctx3.clearRect(0, 0, canvas3.width, canvas3.height);
  ctx_map.clearRect(0, 0, canvas3.width, canvas3.height);
}));

function is_empty(x, y) {
  return map[coord_to_pos(x,y)] === 0;
}

function pos_is_empty(pos) {
  return map[pos] === 0;
}

function argMin(array) {
  return array.map((x, i) =&gt; [x, i]).reduce((r, a) =&gt; (a[0] &lt; r[0] ? a : r))[1];
}

function coord_to_pos(x,y) {
  // checks map
  if (x &gt; frame_width2 || y &gt; frame_height2) {
    throw Error(&quot;pos unknown&quot;);
  }
  return  y * frame_width2 + x;
}

function pos_to_coord(pos) {
  let y = Math.floor(pos / frame_width2);
  let x = pos - y*frame_width2;
  return [x, y];
}

function get_neighbours(x,y) {
  let n = [];
  if (x &gt; 0 &amp;&amp; is_empty(x-1, y)) {
    n.push(coord_to_pos(x-1, y));
  }
  if (x&lt;frame_width2 &amp;&amp; is_empty(x+1, y)) {
    n.push(coord_to_pos(x+1, y));
  }
  if (y &gt; 0 &amp;&amp; is_empty(x, y-1)) {
    n.push(coord_to_pos(x, y-1));
  }
  if (y &lt; frame_height2 &amp;&amp; is_empty(x, y+1)) {
    n.push(coord_to_pos(x, y+1));
  }
  return n;
}

function heuristic(pos) {
  let [x, y] = pos_to_coord(pos);
  return Math.sqrt( (x-frame_width2-1) ** 2 + (y - frame_height2) ** 2);
}

function plan_path() {
  // every pixel is a possible state
  // target is bottom right
  // origin is (0,0)

  let iterations = 0;

  let goal_expanded = false;
  let current_state = coord_to_pos(0,0);
  let cost_to_state = Array(frame_width2 * frame_height2).fill(Infinity);
  // value for candidate selection fused with expansion state
  let cost_to_select = Array(frame_width2 * frame_height2).fill(Infinity);
  let expanded_states = Array(frame_width2 * frame_height2).fill(false);
  let backpointers = Array(frame_width2 * frame_height2).fill(-1);

  // start
  cost_to_state[0] = 0;
  expanded_states[0] = true;

  function visualize_solution() {
    let state = coord_to_pos(frame_width2-1, frame_height2-1);
    while (state !== 0) {
      ctx3.fillStyle = &quot;#ff0000&quot;;
      ctx3.fillRect(pos_to_coord(state)[0], pos_to_coord(state)[1], 1, 1);
      state = backpointers[state];
    }
  }

  function search() {
    iterations++;

    expanded_states[current_state] = true;
    cost_to_select[current_state] = Infinity;

    ctx3.fillStyle = &quot;#00d8ff&quot;;
    ctx3.fillRect(pos_to_coord(current_state)[0], pos_to_coord(current_state)[1], 1, 1);
    goal_expanded = (current_state === coord_to_pos(frame_width2-1, frame_height2-1));

    // get neighbours
    let [current_x, current_y] = pos_to_coord(current_state);
    let neighbours = get_neighbours(current_x, current_y);

    // update cost to neighbours which were not expanded yet
    for (let i=0; i&lt;neighbours.length; i++) {
      // if state not expanded yet
      if (!expanded_states[neighbours[i]]) {
        // if cost to state lower, then overwrite
        if (cost_to_state[neighbours[i]] &gt; cost_to_state[current_state] + 1) {
          cost_to_state[neighbours[i]] = cost_to_state[current_state] + 1;
          cost_to_select[neighbours[i]] = cost_to_state[current_state] + 1 + heuristic(neighbours[i]);
          backpointers[neighbours[i]] = current_state;
        }
      }
    }

    // pick next state to expand
    if (!goal_expanded) {
      current_state = argMin(cost_to_select);
      if (current_state === Infinity) {
        alert(&quot;no solution found&quot;);
      }

      setTimeout(search, 1);
    } else {
      setTimeout(visualize_solution, 10);
    }
  }


  search();
}

&lt;/script&gt;

&lt;h2 id=&quot;optimal-control&quot;&gt;Optimal control&lt;/h2&gt;

&lt;p&gt;Given the trajectory from the last step, how do we get the steering angle and
acceleration necessary to drive it?&lt;/p&gt;

&lt;p&gt;One option would have been to plan in a Markov Decision Process. Instead of assuming
a point robot we could frame it as follows:&lt;/p&gt;

&lt;p&gt;Our car is in an initial state (steering angle, acceleration, position).
It can take actions (steer and accelerate) which leads to different states.
The different actions (lets assume they are discrete) lead to new states which
we calculate using the motion model from before.&lt;/p&gt;

&lt;p&gt;The different action values determine the branching factor of our state tree.
Using the Bellman optimality equation we could iterate backwards starting at the
goal in order to determine the “goodness” of each state at different time steps.
Once the “goodness” has converged (the order of the values doesn’t change anymore
or the values of the values either) we can greedily search through the graph
in order to maximize the “goodness” at every time step.&lt;/p&gt;

&lt;p&gt;This is called value iteration. Actually Dijkstra and A* are also based on the
Bellman Recursion but the time index is replaced by the sorting index of the
next expansion candidate. Dijkstra sorts by cost-so-far and A* by cost-so-far
plus cost-to-go (a heuristic which has to be admissible, which means that it
underestimates the real cost-to-go).&lt;/p&gt;

&lt;p&gt;The problem with this discrete approach is that it would happily jump between
accelerations and steering angles although in reality these values are continuous.&lt;/p&gt;

&lt;p&gt;No matter where our target trajectory comes from and the controls for that we
somehow have to “smoothen” them. We want to optimize them. Imagine the trajectory
makes an abrupt  corner. To directly follow it we would have to stop at the corner
turn the wheels and accelerate again.
We note that there is a trade off between following the trajectory and following
the control inputs.&lt;/p&gt;

&lt;p&gt;Finding the optimal solution depends on what we want. We can formulate a cost
functional (a functional is a function of functions) which penalizes both deviations
of the trajectory and the input controls.
According to our needs we add weightings to the parts to balance it or stress
that we have to reach the target.&lt;/p&gt;

&lt;p&gt;The cost functional look as follows:&lt;/p&gt;

\[J = x^T(k_f) Q_f x(k_f) + \sum_{k=1}^{k_{f}-1} x^T(k) Q_f x(k) + \sum_{k=0}^{k_{f}-1} u^T(k) R_f u(k)\]

&lt;p&gt;\(Q_f\) is the weighting of the final state deviation. \(Q\) is the weighting of the state deviation.
\(R\) is the weighting of the control input deviation.&lt;/p&gt;

&lt;p&gt;We can solve this problem by applying the Bellman Recursion Formula backwards.
But this time the amount of control values and state values is infinite because
we are in a continuous domain.
The cost functional between two time steps is a quadratic equation dependent on a
weighting matrix P. We differentiate and solve for P which gives us the optimal
P(k) for the time step k. We repeat this process until we reach the beginning.
The formula to calculate P(k) is a Riccati difference equation which can be solved analytically.&lt;/p&gt;

&lt;p&gt;Using P(k) we can calculate the optimal Gain matrix K* which we use to calculate the
optimal control input u&lt;em&gt;(k) = -K&lt;/em&gt;(k) x(k) for every time step.&lt;/p&gt;

&lt;p&gt;If we don’t have a fixed target at time \(k_f\) and our system is controllable
and the system is time invariant (really?) then we can find an optimal P(k) which
is optimal for all time steps. We call is \(P_{\infty}\) and obtain it by solving
the riccati differences equation until convergence. This leads to a time independent
optimal control u* = -K* x(t) which is the LQR (linear quadratic regulator).
As opposed to the classical creation of a regulator by determining eigenvalues,
the advantages of the LQR are intuitive weighting with Q/R and no additional
unwanted degrees of freedom.&lt;/p&gt;

&lt;p&gt;ToDo: Clean this up and add the formulas.&lt;/p&gt;

&lt;p&gt;Unfortunately I don’t have JavaScript example for this because I could not find
a nice matrix package which helps me, therefore I will show some python code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/riccati.png&quot; alt=&quot;riccati&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build_batch_matrices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# Batch Matrices
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matrix_power&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# build row
&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matrix_power&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build_batch_cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# build row
&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;row_q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;row_r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k2&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row_q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row_r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row_q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;row_r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row_q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row_r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build_H_F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;H_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;F_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;H_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_batch&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# how many time steps
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# target trajectory
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# different values for y are more interesting
# y = np.sin(x)
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;kappa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# x(k+1) = A x(k) + B u(k)
# u(k) = [u, u]
&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Riccati
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Q_f = P(k_f)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q_f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#  Q
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;#  R
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Ps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q_f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Ks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Loese Riccati-Differenzengleichung rückwärts
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;reversed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;P_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;K_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pinv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;P_kp1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;Ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;P_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;Ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;K_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Ps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Ks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Optimale Stellgroesse u(k) = -K(k) * x(k)
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# state space
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
   &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# d
&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# delta_psi
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# euclidean
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X_world&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# -------------------------
# The following lines contain a naive regulator which does not work as good
# as the riccati regulator
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;us&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;u_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;u_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


   &lt;span class=&quot;c1&quot;&gt;# next time step
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;x_p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_k&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# normalize delta_psi
&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# x_p[1] = ((x_p[1] + np.pi ) % 2*np.pi) - np.pi   
&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# print(x_traj[k].copy())
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;x_world&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;x_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;x_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;X_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_world&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;x_n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_world&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# x_n += np.random.normal(0, 0.01) # add some randomness
&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# end of suboptimal regulator
# ----------------------------
&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build_batch_matrices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;us&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;us&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;x_batch_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# u.T H u + 2 x_0.T F u
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build_batch_cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;H_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;build_H_F&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Q_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;u_opt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;H_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;F_batch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;x_opt_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B_batch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u_opt&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_batch_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[:,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Suboptimal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_opt_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[:,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Optimal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;legend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;geometric-modeling-of-a-trailer&quot;&gt;Geometric modeling of a trailer&lt;/h2&gt;

&lt;p&gt;The following simulation models a car with an attached trailer. This is a differential
equation grounded on geometric considerations.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/trailer.png&quot; alt=&quot;trailer&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.patches&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patches&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# variables
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# steering angle
&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# constants
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;car_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;car_width&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;trailer_length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;distance_car_trailer_axis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;x_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plot_dt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;# differential equations
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;forward_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;psi_dot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;car_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;v_dot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;gamma_dot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distance_car_trailer_axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi_dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v_dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delta_t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gamma_dot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calc_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;calc_trailer_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance_car_trailer_axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance_car_trailer_axis&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# psi, v, gamma
&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# x, y
&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance_car_trailer_axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timesteps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;forward_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calc_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;calc_trailer_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;fig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subplots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot_dt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;x_vec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;y_vec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;car_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;car_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

   &lt;span class=&quot;c1&quot;&gt;# deichsel
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_vec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'k-'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;c1&quot;&gt;# car
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;car_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;car_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;car_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;car_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;car_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;psi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;car_length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;linewidth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;c1&quot;&gt;# trailer
&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;ax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trailer_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;trailer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state_traj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;axis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;equal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# plt.legend()
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;grid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/demo/Generating-Behaviour-for-Vehicles&quot;&gt;Generating Behavior for Vehicles&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on November 06, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Localization of mobile agents]]></title>
  <link>https://danielpollithy.github.io/python/localization/Localisation-of-mobile-agents</link>
  <id>https://danielpollithy.github.io/python/localization/Localisation-of-mobile-agents</id>
  <published>2019-09-23T00:00:00+02:00</published>
  <updated>2019-09-23T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;In this post I am going to try to explain the basic concepts of localization
of mobile agents which I have learned in the lecture “Lokalisierung mobiler Agenten”
at the KIT.&lt;/p&gt;

&lt;p&gt;The main outline:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Wheel and vehicles (one lane kinematic model and differential model)&lt;/li&gt;
  &lt;li&gt;Systems and discretization&lt;/li&gt;
  &lt;li&gt;Euler method&lt;/li&gt;
  &lt;li&gt;Dead reckoning&lt;/li&gt;
  &lt;li&gt;Example: Error accumulating with constant velocity model&lt;/li&gt;
  &lt;li&gt;Static localization (measurements, objective function and least squares)&lt;/li&gt;
  &lt;li&gt;Angular measurements (atan2)&lt;/li&gt;
  &lt;li&gt;Distance measurements (linearizing)&lt;/li&gt;
  &lt;li&gt;Example: GPS&lt;/li&gt;
  &lt;li&gt;Recursive Least Squares&lt;/li&gt;
  &lt;li&gt;Bayesian Filtering Framework (Linear Gaussian Model)&lt;/li&gt;
  &lt;li&gt;Dynamic localization (fusioning principles: BLUE, naive fusion, recursive fusion)&lt;/li&gt;
  &lt;li&gt;Kalman Filter (derivation, optimality)&lt;/li&gt;
  &lt;li&gt;Example: Tracking Car position and velocity&lt;/li&gt;
  &lt;li&gt;Nonlinear Filtering (EKF, UKF, Particle Filter)&lt;/li&gt;
  &lt;li&gt;EKF&lt;/li&gt;
  &lt;li&gt;Wonham Filter&lt;/li&gt;
  &lt;li&gt;Bingham Quaternion Filter&lt;/li&gt;
  &lt;li&gt;SLAM&lt;/li&gt;
  &lt;li&gt;Online SLAM (EKF-SLAM)&lt;/li&gt;
  &lt;li&gt;Full SLAM (Graph-SLAM)&lt;/li&gt;
  &lt;li&gt;Example: EKF-SLAM for 3d pose&lt;/li&gt;
  &lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;localization-of-mobile-agents&quot;&gt;Localization of Mobile Agents&lt;/h2&gt;

&lt;h3 id=&quot;wheel-and-vehicles&quot;&gt;Wheel and vehicles&lt;/h3&gt;

&lt;p&gt;As we don’t want to spend too much time on modeling forces and we assume that
our mobile agents drive with moderate velocity on wheels we use the idealized
wheel.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It has a radius r, a wheel velocity \(\omega\),&lt;/li&gt;
  &lt;li&gt;no slip in lateral direction&lt;/li&gt;
  &lt;li&gt;no slip in longitudinal direction.&lt;/li&gt;
  &lt;li&gt;It has point contact to the ground and&lt;/li&gt;
  &lt;li&gt;only rolls into the direction of the steering angle&lt;/li&gt;
  &lt;li&gt;it has no roll resistance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Instantaneous Center of Rotation (ICR, “Momentanpool”) is the point where
the wheel axis intersect. There are four different cases with our model:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The axes meet at a point inside our outside of the vehicle and move on a
circular path around the ICR.&lt;/li&gt;
  &lt;li&gt;The wheel axes are on the same line. This is the case for the differential drive.
The position of the ICR is controlled by the difference of the wheel velocities.
If their difference is zero then ICR lays between the wheels.&lt;/li&gt;
  &lt;li&gt;If wheel axes are parallel then the ICR is located at infinite distance. The
vehicle is driving forward without a curved path.&lt;/li&gt;
  &lt;li&gt;The wheel axes do not intersect at a single point. Within our model the vehicle
is unable to move. Other models can handle this but they are a little bit more complex.
For example: The dynamic one track model which models the slip angles of the wheels.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The magnitude form of the euler velocity equation (“Betragsform der eulerschen Geschwindigkeitsgleichung”)
is used to set the angular velocity and the vehicle velocity into relation.&lt;/p&gt;

\[|\omega| = \frac{||v||}{||p||}\]

&lt;p&gt;where \(\omega\) is the angular velocity, v the vehicle velocity at a point at the vehicle
and p the line from the ICR to the point.&lt;/p&gt;

&lt;p&gt;For two different points p1 and p2 on the vehicle with different velocities v1 and v2, we can also use:&lt;/p&gt;

\[|\omega| = \frac{||v2 - v1 ||}{||p2 - p1||}\]

&lt;h4 id=&quot;kinematic-one-track-model&quot;&gt;Kinematic one track model&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_1.jpg&quot; alt=&quot;lma_1.jpg&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;differential-drive&quot;&gt;Differential drive&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_2.jpg&quot; alt=&quot;lma_2.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note: If \(v_L + v_R = 0\) the ICR is at the center of the axis between the
two wheels.&lt;/p&gt;

&lt;h3 id=&quot;systems&quot;&gt;Systems&lt;/h3&gt;

&lt;p&gt;Let \(x\) be the state of the system, \(u\) the controllable inputs and \(w\) the uncontrollable changes to the state (like noise).
The system equation \(a(x, \dot{x}, u, w) = 0\) holds. A simple specialization of this
equation which we are going to use: \(\dot{x} = a(x, u, w)\)&lt;/p&gt;

&lt;p&gt;If we manage to design \(a(...)\) in form a linear function then we can write our system
in the following form and call it a Linear System:&lt;/p&gt;

\[\dot{x}(k) = A_k x(k) + B_k u(k) + w_k\]

\[y(k) = C_k x(k) + D_k u(k)\]

&lt;p&gt;In the case that the system’s behavior does not change over time, we call it
a &lt;strong&gt;Linear Time-invariant System&lt;/strong&gt; (LTI):&lt;/p&gt;

\[\dot{x}(k) = A x(k) + B u(k) + w\]

\[y(k) = C x(k) + D u(k)\]

&lt;p&gt;In order to access the state of the system at a point in time \(t\) we can use the
the solution for the time-continuous linear time-invariant system:&lt;/p&gt;

\[x(t) = e^{A (t - t_0)} x_0 + \int_{t_0}^{t}{e^{A (t-\tau)} B u(\tau) d\tau }\]

&lt;h3 id=&quot;discretization&quot;&gt;Discretization&lt;/h3&gt;

&lt;p&gt;Computers generally do not know how to solve time-continuous differential equations.
The main problem is “how to solve the integral”? It is also difficult for humans
if the antiderivative cannot be calculated.&lt;/p&gt;

&lt;p&gt;For the use in digital computers we have to discretize the with respect to time,
only then can we use it together with the discrete state sampling rate.
So we introduce discrete timesteps \(t_k = k \cdot T_s, k \in  \mathbf{Z}^+\).&lt;/p&gt;

&lt;p&gt;Now we assume that the input signal is constant between two timesteps:&lt;/p&gt;

\[x(t_{k+1}) = e^{A T_s} x(t_k) + \int_{0}^{T_s}{e^{A (T_s - \tau)} B d\tau \cdot u(t_k) }\]

&lt;p&gt;Because the system is time-invariant we see that everything expect the x(t) and u(t) is constant, which leads us to the following discrete form:&lt;/p&gt;

\[x(t_{k+1}) = A' x(t_k) \cdot B' u(t_k)\]

&lt;p&gt;So we still have an integral here. How do we get A’ and B’?&lt;/p&gt;

&lt;p&gt;With the use of the Laplace transformation if possible or numerical approximations.&lt;/p&gt;

&lt;h4 id=&quot;euler-method&quot;&gt;Euler method&lt;/h4&gt;

&lt;p&gt;Given a differential equation which describes the system dynamics we want to
calculate the state of the system after time t.&lt;/p&gt;

\[x(t) = x_0 + \int_0^t{\dot{x}(\tau) d\tau}\]

&lt;p&gt;We use the Euler Method. It tries to fit small rectangles under the curve of
which we want to calculate the integral. If we use the height of the function
at timestep \(t_k\) as the height of the rectangle we call it &lt;strong&gt;Forward/explicit euler&lt;/strong&gt;.
If the we use the height at \(x_{k+1}\) then it’s called &lt;strong&gt;Backward euler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The backward euler is a little bit extra effort because you have to solve an
equation to get to the next state but it has the advantage of being stable (solution can
  be found with the Newton method).&lt;/p&gt;

&lt;p&gt;Instead of using the quotient of differentials we have to use the &lt;strong&gt;difference quotient&lt;/strong&gt;.&lt;/p&gt;

\[\frac{d x(t)}{dt}\approx \frac{x(t + T_s) - x(t)}{T_s} = \frac{x_{k+1} - x_k}{T_s}\]

&lt;p&gt;In Matlab a continuous system can be transformed numerically with the command c2d:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sys_disc = c2d(sys_cont,Ts)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Until rounding errors happen in the computer, a smaller \(T_s\) leads to a
better approximation.&lt;/p&gt;

&lt;h4 id=&quot;solution-3&quot;&gt;Solution 3&lt;/h4&gt;

&lt;p&gt;Constant acceleration or constant velocity models.&lt;/p&gt;

&lt;h3 id=&quot;dead-reckoning&quot;&gt;Dead reckoning&lt;/h3&gt;

&lt;p&gt;Definition:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The task of dead reckoning is to get the pose of an object with respect to an
external coordinate system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To solve this task formulate a motion model in the object’s coordinate system.&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;High sampling rate&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;No infrastructure&lt;/strong&gt; needed&lt;/li&gt;
  &lt;li&gt;low latency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pose is only relative&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Accumulated error&lt;/strong&gt; which leads to drift&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How it works:
We measure &lt;strong&gt;increments&lt;/strong&gt; from the last state (change of place, velocity or acceleration).
And then we use this measured information as system input to our discrete system
model in order to calculate where our current position should be next.&lt;/p&gt;

&lt;p&gt;“Schritthaltend”: Abtastrate höher als Rechenzeit für neuen Zustand.&lt;/p&gt;

&lt;h4 id=&quot;error&quot;&gt;Error&lt;/h4&gt;

&lt;p&gt;The total error of a linear system depends on all noise vectors:&lt;/p&gt;

\[e_k = x_k - x_{k}^{\text{ground truth}} = e_k (w_{k-1}, ..., w_0)\]

&lt;p&gt;&lt;strong&gt;For linear systems: The longer ago the error has been added, the more influence
it has, because the exponentiated system matrix usually becomes larger over time&lt;/strong&gt;:&lt;/p&gt;

\[e_k = A^{k-1}\cdot w_0 + A^{k-2}\cdot w_1 + ... + A\cdot w_{k-1}\]

&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;: When talking about the error it is important to realize that
  the error is not the difference between the estimate and the measurement but
  it is the difference between the ground truth and the estimate!&lt;/p&gt;

&lt;p&gt;(The ground truth could be manually annotated or retrieved with another system,
  for example with a VICON or GPS)&lt;/p&gt;

&lt;h3 id=&quot;static-localization&quot;&gt;Static localization&lt;/h3&gt;

&lt;p&gt;Sensors measure absolute pose in world coordinates.&lt;/p&gt;

&lt;p&gt;Advantage&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;No increasing error (“keine Fehlerfortpflanzung”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantage&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;External infrastructure necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Measurement principles&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Time-of-Flight&lt;/li&gt;
  &lt;li&gt;Radar&lt;/li&gt;
  &lt;li&gt;visual (cameras)&lt;/li&gt;
  &lt;li&gt;strength of a signal (WLAN, Bluetooth, GSM)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The measurement function z = h(x) generates a measurement from the true pose of the robot.&lt;/p&gt;

\[z \in R^M , x \in R^N, M &amp;gt;= N\]

&lt;h4 id=&quot;example-1-trilateration&quot;&gt;Example 1: Trilateration&lt;/h4&gt;

&lt;p&gt;You want to localize the robot by measuring the distance to point landmarks.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_3.jpg&quot; alt=&quot;lma_3&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The ith measurement is the distance to the point i (with coordinates p_x and p_y).
The robot’s position is x_x, x_y.&lt;/p&gt;

\[z_i = \sqrt{ (x_x - p_x)^2 + (x_y - p_y)^2 } = || p - x ||\]

&lt;p&gt;ToDo: Linearize!&lt;/p&gt;

&lt;p&gt;The vector z contains the measurements to all the landmarks: \(z = [z_1, ..., z_M]^T\)
And we assume that the measurement function h(x) produced this vector \(z = [h_1(x), ..., h_M(x)]\).&lt;/p&gt;

&lt;p&gt;This leads us to a non-linear least squares (LSQ) problem with the objective function and the weighting matrix W (pos. definite):&lt;/p&gt;

\[arg_x min G(x) = ||z - h(x)||^2_W = (z - h(x))^T  W^{-1} (z - h(x))\]

&lt;p&gt;The weighting matrix allows us to express our knowledge about the measurements. Whether we want to trust
the measurement of one sensor more than others.&lt;/p&gt;

&lt;p&gt;Once we solve this optimization problem we will localize the robot. If we cannot write the measurement
function as a linear equation then we could do this numerically.&lt;/p&gt;

&lt;p&gt;If we can write the function as a linear equation then we can solve the problem analytically by deriving it, setting the
derivation to zero and solving for x. (If we do not knew the orientation of the parabola then we would also have to check
whether the optimum is a minimum or a maximum by checking the sign of the second derivation).&lt;/p&gt;

&lt;h4 id=&quot;example-2-trilateration-with-walls&quot;&gt;Example 2: Trilateration with walls&lt;/h4&gt;

&lt;p&gt;Let’s go back to the example and see whether we can reformulate the measurement function.
Let’s assume that the landmarks are points on walls of a room.&lt;/p&gt;

&lt;p&gt;In this case we can model the walls with Hesse’sche Normalform
\(n_i * x + d_i = 0\)  with \(||n_i||^2 = 1\) and \(d_i\) the distance to the wall.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_4.jpg&quot; alt=&quot;lma_4&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The distance to the ith wall is \(s_i(x) = h_i * x + d_i\)&lt;/p&gt;

\[s_i(x) - d_i = h_i * x\]

\[z_i = h_i * x\]

\[z_i = [h_{i_x}, h_{i_y}] * [x y]^T\]

&lt;p&gt;Which is a linear equation.&lt;/p&gt;

&lt;p&gt;In the easiest case where we have exactly as many observations as state variables we obtain a quadratic measurement matrix:&lt;/p&gt;

\[[z_0, z_1] = [h_{0_x}, h_{0_y}; h_{1_x}, h_{1_y}] * [x y]^T\]

\[z = H x\]

&lt;p&gt;=&amp;gt; \(x = H^{-1} z\)&lt;/p&gt;

&lt;p&gt;We see that it would be convenient to always use a quadratic measurement matrix H but it has the downside
that we would not use all of our measurements if we have more walls in the room and therefore we would be more
error prone if one of the sensors returns a noisy value.&lt;/p&gt;

&lt;h3 id=&quot;least-squares&quot;&gt;Least Squares&lt;/h3&gt;

&lt;p&gt;That’s why we come back to the LSQ which minimizes the sum of the squared errors between our measurements and the estimated state.&lt;/p&gt;

\[arg_x min G(x) = ||z - H x||^2_W = (z - Hx)^T  W^{-1} (z - Hx)\]

&lt;p&gt;Multiplying the terms:&lt;/p&gt;

\[G(x) = (z - Hx)^T  W^{-1} (z - Hx) = z\]

\[z^T W^{-1} z    -    x^T H^T W^{-1} z    -   z^T W^{-1}Hx   +   x^T H^T W^{-1} H x\]

&lt;p&gt;Derive:&lt;/p&gt;

\[\frac{d }{d x} G(x) = - H^T W^{-1} z - z^T W^{-1}H + 2 H^T W^{-1} H x\]

&lt;p&gt;Set to zero:&lt;/p&gt;

\[-2 H^T W^{-1} z + 2 H^T W^{-1} H x = 0\]

\[+ 2 H^T W^{-1} H x = +2 H^T W^{-1} z\]

\[H^T W^{-1} H x = H^T W^{-1} z\]

\[x = (H^T W^{-1} H)^{-1} H^T W^{-1} z\]

&lt;p&gt;Checking the second derivative:&lt;/p&gt;

\[\frac{d }{d x} -2 H^T W^{-1} z + 2 H^T W^{-1} H x z\]

\[2 H^T W^{-1} H z\]

&lt;p&gt;Check whether it is positive definite:&lt;/p&gt;

\[2 H^T W^{-1} H z &amp;gt; 0\]

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; H has to have at least full column rank otherwise the first bracket
   could not be inverted. This means that the columns have to be linearly independent
   of each others. Full column rank is the same as saying that rank(H) = dim(x) which
   enough to make rank(H) &amp;gt;= dim(x) true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If the weight matrix W is only semi-definite then the matrix \((H^T W^{-1} H)\)
  then the inversion is not uniquely determined (infinite solutions). We can still
  choose one by picking the with the smallest norm ||x||^2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to choose W?&lt;/strong&gt; Diagonal matrix, positive definite. A large entry on the diagonal
  like 999 becomes 1/999 after inverting the matrix. And the multiplication with
  such a small value nearly cancels its influence onto \(\hat{x}\).
  Therefore: &lt;strong&gt;Large values&lt;/strong&gt; in W result in &lt;strong&gt;mistrust&lt;/strong&gt; for the related sensor value.&lt;/p&gt;

&lt;h4 id=&quot;example-3-triangulation&quot;&gt;Example 3: Triangulation&lt;/h4&gt;

&lt;p&gt;If we can’t measure the distance to known landmark there might be the possibility
to measure the angle.&lt;/p&gt;

&lt;p&gt;The measurement equation:&lt;/p&gt;

\[\alpha_i = atan2(y_{LM}^i - y, x_{LM}^i - x) - \psi\]

&lt;p&gt;is not linear.&lt;/p&gt;

&lt;p&gt;A quick reminder. The tan(x) looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_5.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Which is undefined at 90 degree because it is sin(90) / cos(90) and cos(90) is zero.&lt;/p&gt;

&lt;p&gt;The atan2 is defined as the angle between the x axis in the range between ]-pi, pi]:&lt;/p&gt;

&lt;p&gt;It resolves the ambiguity that -90 degree is the same as 270 degree.&lt;/p&gt;

&lt;h3 id=&quot;recursive-least-squares&quot;&gt;Recursive Least Squares&lt;/h3&gt;

&lt;p&gt;The normal least squares method has the downside of processing all measurements in one
matrix. In reality the measurements are obtained incrementally and we do not want to
repeat the processing of the measurement matrix again and again.
Especially when it is becoming larger and larger.&lt;/p&gt;

&lt;p&gt;The recursive least squares fusions the last result with the newly obtained measurement.
The measurement matrix’s size stays constant and therefore the processing time.&lt;/p&gt;

&lt;p&gt;We are now going to work with batch matrices. They are matrices whose entries
are matrices themselves.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_6.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It is important that the block weight matrix W is a diagonal matrix. If that is not
the case then we have to diagonalize it: \(W = V^T D V\).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; \(C_k\) can be calculated independently if H and W are independent of
  the measurements. With this in mind we see that with \(k to \infty: C_k\) ~= 0&lt;/p&gt;

&lt;p&gt;We obtain recursive equations which we can solve for every timestep in constant time.
But how do we start the recursion?&lt;/p&gt;

&lt;p&gt;There are two options:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Wait until we have N measurements where N = dim(x). Then H is quadratic so we
easily invert it directly. And we calculate \(C_k = (H_{1:K}^T W_{1:K}^{-1} H_{1:K})^{-1}\)&lt;/li&gt;
  &lt;li&gt;We initialize x with the zero vector and set its uncertainty to infinite by
defining \(C_k = \lambda \cdot I\) where I is the identity matrix and \(\lambda\) a large positive number.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;information-form&quot;&gt;Information form&lt;/h3&gt;

&lt;p&gt;With the relationship: \((I - K_k H_{k+1}) = C_{k+1} C_{k}^{-1}\)&lt;/p&gt;

&lt;p&gt;we can transform the prediction:&lt;/p&gt;

\[x_{k+1} = (I - K_k H_{k+1}) x_k + K_k z_{k+1}\]

&lt;p&gt;… to:&lt;/p&gt;

\[x_{k+1} = C_{k+1} C_k^{-1} x_k + C_{k+1} H_{k+1}^T W_{k+1}^{-1} z_{k+1}\]

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Kalman_filter#Information_filter&quot;&gt;Wikipedia states&lt;/a&gt;:
In the information filter, or inverse covariance filter, the estimated covariance
and estimated state are replaced by the information matrix Y and information vector y respectively.&lt;/p&gt;

&lt;p&gt;We multiply \(C_{k+1}^{-1}\) on both sides left:&lt;/p&gt;

\[C_{k+1}^{-1} x_{k+1} =  C_k^{-1} x_k + H_{k+1}^T W_{k+1}^{-1} z_{k+1}\]

\[y_{k+1} =  y_{k} + H_{k+1}^T W_{k+1}^{-1} z_{k+1}\]

&lt;p&gt;And the Inverse Covariance matrix is calculated like this:&lt;/p&gt;

\[C_{k+1}^{-1} = C_{k} + H_{k+1}^T W_{k+1}^{-1} H_{k+1}\]

\[Y_{k+1} = Y_{k} + H_{k+1}^T W_{k+1}^{-1} H_{k+1}\]

&lt;p&gt;&lt;strong&gt;But why?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In this inverse formulation of the covariance matrix we can define infinite mistrust with a simple zero&lt;/li&gt;
  &lt;li&gt;As long as we do not need any steps in between, we can calculate the information
matrix and information vector separated from each others&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Biggest advantage&lt;/strong&gt; according to Wikipedia: “The main advantage of the information filter is that N measurements can be filtered at     each timestep simply by summing their information matrices and vectors.” (“Kovarianz wird additiv”)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;bayesian-filtering-framework&quot;&gt;Bayesian Filtering Framework&lt;/h3&gt;

&lt;p&gt;We are going to approach the localization from a probabilistic context.
We treat the state \(x\) as a probability density function over the state space
with its expectation value as the most likely position and the covariance matrix
of the pdf as the measure of uncertainty.&lt;/p&gt;

&lt;p&gt;This is equivalent to hidden markov models.&lt;/p&gt;

&lt;p&gt;Estimate the current state after all the measurements of the past:&lt;/p&gt;

\[P(x_k|z_{1:k}) =^{\text{Bayes}}= \frac{P(z_k|x_k, z_{1:k-1}) \cdot P(x_k|z_{1:k-1})}{P(z_k|z_{1:k-1})}\]

&lt;p&gt;With the Markov assumption:&lt;/p&gt;

\[\frac{P(z_k|x_k) \cdot P(x_k|z_{1:k-1})}{P(z_k|z_{1:k-1})}\]

&lt;p&gt;The partition function might not be tractable therefore we continue with a term which is proportional to the last one:&lt;/p&gt;

\[P(z_k|x_k) \cdot P(x_k|z_{1:k-1})\]

&lt;p&gt;\(P(z_k\|x_k)\) is a probabilistic form of the &lt;strong&gt;observation model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The probability of a state given the past observations is the prediction problem:
\(P(x_k|z_{1:k-1}) = P(x_{k+1}|z_{1:k})\)&lt;/p&gt;

&lt;p&gt;We can marginalize this:
\(P(x_{k+1}|z_{1:k}) = \int_{x_k}{P(x_{k+1}|x_k, z_{1:k}) \cdot P(x_{k}|z_{1:k})}\)&lt;/p&gt;

&lt;p&gt;If we assume time invariance then we can write:&lt;/p&gt;

\[P(x_{k+1}|z_{1:k}) = \int_{x_k}{P(x_{k+1}|x_k) \cdot P(x_{k}|z_{1:k})} dx_k\]

&lt;p&gt;\(P(x_{k+1}\|x_k)\) is the probabilistic version of the &lt;strong&gt;system model&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And \(P(x_{k}\|z_{1:k})\) is the question where we started but one timestep earlier. So we see that we can solve this problem with recursion.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;main problem&lt;/strong&gt; with this is the integral after the marginalization.
A restriction is necessary to solve it.&lt;/p&gt;

&lt;h3 id=&quot;linear-gaussian-model&quot;&gt;Linear Gaussian Model&lt;/h3&gt;

&lt;p&gt;“A linear-Gaussian model is a Bayes net where all the variables are Gaussian, and each variable’s mean is linear in the values of its parents. They are widely used because they support efficient inference. Linear dynamical systems are an important special case. “ - &lt;a href=&quot;https://metacademy.org/graphs/concepts/linear_gaussian_models&quot;&gt;metacedemy&lt;/a&gt;&lt;/p&gt;

\[x_{k+1} = A_k x(k) + B_k u(k) + w_k\]

\[z_k = H_k x(k) + v_k\]

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;\(A_k\) is the system model&lt;/li&gt;
  &lt;li&gt;\(B_k\) the input matrix&lt;/li&gt;
  &lt;li&gt;u(k) the controllable input vector&lt;/li&gt;
  &lt;li&gt;\(w_k\) the normally distributed white &lt;strong&gt;process noise&lt;/strong&gt; (-&amp;gt; mean=0, cov=\(C_w\))&lt;/li&gt;
  &lt;li&gt;\(H_k\) the measurement matrix&lt;/li&gt;
  &lt;li&gt;\(v_k\) the normally distributed white &lt;strong&gt;measurement noise&lt;/strong&gt; (cov=\(C_v\))&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result: x(k) and z(k) are also random variables with \(N(\hat{x}, C_x)\) and
measurement uncertainty \(C_z\).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Summary&lt;/strong&gt;: The state and the measurement are random variables. The Bayesian Framework is helpful to see how a filter should calculate the posterior distribution from the prior distribution, measurements, the measurement model and the system model.
The mentioned restriction of the motion model leads to the fact that we have only one possible predecessor for
a given state. As a result, we do not have to build the integral in the Bayesian Framework anymore.&lt;/p&gt;

&lt;h4 id=&quot;filter-step-without-priori-knowledge&quot;&gt;Filter Step without priori knowledge&lt;/h4&gt;

&lt;p&gt;“Filterschritt ohne Vorwissen”&lt;/p&gt;

&lt;p&gt;We start with the measurement equation of the linear system.&lt;/p&gt;

\[z_k = H_k x_k + v_k\]

&lt;p&gt;&lt;strong&gt;Attention:&lt;/strong&gt; dim(z_k) &amp;gt;= dim(x_k) and H full column rank.&lt;/p&gt;

&lt;p&gt;A first non-formal way is to use the deterministic Least Squares for the
random variable mapping with the unknown weight matrix W:&lt;/p&gt;

\[x_k^{LS} = (H_k^T W_k^{-1} H_k)^{-1} H_k^T W_k^{-1} z_k\]

&lt;p&gt;And then determine the first and second moment:&lt;/p&gt;

&lt;p&gt;Expectation value: \(\hat{x}_k^{LS} = (H_k^T W_k^{-1} H_k)^{-1} H_k^T W_k^{-1} \hat{z}_k\)&lt;/p&gt;

&lt;p&gt;Covariance matrix: \(C_k^{LS} = (H_k^T W_k^{-1} H_k)^{-1}  H_k^T W_k^{-1} C_k^z W_k^{-1} H_k  (H_k^T W_k^{-1} H_k)^{-1}\)&lt;/p&gt;

&lt;p&gt;This solution contains the unknown weighting matrix and has no proof of optimality
in any way.&lt;/p&gt;

&lt;p&gt;Therefore the next step is to derive a better solution with formal restrictions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Affine estimator (“linear”)&lt;/li&gt;
  &lt;li&gt;Unbiased&lt;/li&gt;
  &lt;li&gt;Minimum covariance (“best”)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These requirements form the “Best Linear Unbiased Estimator” (BLUE)&lt;/p&gt;

&lt;p&gt;We start with an affine estimator:&lt;/p&gt;

\[x^e_k = K_k z_k + c_k\]

&lt;p&gt;We require (2) that the expectation value of the estimator is the same as of the
real value (which is unknown) \(E[x^e_k] = E[x_k]\)&lt;/p&gt;

\[E[x^e] = K_k E[z_k] + c_k\]

&lt;p&gt;Now we use the measurement model:&lt;/p&gt;

\[E[x^e] = K_k H_k E[x_k] + c_k\]

&lt;p&gt;\(c_k\) has to be zero in order to let the estimator be unbiased:&lt;/p&gt;

\[E[x^e] = K_k H_k E[x_k]\]

&lt;p&gt;Now we add that the expectation values should be the same:&lt;/p&gt;

\[K_k H_k E[x_k] = I E[x_k]\]

&lt;p&gt;This brings us to the following relationship which is not unique.&lt;/p&gt;

\[K_k H_k = I\]

&lt;p&gt;This is where our third requirement comes into play: We want the Cov(x_k^e)=C_k^e to be minimal.
We can formulate this demand with the inverted observation model and the least squares
approach:&lt;/p&gt;

\[x_k^e = K_k^{opt} z_k\]

&lt;p&gt;with&lt;/p&gt;

\[K_k^opt = (H_k^T (C_k^z)^{-1} H_k)^{-1} H_k^T (C_k^z)^{-1}\]

&lt;p&gt;We calculate the covariance matrix like this:&lt;/p&gt;

\[C_k^e = (H_k^T (C_k^z)^{-1} H_k)^{-1}\]

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; We get the same result for the formal approach and the initial least
   squares solution if we use the covariance matrix of the measurement as our
   weighting matrix.&lt;/p&gt;

&lt;h4 id=&quot;optimal-fusion&quot;&gt;Optimal fusion&lt;/h4&gt;

&lt;p&gt;Now we have the case that there are two unbiased but uncertain state estimations
\(x_1\) with covariance \(C_1\) and \(x_2\) with \(C_2\).&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Linear estimator&lt;/li&gt;
&lt;/ol&gt;

\[x^e = K_1 x_1 + K_2 x_2\]

&lt;ol&gt;
  &lt;li&gt;Unbiased&lt;/li&gt;
&lt;/ol&gt;

\[E[x^e] = K_1 E[x_1] + K_2 E[x_2]\]

&lt;p&gt;\(x_1\) and \(x_2\) are unbiased.&lt;/p&gt;

\[= K_1 E[x] + K_2 E[x]\]

\[(K_1 + K_2) \cdot E[x] =^{!}= E[x]\]

\[K_1 + K_2  = I\]

&lt;p&gt;We can reduce the amount of work by only defining one weighting matrix K and
its opposite:&lt;/p&gt;

\[K  = K_1\]

\[K_2  = I - K\]

&lt;p&gt;And plug it into the estimator:&lt;/p&gt;

\[x^e = K x_1 + (I - K) x_2\]

&lt;p&gt;The covariance matrix of the estimator becomes:&lt;/p&gt;

\[C^e(K) = K^T C_1 K + (I - K)^T C_2 (I - K)\]

&lt;p&gt;As with the filter step without bias, we want the uncertainty of the combination
to be minimal. We achieve this by projecting the covariance matrix onto a unit vector,
deriving this projection, setting the derivate to zero and then solve for the
optimal K.&lt;/p&gt;

&lt;p&gt;Projection: \(P(K) = e^T C^e(K) e\)&lt;/p&gt;

&lt;p&gt;Derivative:&lt;/p&gt;

\[\frac{d}{dK} P(K) = 2 e e^T (K C_1 + (I - K) C_2)\]

&lt;p&gt;Set to zero:&lt;/p&gt;

\[2 e e^T (K C_1 + (I - K) C_2) = 0\]

\[K C_1 - (I - K) C_2 = 0\]

\[K C_1 - C2 + K C_2 = 0\]

\[K C_1 + K C_2 =  C_2\]

\[K (C_1 + C_2) = C_2\]

\[K  = C_2 (C_1 - C_2)^{-1}\]

&lt;p&gt;Finally the optimal fusion of two unbiased states:&lt;/p&gt;

\[x^e = C_2 (C_1 + C_2)^{-1} x_1 + C_1 (C_1 + C_2)^{-1} x_2\]

&lt;p&gt;With the new Cov:&lt;/p&gt;

\[C^e = C_2 (C_1 + C_2)^{-1} C_1\]

&lt;h4 id=&quot;prediction&quot;&gt;Prediction&lt;/h4&gt;

&lt;p&gt;First of all we rewrite our linear model a little bit. We assume that the input
random vector is a sum of a known input vector \(\hat{u}_k\) and process noise
\(w_k\).&lt;/p&gt;

\[x_{k+1} = A_k x_k + B_k (\hat{u}_k + w_k)\]

&lt;p&gt;The expectation value of the prediction becomes:&lt;/p&gt;

\[x_{k+1}^p = A_k \hat{x}_k + B_k \hat{u}_k\]

&lt;p&gt;Under the assumption that the system noise is &lt;strong&gt;not correlated&lt;/strong&gt; to the old state
we obtain the new covariance matrix:&lt;/p&gt;

\[C_{k+1}^p = A_k C_k^x A_k^T + B_k C_k^w B_k^T\]

&lt;h3 id=&quot;dynamic-localization&quot;&gt;Dynamic Localization&lt;/h3&gt;

&lt;p&gt;Use the optimal fusion, dead reckoning and prediction to build the naive recursive
estimator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; Because we are going to calculate a full state from the given
  measurement we have to require the \(dim(z_k) &amp;gt;= dim(x_k)\)&lt;/p&gt;

&lt;p&gt;It works as follows:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Get a measurement z&lt;/li&gt;
  &lt;li&gt;Deduce a state variable from z and C_z&lt;/li&gt;
  &lt;li&gt;Use the system dynamics to predict the state variable until we have a new measurement&lt;/li&gt;
  &lt;li&gt;Deduce a new state from the new measurement&lt;/li&gt;
  &lt;li&gt;Use a BLUE estimator which fusions the predicted state and the deduced state from the new measurement&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_7.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;kalman-filter-step&quot;&gt;Kalman filter step&lt;/h3&gt;

&lt;p&gt;In the Kalman filter step we assume that the dimension of the measurement vector
is smaller than the dimension of the state vector and we have priori knowledge.&lt;/p&gt;

&lt;p&gt;When a new measurement arrives, the predicted state and the measurement matrix
are used to “generate” a predicted measurement that gets compared to the true
measurement. The difference between both is called the innovation and it is used
to correct the predicted state.&lt;/p&gt;

&lt;p&gt;We are looking for a BLUE estimator again:&lt;/p&gt;

&lt;p&gt;Linear estimator:&lt;/p&gt;

\[x^e = K_1 x^p + K_2 z_k\]

&lt;p&gt;shall be unbiased (the predicted estimation and the z_k are also unbiased):&lt;/p&gt;

\[E[x^e] = K_1 E[x^p] + K_2 E[z_k]\]

\[E[x] = K_1 E[x] + K_2 H_k E[x]\]

\[I = K_1 + K_2 H_k\]

\[K = K_1\]

\[K_2 = I - K H_k\]

&lt;p&gt;Third requirement: Minimum variance. Again with projection onto a unit vector and
minimizing we get:&lt;/p&gt;

\[C_k^e = (I - K_k H_k) C_k^p\]

&lt;p&gt;A &lt;strong&gt;popular interpretation&lt;/strong&gt; of the Kalman filter step uses a different formulation
of the filter:&lt;/p&gt;

\[\hat{x}_k^e = \hat{x}_k^p + K_k (z - H_k \hat{x}_k^p)\]

&lt;p&gt;The difference in the brackets is called “innovation”. And the difference is
multiplied by the Kalman Gain Matrix. In block diagrams this can be written as
a controller (more specific a “regulator”) that regulates the difference between
the measurement and the projected measurement to zero with a proportional factor of K.&lt;/p&gt;

&lt;h3 id=&quot;recursive-kalman-estimator&quot;&gt;Recursive Kalman estimator&lt;/h3&gt;

&lt;p&gt;The recursive Kalman estimator works the same as the recursive estimator but
it uses the Kalman filter step. This means that a new measurement is not transferred
into state space instead it gets compared directly to a predicted measurement of
the predicted state. The difference is multiplied by the Kalman gain and added
to the predicted to state. This way the Kalman filter only stores the mean and
covariance of the state estimation and it also does not get more complex with
the number of used measurements.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_8.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;approximation-of-general-systems&quot;&gt;Approximation of general systems&lt;/h3&gt;

&lt;p&gt;When we are dealing with a nonlinear system and we can’t trick it into linearity
then we have to linearize it.&lt;/p&gt;

&lt;p&gt;If we don’t do this, then the main problem becomes that we are not mapping
from gaussian to gaussian. The following image shows the blue gaussian curve
projected by a linear function h(x) and by a nonlinear function h’(x).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_9.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We solve this by linearizing the system model \(x_{k+1} = a(x, u)\) and the measurement model
\(z = h(x, v)\). Why? Because all of our equations until now only work with
matrices A, B and H.&lt;/p&gt;

&lt;p&gt;The first order Taylor polynomial is used:&lt;/p&gt;

\[x_{k+1} = a(x, u) \approx a(x, u) + J_{a, x}^x \cdot \Delta x + J_{a, x}^u \cdot \Delta u\]

&lt;p&gt;\(J_{a, x}^u\) is the jacobi matrix of function \(a\) around the point \(x\) containing the partial
derivatives only after u.&lt;/p&gt;

\[x_{k+1} \approx a(x, u) + J_{A_k} * \Delta x + J_{B_k} * \Delta u\]

&lt;p&gt;This is a linear equation but it still does not look like the system equation
that we need for our Kalman filter.&lt;/p&gt;

&lt;p&gt;But if we stop modelling the full state of the system and only track the difference
between the states (\(x_{k+1} \approx x_{k} + \Delta_{x_k}\)) we get the form in which we are interested:&lt;/p&gt;

\[\Delta x_{k+1} \approx J_{A_k} * \Delta x_k + J_{B_k} * \Delta u_k\]

&lt;p&gt;Note: If the system was time invariant or the development point around which we
linearized was an equilibrium point, the Jacobi matrices are also time invariant.&lt;/p&gt;

&lt;p&gt;We linearize the measurement model in the same way:&lt;/p&gt;

\[\Delta z_k \approx J_{H_k} * \Delta x_k\]

&lt;p&gt;The &lt;strong&gt;Extended Kalman Filter (EKF)&lt;/strong&gt; is the regular Kalman filter using these
linearized equations.&lt;/p&gt;

&lt;p&gt;The predicted state is the linearization point.&lt;/p&gt;

&lt;p&gt;???&lt;/p&gt;

&lt;p&gt;ToDo: Mitschrieb Vorlesung 12&lt;/p&gt;

&lt;p&gt;???&lt;/p&gt;

&lt;h4 id=&quot;ukf&quot;&gt;UKF&lt;/h4&gt;

&lt;p&gt;The problem with EKF is that large uncertainties or large \(\Delta\)s are not
transformed correctly when the nonlinear function is only linearized at one
place.&lt;/p&gt;

&lt;p&gt;Therefore the &lt;strong&gt;Unscented Kalman Filter&lt;/strong&gt; uses so called sigma points to represent
remarkable points of the input normal distribution, transforms them with the
nonlinear function and reestimates a new normal distribution from the new sigma points.&lt;/p&gt;

&lt;h4 id=&quot;particle-filter&quot;&gt;Particle Filter&lt;/h4&gt;

&lt;p&gt;The procedure of the UKF is already close to the Particle filter. Here we represent
the priori distribution with particles instead of a parametric function.
Then the particles are transformed by the nonlinear function. The function might
not be deterministic, it could add random noise.&lt;/p&gt;

&lt;p&gt;The predicted particles are weighted according to a distance measure of a new
measurement. For example: Particles which are close to the real measurement get
a large weighting.&lt;/p&gt;

&lt;p&gt;In order to avoid degeneration of the particles we resample the particles
by sampling the same number of particles but not uniformly. The distribution from
which we sample is the distribution of the samples.&lt;/p&gt;

&lt;p&gt;As a result we obtain many particles near the location where a single particle with large weight
had been. And random other particles.&lt;/p&gt;

&lt;p&gt;The particle filter is also called &lt;strong&gt;Sequential Monte Carlo&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;slam&quot;&gt;SLAM&lt;/h3&gt;

&lt;p&gt;Simultaneous Localization and Mapping is a “Chicken and Egg” problem.
We don’t know the pose of the robot and neither the positions of the landmarks
but we want to create a map and localize the robot within.&lt;/p&gt;

&lt;p&gt;Challenges:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Nonlinearities&lt;/li&gt;
  &lt;li&gt;Data association: which measurement belongs to which landmark&lt;/li&gt;
  &lt;li&gt;Complexity of big maps&lt;/li&gt;
  &lt;li&gt;Non-static environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Approaches for 2d SLAM:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Online SLAM -&amp;gt; Map and last pose. The state contains the last pose and the landmarks:
\(x^T = [x,y,\phi, LM_1^x, LM_^y, ..., LM_L^x, LM_L^y]\). It has a size of 3 + 2L.
The Covariance matrix has the size squared entries.&lt;/li&gt;
  &lt;li&gt;Full SLAM -&amp;gt; Map and trajectory
The state contains 3k + 2L entries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;ekf-slam&quot;&gt;EKF SLAM&lt;/h4&gt;

&lt;h5 id=&quot;initialization&quot;&gt;Initialization:&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;Naive init: Estimate the number of landmarks the robot is going to see and
initialize the values with zero and infinite uncertainty&lt;/li&gt;
  &lt;li&gt;Preferred init: Start with a small state vector and expand it every time a
new landmark has been measured.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whether it is a new landmark or a measurement belongs to an already known landmark
is called the data association problem and an easy approach is to use 1-Nearest-Neighbour
with the Mahalanobis distance that gets weighted according to the uncertainty of the
landmarks. If this distance is above a threshold we see a new landmark.&lt;/p&gt;

&lt;h5 id=&quot;prediction-1&quot;&gt;Prediction:&lt;/h5&gt;

&lt;p&gt;The landmarks are static accordingly they do not move and no change in position
has to be predicted. The robots moves as usual. The dead reckoning then adds
uncertainty to the robot pose and consequently we also have to increase the
uncertainty between the landmarks and the robot’s pose but the uncertainty between
landmarks is not updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attention:&lt;/strong&gt; For the prediction of the mean we just apply the nonlinear motion
  model to the robot’s pose: \(x_{k+1}^p = a(x_k^e, u_k)\). For the prediction
  of the covariance matrix we do have to linearize \(a(.)\) with the Jacobi matrix
  J_{A_k}.&lt;/p&gt;

\[C_{k+1}^p = J_{A_k}^T C_k^e J_{A_k} + C_k^w\]

&lt;p&gt;\(C_k^w\) is an all zeros matrix except for the robots covariance which gets
an additive noise term due to the system noise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only the first column and first row&lt;/strong&gt; are updated by the prediction step:&lt;/p&gt;

\[C_{k+1}^p = \begin{bmatrix}
    C_{k+1}^{Robot} &amp;amp; C_{k+1, 1}^{Robot,LM} &amp;amp; \dots &amp;amp; \dots &amp;amp; C_{k+1, L}^{Robot,LM} \\
    C_{k+1, 1}^{LM, Robot} &amp;amp; C_{1}^{LM} &amp;amp; C_{1, 2}^{LM, LM} &amp;amp; \dots &amp;amp; C_{1, L}^{LM,LM} \\
    C_{k+1, 2}^{LM, Robot} &amp;amp; C_{2, 1}^{LM, LM} &amp;amp; C_{2}^{LM} &amp;amp; \dots &amp;amp; C_{2, L}^{LM,LM} \\
    \vdots &amp;amp; \vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots  \\
    C_{k+1, L}^{LM,Robot} &amp;amp;  \vdots &amp;amp;  \dots   &amp;amp; \dots  &amp;amp; C_{L}^{LM}
    \end{bmatrix}\]

&lt;p&gt;Complexity: The prediction step is linear in the number of landmarks.&lt;/p&gt;

&lt;h5 id=&quot;filtering&quot;&gt;Filtering&lt;/h5&gt;

&lt;p&gt;The robot measures an angle \(\alpha\) and the distance \(d\) to a landmark.
Now we have got two different cases:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Landmark has &lt;strong&gt;not been seen&lt;/strong&gt; before&lt;/li&gt;
  &lt;li&gt;Landmark has &lt;strong&gt;already been measured&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Unknown Landmark:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the landmark is new we initialize the position as follows:&lt;/p&gt;

\[x_{LM} = g_x(x, z) = x_{Robot} + d \cdot cos(\phi_{Robot} + \alpha)\]

\[y_{LM} = g_y(y, z) = y_{Robot} + d \cdot sin(\phi_{Robot} + \alpha)\]

&lt;p&gt;where \(\phi_{Robot}\) is the robots orientation. g(…) is the nonlinear function
responsible for the mapping. L is the number of landmarks.
These two new values are stacked into the state vector.&lt;/p&gt;

&lt;p&gt;For the extension of the covariance matrix we have to linearize the function \(g\)
at the robot position and at the new landmark position with the Jacobian \(G_R\) and
\(G_{L+1}\).&lt;/p&gt;

\[C_{k+1}^{LM} = G_R C_k^{Robot} G_R^T + G_{L+1} C_k^{v, L+1} G_{L+1}^T\]

&lt;p&gt;\(C_k^{v, L+1}\) is the measurement uncertainty.&lt;/p&gt;

&lt;p&gt;With \(C_{k+1}^{LM}\) we can initialize the diagonal entry of the extended
covariance matrix of the state vector but we also have to add the cross covariance
between this landmark and the robot \(C_{k+1}^{Robot, LM}\) and between this landmark and the other
landmarks i \(C_{i, L+1}^{LM}\). We add these values in the row and column of the new landmarks
covariance matrix.&lt;/p&gt;

&lt;p&gt;The following image shows where the three new covariance matrices are added to
the batch covariance matrix of the state:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lma/lma_10.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2nd case: Known Landmark&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have a nonlinear measurement model which uses the estimated position of the landmark
and the estimated position of the robot from the state in order to generate a
measurement. The landmark and the robots position are extracted from the state
using a selection matrix.&lt;/p&gt;

\[z_k^i = h(x_k^{Robot}, x_k^{LM i}) + v_k^i\]

&lt;p&gt;This function h(..) gets linearized and the Jacobi matrix \(H_k\) is used to
calculate the Kalman gain \(K_k\).&lt;/p&gt;

&lt;p&gt;Complexity: The field of view is usually limited and the robot never observes
  all of the landmarks that is has in its map. The complexity of the matrix inversion
  in order to calculate the Kalman gain is cubic in the number of observed landmarks
  but the number of observed landmarks is « total landmarks in the map.&lt;/p&gt;

&lt;h5 id=&quot;update&quot;&gt;Update&lt;/h5&gt;

&lt;p&gt;Now we can update the state estimation and
its covariance matrix in the previously described EKF way.&lt;/p&gt;

&lt;p&gt;Complexity: The update changes all entries of the covariance matrix.
 Therefore this is quadratic in the number of landmarks. This operation dominates
 the EKF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The correlation between the landmarks and the robot is important and cannot be
ignored. Otherwise the uncertainties decrease too fast and the robot would be
overconfident about the positions of the landmarks and therefore fail.&lt;/p&gt;

&lt;p&gt;The landmarks’ uncertainty decreases monotonically that means that they had the
largest uncertainty at initialization.&lt;/p&gt;

&lt;p&gt;The lower bound for the uncertainty is the robot’s pose uncertainty at the time
it made its first landmark measurement. It can’t be lower that that unless other
external information (like GPS) is integrated.&lt;/p&gt;

&lt;h4 id=&quot;graph-slam&quot;&gt;Graph SLAM&lt;/h4&gt;

&lt;p&gt;This is a full slam approach and I assume that the name comes from graphical
model.&lt;/p&gt;

&lt;h3 id=&quot;faq&quot;&gt;FAQ&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;How can we see that the Kalman filter minimizes the MSE?
-&amp;gt; The Kalman Gain is chosen to minimize the Covariance matrix of the estimate.
   This matrix can be derived by minimizing the trace of of the covariance which
   is the same as the mean variance. Which is the same as the mean squared derivation
   of the correct value. Which is the mean squared error.&lt;/li&gt;
&lt;/ul&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/python/localization/Localisation-of-mobile-agents&quot;&gt;Localization of mobile agents&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on September 23, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Boltzmann Machines]]></title>
  <link>https://danielpollithy.github.io/python/machine-learning/Boltzmann-Machines</link>
  <id>https://danielpollithy.github.io/python/machine-learning/Boltzmann-Machines</id>
  <published>2019-07-11T00:00:00+02:00</published>
  <updated>2019-07-11T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This article tries to explain Boltzmann machines, RBMs, DBN, a little bit about energy models
and contains a python example which shows how a generative model can be trained with contrastive divergence.&lt;/p&gt;

&lt;h2 id=&quot;boltzmann-machines&quot;&gt;Boltzmann Machines&lt;/h2&gt;

&lt;p&gt;I have explained Binary Hopfield Networks in my last post.
They had three main problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Bad efficiency&lt;/li&gt;
  &lt;li&gt;Spurious states&lt;/li&gt;
  &lt;li&gt;No possibility of “escaping” the wrong attractor region&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hinton and Sejnowski worked with a probabilistic graphical model which they called &lt;strong&gt;Boltzmann machine&lt;/strong&gt; (prev. Harmonium).
The main differences:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Every unit can have a unique bias&lt;/li&gt;
  &lt;li&gt;The weighted sum that is calculated by each hidden unit has no threshold but a sigmoid activation function
(the activation function is interpreted as the probability of the unit being active)&lt;/li&gt;
  &lt;li&gt;Due to the stochasticity of the process a particle on the energy function can leave a local minimum&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Generally speaking: A Boltzmann machine is a &lt;strong&gt;stochastic recurrent neural network&lt;/strong&gt; with visible and hidden units. It is an undirected graph without self-connections.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/boltz1.jpg&quot; alt=&quot;boltz1.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The structure of the net is generally not constrained and therefore sampling and learning become a big problem.&lt;/p&gt;

&lt;p&gt;The hidden units are denoted with \(h_i\) and the visible units with \(v_i\).
Both of these units are written as \(s_i\).&lt;/p&gt;

&lt;p&gt;As mentioned above, every unit can either be active (1) or deactivated (0).
Additional to the Hopfield Update rule we add a bias \(b_i\) and the sigmoid function:&lt;/p&gt;

&lt;p&gt;\(z_i = b_i + \sum_{j}{s_j \cdot w_{ij}}\),       \(p(s_i=1) = \sigma(z_i) = \frac{1}{1+e^{-z_i}}\)&lt;/p&gt;

&lt;p&gt;\(w_ij\) is the weight of the connection between i and j and vice versa (for i!=j).&lt;/p&gt;

&lt;h3 id=&quot;energy&quot;&gt;Energy&lt;/h3&gt;

&lt;p&gt;Therefore we can write the energy of the network as:&lt;/p&gt;

\[E = -\sum_{i&amp;lt;j}{s_i \cdot w_{ij} \cdot} - \sum_{i} b_i \cdot s_i\]

&lt;p&gt;This is different from the Hopfield Networks because of the bias. Although the weights are undirected, two connected units do not have to have the same bias.&lt;/p&gt;

&lt;p&gt;What is the probability p(v) of a given state v?
We defer the single probability of state to the energy function and divide it by all possible values of the Energy function:&lt;/p&gt;

\[p(v) = \frac{e^{-E(v)}}{\sum_{u}{e^{-E(u)}}} = \frac{e^{-E(v)}}{Z}\]

&lt;p&gt;(Z is the partition function)&lt;/p&gt;

&lt;h3 id=&quot;entropy-and-the-boltzmann-distribution&quot;&gt;Entropy and the Boltzmann distribution&lt;/h3&gt;

&lt;p&gt;If you measure the microscopic state of a thermodynamic system whose thermodynamic state is determined by a constant average energy, and only a constant average energy,&lt;/p&gt;

&lt;p&gt;∑𝑖𝑝𝑖𝐸𝑖=⟨𝐸⟩&lt;/p&gt;

&lt;p&gt;and you measure it many times, waiting between measurements long times in order to remove temporal correlations between them, then the set of measurements will follows the Boltzmann distribution&lt;/p&gt;

&lt;p&gt;𝑝𝑖=𝑒−𝐸𝑖/𝑇∑𝑗𝑒−𝐸𝑗/𝑇&lt;/p&gt;

&lt;p&gt;where 𝐸𝑖
is the energy of the i-th microscopic state, 𝑇 is the temperature and 𝑝𝑖&lt;/p&gt;

&lt;p&gt;is the probability for each of the measurements to result in i-th microscopic state.&lt;/p&gt;

&lt;p&gt;Notoriously, the Boltzmann distribution is the one you obtain if you maximize the entropy of the system&lt;/p&gt;

&lt;p&gt;𝑆=−∑𝑖𝑝𝑖log2𝑝𝑖&lt;/p&gt;

&lt;p&gt;as a function of the distribution 𝑝𝑖
subject to the set of thermodynamic constraints defining the thermodynamic state of the system, which in our case it is a constant average energy, only. This happens to be that way because, among all the microscopic states the system can possibly be, if you force the system to be in a specific thermodynamic state, then, you impose restrictions onto the set of microscopic states that the system can actually reach and with which probability (the 𝑝𝑖). This is the reason for which the thermodynamic state gives you some information about which are going to be your measurements about the microscopic states of the system. In other words, the entropy quantifies how much extra information you need, in average, to determine which is the microscopic state of the system at the time of your measurements, given that you only know its thermodynamic state.&lt;/p&gt;

&lt;p&gt;source: &lt;a href=&quot;https://www.quora.com/What-is-free-energy&quot;&gt;quora&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;heat&quot;&gt;Heat&lt;/h3&gt;

&lt;p&gt;The more you know about the state of system, the more you can take advantage of it in order to extract energy from it. For example, if a rock is falling from the sky, you can extract energy from it if you know where it is going to fall. The more you know about how and where the rock is falling, the more energy you will be able to extract from the event. In a sort of analogy, knowing that a rock is falling from the sky is like knowing the macroscopic state. On the other hand, knowing where it is going to fall is like knowing the microscopic state.&lt;/p&gt;

&lt;p&gt;Following the previous idea, you can only extract energy from a thermodynamic system from what you know of its microscopic state, which in the present context, it is the thermodynamic state. You can think of heat as energy contained in the system that you cannot extract from it because you ignore the precise microscopic state of the system at the moment where you want to extract the energy.&lt;/p&gt;

&lt;p&gt;source: &lt;a href=&quot;https://www.quora.com/What-is-free-energy&quot;&gt;quora&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;free-energy&quot;&gt;Free energy&lt;/h3&gt;

&lt;p&gt;What is &lt;strong&gt;free energy&lt;/strong&gt;? A thermodynamic quantity equivalent to the capacity of a system to do work.&lt;/p&gt;

&lt;p&gt;The free-energy is then, in an average sense, the amount of energy contained in the system, i.e. it is total energy 𝑈=⟨𝐸⟩ minus the energy you cannot extract 𝑇𝑆 due to the remaining uncertainty or ignorance you have about which is its precise microscopic state the system is given that you only know about it its thermodynamic state.&lt;/p&gt;

&lt;p&gt;This is free energy according to Helmholtz:
&lt;strong&gt;Hemholtz free energy (U - TS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is also &lt;strong&gt;Gibbs free energy&lt;/strong&gt; defined as&lt;/p&gt;

&lt;p&gt;$ G = U + PV - TS = H - TS $&lt;/p&gt;

&lt;p&gt;in which U is internal energy, P is pressure, V is volume, T is absolute temperature, S is entropy, and H is enthalpy.&lt;/p&gt;

&lt;p&gt;It measures the usefulness or process-initiating work obtainable from a system at a constant temperature and pressure.  If it is a chemical system, a reaction that lowers G occurs spontaneously.&lt;/p&gt;

&lt;p&gt;source: &lt;a href=&quot;https://www.quora.com/What-is-free-energy&quot;&gt;quora&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;where-the-sigmoid-comes-from&quot;&gt;Where the sigmoid comes from&lt;/h3&gt;

&lt;p&gt;see &lt;a href=&quot;https://en.wikipedia.org/wiki/Boltzmann_machine&quot;&gt;wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The difference of energies of two states is&lt;/p&gt;

\[\Delta E_i = E_\text{i=off} - E_\text{i=on}\]

&lt;p&gt;Substituting the energy of each state with its relative probability according to the Boltzmann factor (the property of a Boltzmann distribution that the energy of a state is proportional to the negative log probability of that state) gives:&lt;/p&gt;

\[\Delta E_i = -k_B\,T\ln(p_\text{i=off}) - (-k_B\,T\ln(p_\text{i=on}))\]

&lt;p&gt;where \(k_B\) is Boltzmann’s constant and is absorbed into the artificial notion of temperature \(T\). We then rearrange terms and consider that the probabilities of the unit being on and off must sum to one:&lt;/p&gt;

&lt;p&gt;\(\frac{\Delta E_i}{T} = \ln(p_\text{i=on}) - \ln(p_\text{i=off})\)
\(\frac{\Delta E_i}{T} = \ln(p_\text{i=on}) - \ln(1 - p_\text{i=on})\)
\(\frac{\Delta E_i}{T} = \ln\left(\frac{p_\text{i=on}}{1 - p_\text{i=on}}\right)\)
\(-\frac{\Delta E_i}{T} = \ln\left(\frac{1 - p_\text{i=on}}{p_\text{i=on}}\right)\)
\(-\frac{\Delta E_i}{T} = \ln\left(\frac{1}{p_\text{i=on}} - 1\right)\)
\(\exp\left(-\frac{\Delta E_i}{T}\right) = \frac{1}{p_\text{i=on}} - 1\)&lt;/p&gt;

&lt;p&gt;Solving for \(p_\text{i=on}\), the probability that the \(i\)-th unit is on gives:&lt;/p&gt;

\[p_\text{i=on} = \frac{1}{1+\exp(-\frac{\Delta E_i}{T})}\]

&lt;p&gt;where \(T\) is referred to as the temperature of the system. This relation is the source of the logistic function found in probability expressions in variants of the Boltzmann machine.&lt;/p&gt;

&lt;p&gt;Altering the factor T makes the logistic function wider or steeper.&lt;/p&gt;

&lt;h3 id=&quot;convergence&quot;&gt;Convergence&lt;/h3&gt;

&lt;p&gt;As with the Hopfield Nets the network shall converge to a stable state but “with a little bit of random”.
This randomness is expressed by the steepness of the sigmoid function:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/sigmoid.jpg&quot; alt=&quot;sigmoid.jpg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This steepness can be thought of as the learning rate of sgd. So we initially choose it large and then we let it become smaller so it can converge into a small region.&lt;/p&gt;

&lt;p&gt;This is related to a method called simulated annealing. The size of the learning rate is called temperature and its getting colder with every step. The temperature determines the steepness in our example. The following image is taken from wikipedia to illustrate this process:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/Hill_Climbing_with_Simulated_Annealing.gif&quot; alt=&quot;/images/Hill_Climbing_with_Simulated_Annealing.gif&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If the temperature is fixed and after enough unit updates the system only depends on the energy
we say that it reached its &lt;strong&gt;thermal equilibrium&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;restricted-boltzmann-machines&quot;&gt;Restricted Boltzmann Machines&lt;/h2&gt;

&lt;p&gt;In order to cope with some of the problems the model had to be restricted to a bipartite graph called
the &lt;strong&gt;Restricted&lt;/strong&gt; Boltzmann Machine.
The two cores of the bipartite graph are the visible and the hidden units.&lt;/p&gt;

&lt;p&gt;It was proven in 2010 by Long and Servedio that Z is intractable for both machines.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/rbm1.jpg&quot; alt=&quot;rbm1.jpg&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;energy-1&quot;&gt;Energy&lt;/h3&gt;

\[E(h,v) = -\sum_{h_i}{\sum_{v_j}{w_{ij} h_i v_j}} - \sum_{h_i}{h_i b_i} - \sum_{v_j}{v_j b_j}\]

&lt;p&gt;The probability of a visible unit v can be calculated easier:&lt;/p&gt;

\[p(v_j|H) = \sigma(b_j + \sum_{h_i}{w_{ij} h_i} )\]

&lt;p&gt;And vice versa for a hidden unit:&lt;/p&gt;

\[p(h_i|V) = \sigma (b_i + \sum_{v_j}{w_{ij} v_j} )\]

&lt;p&gt;The free energy in a RBM can be calculated and one might use it to tell something about the “potential energy” we still have when we converged to an equilibrium. It can be used to determine if a RBM is overfitting.&lt;/p&gt;

&lt;h3 id=&quot;learning-with-contrastive-divergence&quot;&gt;Learning with Contrastive Divergence&lt;/h3&gt;

&lt;p&gt;Source: &lt;a href=&quot;https://www.youtube.com/watch?v=UcAWwySuUZM&quot;&gt;Youtube&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is to pick a data vector and set it as visible units.
Now because the graph is bipartite we can update all hidden units at the same time and vice versa with the visible units until the units of the RBM reached thermal equilibrium.
This is a Markov Chain Monte Carlo method particularly Gibbs sampling.&lt;/p&gt;

&lt;p&gt;The weight update becomes: \(\Delta w_{ij} = \epsilon ( &amp;lt;v_i h_j&amp;gt;^0 - &amp;lt;v_i h_j&amp;gt;^{\infty} )\)&lt;/p&gt;

&lt;p&gt;This is a “fight” between what the memory wants (the state in the thermal equilibrium \(&amp;lt;v_i h_j&amp;gt;^{\infty}\)) and the data \(&amp;lt;v_i h_j&amp;gt;^0\). In the beginning the memory is random therefore we don’t want to make too many steps into its direction. If we don’t wait until the thermal equilibrium is reached but rather use the “wrong” gradient the method is called &lt;strong&gt;Contrastive divergence&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The longer the training continues the more iterations of contrastive divergence learning are used. In the beginning it is one and then we increase it.&lt;/p&gt;

&lt;h3 id=&quot;example-of-cd&quot;&gt;Example of CD&lt;/h3&gt;

&lt;p&gt;The following python snippet visualizes as training with CD on MNIST.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;scipy.stats&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logistic&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sklearn.datasets&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_digits&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;Figure size 432x288 with 0 Axes&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;threes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;images&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Init
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# bias
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;b2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# from x to h
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# parameter
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.01&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;contrastive_divergence_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# debug
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;print_every_nth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# contrastive divergence CD-50
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# train on the first 8 threes
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;threes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iteration&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iterations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;p_of_h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logistic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;positive_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newaxis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_of_h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newaxis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contrastive_divergence_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# plt.matshow(v.reshape([8,8]))
&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# calculate p(h|v)
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;p_of_h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logistic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;# sample p(h|v)
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_of_h&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;# calculate p(h|v)
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;p_of_v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logistic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cdf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;# sample p(h|v)
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_of_v&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iteration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;print_every_nth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reshape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;iteration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; size of W: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;negative_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newaxis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_of_h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;newaxis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;positive_phase&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;negative_phase&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;W&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  39.924335666308195
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_2.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  39.17467666748022
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_4.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.97155882317313
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_6.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.944982809345895
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_8.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.80202589068636
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_10.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.74259814116064
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_12.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.6967212149249
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/boltz2/output_3_14.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;0  size of W:  38.74791680409241
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This model of a three could already be used for dichotomizing threes and not-threes.&lt;/p&gt;

&lt;p&gt;In the code I wrote something about a positive and a negative “phase” (or gradient).
In the case of a correct sample the positive gradient increases the likelihood of the data whereas the negative gradient increases the likelihood of all others (which means that it decreases the likelihood of the current point).&lt;/p&gt;

&lt;p&gt;There are discussions whether the latter might be something like “unlearning” what humans do when they dream.&lt;/p&gt;

&lt;h2 id=&quot;deep-belief-networks&quot;&gt;Deep Belief Networks&lt;/h2&gt;

&lt;p&gt;Imagine we stacked another RBM on top of our hidden layer. We would treat the hidden units as visible and do the same training layer by layer (&lt;strong&gt;Greedy Layer-wise training&lt;/strong&gt;). The RBMs are not really connected for the training. Once the first layer is ready we don’t train it anymore. This yields a &lt;strong&gt;Deep Belief Network&lt;/strong&gt; which is something that Geoffrey Hinton has been working on for quite some time.&lt;/p&gt;

&lt;p&gt;In contrast to the Hopfield Net and the Boltzmann Machine is a Belief Net a directed probabilistic graphical model.
For this reason are the first models &lt;strong&gt;Markov Random Fields&lt;/strong&gt; (MRF) and the Belief Net a &lt;strong&gt;Bayesian Net&lt;/strong&gt;.
The MRFs are coupled with Energy-based models because symmetric weights are an important property to converge.
Directed graphs have the intention to model causal relationships and not only correlations.&lt;/p&gt;

&lt;p&gt;The advantage of this “stacking” is to build hierarchical features. Although neural networks with two hidden layers are in theory already a general function approximator depth introduces a valuable inductive bias especially when coupled with a convolution. What I mean with that is that there are hierarchical patterns which can be uncovered easily when we assume locality and increasing complexity.&lt;/p&gt;

&lt;p&gt;A Belief Net is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A directed acyclic graph&lt;/li&gt;
  &lt;li&gt;typically sparsely connected (this is a prerequisite for some smart algorithms to work)&lt;/li&gt;
  &lt;li&gt;every variable could be observed or hidden (“visible effects” and “hidden stochastic causes”)&lt;/li&gt;
  &lt;li&gt;First target: Infer the state of unobserved variables&lt;/li&gt;
  &lt;li&gt;Second target: “Learning”: Adapt the interactions between nodes in the graph in order to maximize the likelihood&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sampling the leaf nodes is easy but sampling the posterior is hard.
&lt;strong&gt;Why is this interesting?&lt;/strong&gt; In supervised learning we assume that all our training samples were sampled from the data manifold. Why can’t we just use the training data as samples from the posterior?&lt;/p&gt;

&lt;p&gt;Unfortunately I have a technical answer only. For Variational Autoencoders (VAE). We assume that there are some hidden causes which we will never observe but we want to make them explicit and in the case of VAE even use them to control the generation of images or robotic hands.&lt;/p&gt;

&lt;p&gt;An intuitively understandable reason for why sampling this posterior is difficult can be given by the concept of &lt;strong&gt;Explaining-Away&lt;/strong&gt;. Explaining-Away is basically a pattern of reasoning where one cause of an effect explains that effect entirely thereby reducing (need not eliminate) the need to verify other alternative causes.&lt;/p&gt;

&lt;p&gt;A quote from a &lt;a href=&quot;https://www.quora.com/What-is-an-intuitive-explanation-of-the-explaining-away-problem-in-directed-graphical-models&quot;&gt;quora answer&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Imagine an ‘observation’ ‘Ob’, say “you scored 100/100 in Math”. It could have had two (for the sake of simplicity) causes, viz ‘C1’ - ‘the question-paper was too easy’ and ‘C2’ - ‘you are too smart’. Now, ‘Ob’ could be because of either of those two causes (or both) i.e. you scored 100/100 because either the question-paper was way too easy or you’re just too smart or both. Confirmation of one cause, say ‘C1’ i.e. ‘paper was too easy’ doesn’t provide any evidence for the other alternate cause ‘C2’ (‘you are too smart’).
But, in a probabilistic scheme of reasoning, confirmation of the first reasoning ‘C1’ (‘paper was easy’) SHOULD REDUCE the probability of the other cause (‘you are smart’) even though both can be true simultaneously. This is called “Explaining Away”. I mean to say if I know that you scored 100/100 and also know that the paper was way too easy, I tend to assume you’re not very very smart even if you actually are.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The variational approach that was kicked-off by the &lt;strong&gt;Wake-Sleep Algorithm&lt;/strong&gt; just does not use an unbiased sample from the posterior but a more or less similar distribution.
With this approximation we can make maximum likelihood. So it seems like we perform the same two steps as in &lt;strong&gt;Expectation Maximization&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There is a lot more to read and write about this topic but it feels like I am drifting to variational methods, therefore I am going end here and leave the rest for the next time.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.cs.toronto.edu/~hinton/absps/guideTR.pdf&quot;&gt;A Practical Guide to Training Restricted Boltzmann Machines&lt;/a&gt;&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/python/machine-learning/Boltzmann-Machines&quot;&gt;Boltzmann Machines&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on July 11, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Hopfield Network]]></title>
  <link>https://danielpollithy.github.io/python/machine-learning/Hopfield-Networks</link>
  <id>https://danielpollithy.github.io/python/machine-learning/Hopfield-Networks</id>
  <published>2019-07-05T00:00:00+02:00</published>
  <updated>2019-07-05T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;This article explains Hopfield networks, simulates one and contains the relation to the Ising model.&lt;/p&gt;

&lt;h2 id=&quot;hopfield-nets&quot;&gt;Hopfield Nets&lt;/h2&gt;

&lt;p&gt;Let’s assume you have a classification task for images where all images are known. The optimal solution would be to store all images and when you are given an image you compare all memory images to this one and get an exact match.
But then you realize that this “look up” (comparing one image after another) becomes costly the more images you have to memorize.
Even if you try to arange the images in a tree structure you will never be as fast as the following solution: store all images in &lt;strong&gt;Content addressable memory (CAM)&lt;/strong&gt;.
CAM is specialized hardware that is used in routers. Ternary-CAM additionally has a “Don’t-Care” state (“?”) with which parts of the pattern can be masked (this is useful for IP routing).&lt;/p&gt;

&lt;p&gt;In German CAMs are referred to as “Assoziativspeicher” (associative memory). Intuitively you don’t use an address to access data but instead you use data to access the address of the data.&lt;/p&gt;

&lt;p&gt;Now imagine we had many pictures of dogs in our memorized array. And then comes a new image of a dog.
Expect for the masking option (“?”) we cannot perform any kind of fuzzy search on hardware CAM.&lt;/p&gt;

&lt;p&gt;As we will see in the following section, a Hopfield Network is a form of a recurrent artificial neural network and it serves as some kind of &lt;strong&gt;associative memory&lt;/strong&gt;. It is interesting to analyse because we can model how neural networks store patterns.&lt;/p&gt;

&lt;h3 id=&quot;binary-hopfield-networks&quot;&gt;Binary Hopfield Networks&lt;/h3&gt;

&lt;p&gt;A network with N binary units which are interconnected symmetrically (weight \(T_{ij}=T_{ji}\)) and without self-loops (\(T_{ii} = 0\)).
Every unit can either be positive (“+1”) or negative (“-1”). Therefore we can describe the state of the network with a vector U. For example U = (+,-,-,-,+…).&lt;/p&gt;

&lt;p&gt;Intuitively we initially set a state and wait until the network relaxes into another stable state. That means it does not change anymore once it reached that state. The reached state is the output value. For the associative memory example with images, the initial state is the image (black and white) and the stable state can also be interpreted as an image.&lt;/p&gt;

&lt;p&gt;Each of the units is a McCulloch-Pitts neuron with a step-function as non-linearity.
That means if we only update a single unit (“neuron”) then we calculate the weighted sum of the neighbours and set the neuron to “+” if the sum is greater or equals a threshold.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Weighted sum of neuron \(x_j\): \(g(x_j) = \sum_{i}{x_i \cdot T_{ji}}\)&lt;/li&gt;
  &lt;li&gt;Step function: \(x_j = \begin{cases}
+1,  g(x_j) \ge 0\\
-1,   else
\end{cases}\)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update procedure&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Synchronous update: A global clock tells all neurons at the same time to update. As a consequence all new states
only depend on the old states&lt;/li&gt;
  &lt;li&gt;Asynchronous update: One unit is updated after another. This seems to be more plausible for biological neurons or
ferro-magnets because they have no common clock. The order is random.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learning&lt;/strong&gt; refers to finding appropriate weights. For the associative memory we want the connections between two neurons positive if they are often active together and we want the value to be negative if they are often different.
This is &lt;strong&gt;Hebbian Learning Theory&lt;/strong&gt; which is summed up as “Neurons that fire together, wire together. Neurons that fire out of sync, fail to link”.&lt;/p&gt;

&lt;h3 id=&quot;example&quot;&gt;Example&lt;/h3&gt;

&lt;p&gt;The following example simulates a Hopfield network for noise reduction. The training patterns are eight times “+”/”-“, six times “+”/”-“ and six times the result of “+”/”-“ AND “+”/”-“.
The reason for the redundancy will be explained later.&lt;/p&gt;

&lt;p&gt;The images of the simulations have the number of state at the x-axis and the time step as y-axis.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#     Left variable                |    Right variable              =   Left AND Right    
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;weights&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;patterns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;weights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visualize&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;number_of_iteration_unchanged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;first_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;first_state&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number_of_iteration_unchanged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;number_of_iteration_unchanged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;number_of_iteration_unchanged&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;random_unit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;randint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;all_new_states&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dtype&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_new_states&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random_unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;np_trace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;visualize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;imshow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np_trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/output_2_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/output_3_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/output_4_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;simulate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/output_5_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We see that all of the simulations “relaxed” to a solution which did not change for a long time (epsilon).
Running the simulations multiple times showed that the (0,0) and (1,1) cases always converged to the correct pattern whereas the distinct cases were torn between the the correct state and its inverse.&lt;/p&gt;

&lt;p&gt;But why does the network converge at all?&lt;/p&gt;

&lt;h3 id=&quot;stability-theory&quot;&gt;Stability theory&lt;/h3&gt;

&lt;p&gt;In system theory there is the quest to prove the stability of different kind of systems (see &lt;a href=&quot;https://en.wikipedia.org/wiki/Lyapunov_stability&quot;&gt;here&lt;/a&gt;). A system is said to be stable if small perturbations of the input data lead to small variations of the output value.&lt;/p&gt;

&lt;p&gt;Stability can be intuitively grasped by imagining the velocity and phase of a pendulum.
See the image by &lt;a href=&quot;https://commons.wikimedia.org/wiki/File:Pendulum_phase_portrait_illustration.svg&quot;&gt;Krishnavedala&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/Pendulum_phase_portrait_illustration.svg.png&quot; alt=&quot;pendulum phase diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If the pendulum was damped the phase portrait would look like a spiral.
The center to which it converges over time is a of point of attraction which is called &lt;strong&gt;equilibrium&lt;/strong&gt;.
The circle in the diagram is called “orbit”. An important question is for example: Will the trajectory of a given initial state converge to the point or will it diverge.&lt;/p&gt;

&lt;p&gt;And what happens if the system gets “pushed” a little bit. A pendulum would oscilate a little bit and converge back to the &lt;strong&gt;equilibrium&lt;/strong&gt; but a football on a hill would roll down.&lt;/p&gt;

&lt;p&gt;For linear systems we can use the magnitude of the derivative of a point a. If it is less than one the system is said to be stable.&lt;/p&gt;

&lt;p&gt;For more information see &lt;a href=&quot;https://en.wikipedia.org/wiki/Stability_theory&quot;&gt;Stability theory&lt;/a&gt; on Wikipedia.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Lyapunov Function&lt;/strong&gt; can be used to show asymptotic stability (it gets really close) or lyapunov stability (all points which were at time t in an orbit are at t+1 in a small neighbourhood). It works by choosing a Lyapunov function which has an analogy to the &lt;strong&gt;potential function&lt;/strong&gt; of classical dynamics. In real physical systems a precise Energy function can be used. You can imagine a state x of pendulum. If the system loses energy the system will reach a final resting point. The final state is the attractor.
Lyapunov showed that it is not necessary to know the energy function but it is enough to find a Lyapunov function V(x) with the following criteria:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
\[V(0) = 0\]
  &lt;/li&gt;
  &lt;li&gt;\(V(x) &amp;gt; 0\) if \(x \ne 0\)&lt;/li&gt;
  &lt;li&gt;\(\dot{V}(x) = \frac{d}{dt}V(x) = \nabla V \cdot f(x) \le 0\) if \(x \ne 0\)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Lyapunov_stability&quot;&gt;Lyapunov Stability&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;energy-function&quot;&gt;Energy function&lt;/h3&gt;

&lt;p&gt;Let’s apply this to Binary Hopfield Networks. We saw in the simulation that the Hopfield nets converge.
Will this always be the case?&lt;/p&gt;

&lt;p&gt;We choose our Energy function: \(E = -0.5 \sum_{j}{ \sum_{i \ne j}{u_i \cdot u_j \cdot T_{ji}} }\)&lt;/p&gt;

&lt;p&gt;Actually we cannot assume to have a single global optimum on the surface of the energy function.
At least every pattern we want to store should a local optimum. So we just show that the energy at t+1 is less or equal to t and therefore we always find a local optimum of the energy function.&lt;/p&gt;

&lt;p&gt;In our asynchronous, random update procedure we pick a unit u. It either has the state -1 and we change it to +1 or it has the state +1 and we change it to -1. In the first case the difference is “+2” and the the second one it is “-2”. =&amp;gt; \(\Delta u_j \in \{ -2, +2 \}\)&lt;/p&gt;

&lt;p&gt;How does the energie of unit j change?&lt;/p&gt;

\[\Delta E_j = E_{j_{new}} - E_{j_{old}} =\]

\[-0.5 \sum_{i \ne j}{u_{i} u_{j_{new}} T_{ji}} -0.5 \sum_{i \ne j}{u_i u_j T_{ji}} =\]

\[-0.5 \cdot (\sum_{i \ne j}{u_{i} u_{j_{new}} T_{ji}} -\sum_{i \ne j}{u_i u_j T_{ji}} ) =\]

\[-0.5 \cdot (\sum_{i \ne j}{u_{i} u_{j_{new}} T_{ji} -{u_i u_j T_{ji}}} ) =\]

\[-0.5 \cdot (\sum_{i \ne j}{u_{i} \cdot T_{ji} \cdot (u_{j_{new}} - u_j}) ) =\]

&lt;p&gt;Define: \(\Delta u_j = u_{j_{new}} - u_j\)&lt;/p&gt;

\[-0.5 \cdot (\sum_{i \ne j}{u_{i} \cdot T_{ji} \cdot \Delta u_j }) =\]

\[-0.5 \Delta u_j (\sum_{i \ne j}{u_{i} \cdot T_{ji} }) =\]

&lt;p&gt;Two possible cases for the neuron j:&lt;/p&gt;

&lt;p&gt;“+2” case: The weighted neighbours are greater equal zero
    (\(\sum_{i \ne j}{u_{i} \cdot T_{ji} } &amp;gt;= 0\)),
    \(\Delta u_j=+2\),
    \(\Delta E_j = -1 \cdot (\sum_{i \ne j}{u_{i} \cdot T_{ji} }) \le 0\)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;“-2” case: The weighted neighbours are less than zero
  (\(\sum_{i \ne j}{u_{i} \cdot T_{ji} } &amp;lt; 0\)),
  \(\Delta u_j=-2\),
  \(\Delta E_j = +1 \cdot (\sum_{i \ne j}{u_{i} \cdot T_{ji} }) &amp;lt; 0\)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; In both cases the energy either reduces or stays the same. Every minimum of the energy function is a stable state.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/hopfield/lyapunov function.png&quot; alt=&quot;Energy visualization&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the example of the associative memory we see that a pattern (state) can only converge to the correct solution (pattern) if it is in its attractor region. Imagine a 2d hill. On which side of the hill we roll down is determined by the random sampling process. This explains why the “AND-simulation” from above can converge into different states.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Not all attractor regions have the same size. Therefore one state can attract more patterns than another. For the associative memory this leads to some kind of prior.
Additionally mixture of an odd number of patterns cause &lt;strong&gt;mixture states&lt;/strong&gt; which do not correspond to real patterns.
Even numbers would sum up to zero.&lt;/p&gt;

&lt;p&gt;For every pattern x the inverse of x is also a local minimum.&lt;/p&gt;

&lt;p&gt;If we try to store too many patterns so called &lt;strong&gt;spin glass&lt;/strong&gt; states are generated. They are no linear combination of the original states. A network of N units has the capacity to store ~ 0.15N uncorrelated patterns.
All the minima that have no associated pattern are called &lt;strong&gt;spurious states&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If all weights are “+1” then the function calculated is something like k-Means/Hamming distance.&lt;/p&gt;

&lt;p&gt;More math about Hopfield nets &lt;a href=&quot;https://page.mi.fu-berlin.de/rojas/neural/chapter/K13.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;ising-model&quot;&gt;Ising model&lt;/h3&gt;

&lt;p&gt;Hopfield nets are isomorph to the &lt;strong&gt;Ising model&lt;/strong&gt; in statistical physics which is used to model magnetism at low temperatures. Every neuron equals an atom in a solid body. The state of the unit coincides with the spin (the magnetic moment).
In the &lt;strong&gt;Heisenbergmodel&lt;/strong&gt; the spin can be multivariate. In the &lt;strong&gt;Ising model&lt;/strong&gt; the spin is either parallel or antiparallel to a given axis z). The latter can be written as the Binary Hopfield Network.&lt;/p&gt;

&lt;p&gt;In physics the energy of the atoms is “measured” with the &lt;strong&gt;Hamilton operator H&lt;/strong&gt;. It is the sum of the potential and kinetic energies in the system.&lt;/p&gt;

\[H = -0.5 \sum_{ij} T_{ij} \cdot s_i \cdot s_j - H_z \sum_{i=1}{s_i}\]

&lt;ul&gt;
  &lt;li&gt;\(s_i\) the spin of an atom&lt;/li&gt;
  &lt;li&gt;\(T_{ij}\) the coupling constant between the spin of two atoms&lt;/li&gt;
  &lt;li&gt;\(H\) is the strength of the magnetic field&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The critical temperature was calculated with this model. A system with less than its critical temperature is dominated by quantum mechanical effects. If the majority of the couplings have a positive sign then
the body is ferromagnetic. Which means you could use a permanent magnet to
magnetize it like a refrigerator magnet.&lt;/p&gt;

&lt;p&gt;
  &lt;figure&gt;
    &lt;div class=&quot;videoWrapper&quot;&gt;
      &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/IP3W7cI01VY&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
    &lt;/div&gt;
  &lt;/figure&gt;
&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/python/machine-learning/Hopfield-Networks&quot;&gt;Hopfield Network&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on July 05, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Simulating heat flow with Fourier]]></title>
  <link>https://danielpollithy.github.io/general/Heat-Simulation-Fourier</link>
  <id>https://danielpollithy.github.io/general/Heat-Simulation-Fourier</id>
  <published>2019-07-01T00:00:00+02:00</published>
  <updated>2019-07-01T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;I recently read the book “Infinite Powers” by Steven Strogatz. In chapter 10
he told the story of Joseph Fourier and why he initially cared about approximating
functions with a mixture of sine and cosine waves.&lt;/p&gt;

&lt;p&gt;His objective was to solve the “heat problem”. How does heat distribute in
in a rod (or regarding circuits: in a wire). For some backgrounds see
the section “background”.&lt;/p&gt;

&lt;p&gt;The following section contains a demo of such a wire that can cool down.
By clicking on the first wire you can draw heat patterns which are smoothed
with a Fourier transformations (actually by setting the higher order coefficients to zero).
In the case that the “simulate” check-box was active, then the simulation will start
after clicking on the wire.&lt;/p&gt;

&lt;h3 id=&quot;demo&quot;&gt;Demo&lt;/h3&gt;

&lt;p id=&quot;status&quot; style=&quot;border: solid 2px green;&quot;&gt;Status: Ready&lt;/p&gt;

&lt;p&gt;Input (click on the left half of the bar):&lt;/p&gt;
&lt;p&gt;
  &lt;canvas id=&quot;canvas&quot; width=&quot;800&quot; height=&quot;15&quot; style=&quot;border: 1px solid black; margin: 0; padding: 0;&quot;&gt;&lt;/canvas&gt;
  &lt;/p&gt;

&lt;p&gt;Betragsspektrum:&lt;/p&gt;
&lt;p&gt;
  &lt;canvas id=&quot;heatmap&quot; width=&quot;401&quot; height=&quot;15&quot; style=&quot;border: 1px solid black; margin: 0; padding: 0;&quot;&gt;&lt;/canvas&gt;
  &lt;/p&gt;

&lt;p&gt;Abgeschnittenes Betragsspektrum:&lt;/p&gt;
&lt;p&gt;
  &lt;canvas id=&quot;heatmap2&quot; width=&quot;401&quot; height=&quot;15&quot; style=&quot;border: 1px solid black; margin: 0; padding: 0;&quot;&gt;&lt;/canvas&gt;
  &lt;/p&gt;

&lt;p&gt;Output:&lt;/p&gt;
&lt;p&gt;
  &lt;canvas id=&quot;output&quot; width=&quot;400&quot; height=&quot;15&quot; style=&quot;border: 1px solid black; margin: 0; padding: 0;&quot;&gt;&lt;/canvas&gt;
  &lt;/p&gt;

&lt;p&gt;Heat flow simulation:&lt;/p&gt;
&lt;p&gt;
  &lt;canvas id=&quot;cooling&quot; width=&quot;400&quot; height=&quot;15&quot; style=&quot;border: 1px solid black; margin: 0; padding: 0;&quot;&gt;&lt;/canvas&gt;
  &lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
  &lt;b&gt;FFT coefficients:&lt;/b&gt;
   1… &lt;input type=&quot;range&quot; onchange=&quot;limit=parseInt(event.srcElement.value)&quot; min=&quot;1&quot; max=&quot;400&quot; value=&quot;400&quot; /&gt; … 400
   &lt;br /&gt;
   &lt;b&gt;Simulate cooling:&lt;/b&gt;
   &lt;input type=&quot;checkbox&quot; onchange=&quot;simulate=event.srcElement.checked&quot; name=&quot;subscribe&quot; checked=&quot;&quot; /&gt;&lt;/p&gt;

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/tensorflow/1.2.2/tf.js&quot; integrity=&quot;sha256-nmpYdNs3Fhti+a0TX7xkb8SVRzaUgZOfafDbgtvCoGk=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;

&lt;script type=&quot;text/javascript&quot;&gt;
    var canvas = document.getElementById(&quot;canvas&quot;);
    var context = canvas.getContext(&quot;2d&quot;);
    var width = 800;
    var height = 15;
    var radius = 30;
    var limit = 10;


    var canvas2 = document.getElementById(&quot;heatmap&quot;);
    var context2 = canvas2.getContext(&quot;2d&quot;);

    var canvas3 = document.getElementById(&quot;heatmap2&quot;);
    var context3 = canvas3.getContext(&quot;2d&quot;);

    var canvas4 = document.getElementById(&quot;output&quot;);
    var context4 = canvas4.getContext(&quot;2d&quot;);

    var canvas5 = document.getElementById(&quot;cooling&quot;);
    var context5 = canvas5.getContext(&quot;2d&quot;);

    var status_p = document.getElementById(&quot;status&quot;)

    real_state = null;
    imag_state = null;

    var start = null;
    var max = null;
    var busy = false;
    var simulate = true;
    var fps = 60;
    var animation_durance = 250 * width / fps;  // milliseconds

    function getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
          x: evt.clientX - rect.left,
          y: evt.clientY - rect.top
        };
    }

    function draw(evt) {
        if (busy) return
        busy_on()
        var pos = getMousePos(canvas, evt);

        context.fillStyle = &quot;rgba(0, 0, 0, 0.25)&quot;;
        context.fillRect (pos.x-radius/2.0, pos.y-radius/2.0, radius, radius);

        updateMap();
    }

    function heatmapToImage(heatmap, ctx, width_pixels) {
      heatmap = heatmap.map(x =&gt; (x-min)/(max-min))

      var image = [];
      for (var n=0; n&lt;height; n++) {
        for (var i=0; i&lt;heatmap.length; i++) {
          image.push(0);
          image.push(0);
          image.push(0);
          image.push(255.0 * heatmap[i]);
        }
      }

      var imgData = new ImageData(new Uint8ClampedArray(image), width_pixels, height)

      ctx.putImageData(imgData, 0, 0);
    }

    function cut_limit(x, idx) {
      if (idx&gt;limit) {
        return 0;
      } else {
        return x;
      }
    }

    function busy_off(){
      busy = false;
      status_p.innerHTML = &quot;Status: Ready&quot;;
      status_p.style.setProperty('border-color', 'green')
    }

    function busy_on(){
      busy = true;
      status_p.innerHTML = &quot;Status: Busy&quot;;
      status_p.style.setProperty('border-color', 'red')
    }

    function draw_canvas() {
      var timestamp = new Date().getTime()
      if (!start) start = timestamp;
      var progress = timestamp - start;
      var relative_progress = progress / animation_durance;

      context5.globalCompositeOperation = 'destination-over';
      context5.clearRect(0, 0, 400, 15); // clear canvas

      real_state = real_state.map((x, idx, ary) =&gt; x - idx/real_state.length * x)
      imag_state = imag_state.map((x, idx, ary) =&gt; x - idx/imag_state.length * x)


      const state = tf.complex(tf.tensor1d(real_state), tf.tensor1d(imag_state));

      var output = state.irfft().dataSync();

      heatmapToImage(output.slice(0,400), context5, 400);

      if (progress &lt; animation_durance) {
        setTimeout(draw_canvas, 1000/fps);
      } else {
        start = null;
        busy_off()
      }
    }

    function updateMap() {
        var imageData = context.getImageData(0, 0, 401, height);

        var firstRow = imageData.data.slice(0, width*4);

        var rgba_pixels = firstRow.filter(function(value, index, Arr) {
            return (index+1) % 4 == 0;
        });

        const real = tf.tensor1d(Array.from(rgba_pixels));
        var coeff = real.rfft().dataSync();

        var betrag = [];
        var imag_array = [];
        var real_array = []
        for (var i=0; i&lt;coeff.length - 1; i+=2) {
          betrag.push(Math.sqrt(coeff[i]**2 + coeff[i+1]**2))
          real_array.push(coeff[i])
          imag_array.push(coeff[i+1])
        }

        min = Math.min(...betrag)
        max = Math.max(...betrag)
        heatmapToImage(betrag, context2, 401);

        // ifft
        real_array = real_array.map(cut_limit);
        imag_array = imag_array.map(cut_limit);

        var betrag2 = [];
        for (var i=0; i&lt;real_array.length; i+=1) {
          betrag2.push(Math.sqrt(real_array[i]**2 + imag_array[i]**2))
        }

        min = Math.min(...betrag2)
        max = Math.max(...betrag2)
        heatmapToImage(betrag2, context3, 401);

        // global store
        real_state = real_array.slice();
        imag_state = imag_array.slice();

        const state = tf.complex(tf.tensor1d(real_array), tf.tensor1d(imag_array));

        var output = state.irfft().dataSync();

        min = Math.min(...output)
        max = Math.max(...output)
        heatmapToImage(output.slice(0,400), context4, 400);

        if (simulate) {
          setTimeout(draw_canvas, 1000/60);
        } else {
          busy_off()
        }
    }

    canvas.addEventListener('click', draw);
&lt;/script&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;Initially I wanted to write a little bit about this but I found that 3b1b just
published a video about this topic:&lt;/p&gt;

&lt;p&gt;
  &lt;figure&gt;
    &lt;div class=&quot;videoWrapper&quot;&gt;
      &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube-nocookie.com/embed/ToIXSwZ1pJU&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
    &lt;/div&gt;
  &lt;/figure&gt;
&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/general/Heat-Simulation-Fourier&quot;&gt;Simulating heat flow with Fourier&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on July 01, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Car model datasets]]></title>
  <link>https://danielpollithy.github.io/cnn/general/machine-learning/vision/car-model-datasets</link>
  <id>https://danielpollithy.github.io/cnn/general/machine-learning/vision/car-model-datasets</id>
  <published>2019-06-29T00:00:00+02:00</published>
  <updated>2019-06-29T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;list-of-car-datasets&quot;&gt;List of car datasets&lt;/h2&gt;

&lt;p&gt;This is a simple lookup page to answer questions like
“In which dataset are images of the Renault Clio?”&lt;/p&gt;

&lt;p&gt;The lists are extracted from the datasets either by reading the directory structure
or the accompanying matlab files which contain the class labels.&lt;/p&gt;

&lt;h3 id=&quot;stanford-196&quot;&gt;Stanford-196&lt;/h3&gt;

&lt;p&gt;see /images/cars_stanford196.txt&lt;/p&gt;

&lt;h3 id=&quot;compcars&quot;&gt;CompCars&lt;/h3&gt;

&lt;p&gt;see /images/compcars.txt&lt;/p&gt;

&lt;h3 id=&quot;boxcars&quot;&gt;BoxCars&lt;/h3&gt;

&lt;p&gt;see /images/boxcars.txt&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/cnn/general/machine-learning/vision/car-model-datasets&quot;&gt;Car model datasets&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on June 29, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Optimization]]></title>
  <link>https://danielpollithy.github.io/personal/python/optimization</link>
  <id>https://danielpollithy.github.io/personal/python/optimization</id>
  <published>2019-06-23T00:00:00+02:00</published>
  <updated>2019-06-23T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;optimization&quot;&gt;Optimization&lt;/h2&gt;

&lt;h3 id=&quot;search-for-the-optimum&quot;&gt;Search for the optimum&lt;/h3&gt;

&lt;p&gt;Assume we define a function f which takes a profession and returns the annual salary.
It sounds naturally to search for the optimum. Maybe we even have some constraints like
“the job should be in Europe” or “I want to work 30 hours per week”. 
This is a so called optimization problem.&lt;/p&gt;

&lt;p&gt;We define:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Variables to optimize&lt;/li&gt;
  &lt;li&gt;A criteria function which depends on the variables&lt;/li&gt;
  &lt;li&gt;Constraints that have to be satisfied by the solution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There exists the general dichotomization into &lt;strong&gt;static&lt;/strong&gt; and &lt;strong&gt;dynamic&lt;/strong&gt; optimization. In static opt. the variables are parameters whereas in dynamic optimization the variables are functions themselves.
The criteria function then is a function of a function which has the name &lt;strong&gt;functional&lt;/strong&gt;. 
A general example for a functional is the integral from zero to one of a function f. It maps the function 
to a scalar.
Control in robotics is mostly dynamic. Classifiying images or speech signals belongs to the static class.&lt;/p&gt;

&lt;p&gt;There is the general possibility to find extrema by differentiating and finding the zeros of it. 
This is done in the Lagrangian method or in a probability context with the Maximum Likelihood estimation.&lt;/p&gt;

&lt;p&gt;The term &lt;strong&gt;search&lt;/strong&gt; refers to the attempt of finding a feasible point that satisfies all
constraints and yields the lowest possible error (in the example of the beginning this would be the highest salary).
Mathematically speaking this is expressed with \(\operatorname*{argmin}_\theta f(x)\) plus some constraints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local search&lt;/strong&gt; starts from a point (a solution) and searches its neighbours
for a better solutions which can be optimized again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global search&lt;/strong&gt;: The state space gets evaluated (not only locally) in order to find an optimum.
Example: Dynamic Programming&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stochastic search&lt;/strong&gt;: Finding a new solution involves a nondeterministic component. 
Like a randomized search in ML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Uninformed search&lt;/strong&gt;: All of the options and permutations of them have to be covered. We can’t discard a path until we have tried it out. Breadth-first or depth-first search are examples of this scheme in graphs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Informed search&lt;/strong&gt;: Contrary to the uninformed search we use some kind of heuristic to guide
the process of obtaining a new solution. The heuristic might exclude parts of the state space
so we don’t have to search there. An example is the A* algorithm or the dijkstra. This is related to the global search.&lt;/p&gt;

&lt;h3 id=&quot;convex-optimization&quot;&gt;Convex optimization&lt;/h3&gt;

&lt;p&gt;Linear least squares is the method of finding a line that best fits given data points. “Best fit” means 
that the sum of the squared distances between a point and the line is minimal. The vertical distance between the point and the line gets called &lt;strong&gt;residual&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We assume the observations y are generated by a linear relationship (m) with the data X which is affected by white noise e.&lt;/p&gt;

\[y = m * x + t + noise\]

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uniform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/optim/output_1_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The process that generates the data has two unknown variables \(m\) and \(t\).
If the error was not present we could solve for the perfect solution in 
with two points:&lt;/p&gt;

\[2.0 = m * 0 + t =&amp;gt; t = 2.0\]

\[2.5 = m * 2 + 2.0 =&amp;gt; 2m = 0.5 =&amp;gt; m = 0.25\]

&lt;p&gt;In reality we cannot rely on the data nor can we rely on our model. Therefore 
we want to use as many points as possible. We just assume that the error has
no bias, because we want to take the average of all estimates.&lt;/p&gt;

&lt;p&gt;This idea is captured in the &lt;strong&gt;Linear least squares&lt;/strong&gt;:&lt;/p&gt;

\[arg_W min \sum_{i}{ (y_i - m x_i + t)^2 }\]

&lt;p&gt;This is called the quadratic error term. We “search” parameters m and t that minimize the error.&lt;/p&gt;

&lt;p&gt;Let’s see how the error term behaves for different values:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linspace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linspace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cost_fn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;square&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cost_fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meshgrid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contourf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xlabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;t&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ylabel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;m&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/optim/output_3_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;From the equation of the error and the plot, we see that this is a paraboloid. 
Its curve belongs to the class of &lt;strong&gt;convex curves&lt;/strong&gt;. Finding the optimum is straightforward:&lt;/p&gt;

&lt;p&gt;Before doing this we switch to the matrix vector notation because we can handle the 
sum better in that way.&lt;/p&gt;

\[y = (y_1, ..., y_n)^T\]

&lt;p&gt;\(X = (x_1, ..., x_n)^T\) where \(x_i\) is a 2d vector because we add a “1” with the bias trick.
For example \(x_i = (1, 2.3)^T\)&lt;/p&gt;

&lt;p&gt;\(w = (t, m)^T\) (“weight vector”)&lt;/p&gt;

\[y = X \cdot w^T\]

&lt;p&gt;We want to solve for the parameters w:&lt;/p&gt;

\[w^T = X^{-1} y\]

&lt;p&gt;For the “normal” case where X is a non-square matrix we can use the Moore-Penrose Pseudoinverse with alpha=0:&lt;/p&gt;

\[w^T = (X^T \cdot X)^{-1} \cdot X^T y\]

&lt;p&gt;Note: The result can be proven by differentiating, setting it to zero. \(X\) has to be of full column rank, or else the \(X^T X\) would not be invertible.&lt;/p&gt;

&lt;p&gt;Let’s apply this closed form solution to the data:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;X_bias&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ones&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;X_bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;array([[1.        , 4.79006299],
       [1.        , 3.30198279],
       [1.        , 0.63063158],
       [1.        , 1.58619112],
       [1.        , 3.48292161]])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;X_bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
            &lt;span class=&quot;n&quot;&gt;X_bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_bias&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;array([1.99713 , 0.302953])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is really close to the original parameters 2.0 and 0.3.&lt;/p&gt;

&lt;p&gt;The “goodness” of the ordinary least squares is proven in the &lt;strong&gt;Gauss-Markov Theorem&lt;/strong&gt; under 
the assumptions that X has full column rank, the noise is white, the noise per dimensions all have the same variance and they are uncorrelated. The assumptions about the noise signify that the Covariance Matrix of the noise is a diagonal matrix which is scaled by one single factor.&lt;/p&gt;

&lt;p&gt;It is the best linear unbiased estimator (&lt;strong&gt;BLUE&lt;/strong&gt;) and this estimator is unique.&lt;/p&gt;

&lt;p&gt;Under the assumtion that the noise is normally distributed with a expectation value of zero the method of linear least squares is the same as the linear regression.&lt;/p&gt;

&lt;h3 id=&quot;polynomial-regression&quot;&gt;Polynomial regression&lt;/h3&gt;

&lt;p&gt;The concept of the linear regression can be extended to non-linear curve fitting with a simple trick.
We transform the data points \(X\) into its higher polynomials, perform the usual least sqaures fitting and use the parameters in the higher order model.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uniform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/optim/output_8_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# We treat the polynomials as new dimensions in our data matrix X
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X_poly&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vstack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# The linear regression from above
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linalg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;matmul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;X_poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
            &lt;span class=&quot;n&quot;&gt;X_poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_poly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;beta&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;array([-1.42284625e+02, -5.03193657e+01,  1.79237377e+01,  3.62618409e+00,
       -2.23686147e+00,  1.87793816e+00,  2.53151667e-01, -4.53556005e-02,
       -8.67038500e-03])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;y_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/optim/output_10_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We note that the original parameters were not restored. This is due to the fact that the 
polynomials are highly correlated and different polynomials can form similar curves.&lt;/p&gt;

&lt;p&gt;There is a lot more to say about regression but this text is about optimization which is the reason why I continue with the next topic.&lt;/p&gt;

&lt;h3 id=&quot;optimization-under-constraints&quot;&gt;Optimization under constraints&lt;/h3&gt;

&lt;p&gt;Let’s go through an example: You want to throw a ball over a wall with as little effort as possible.
The ball flies in a parabola. You stand at (x=-5, y=0). The wall is at x=0 with a height of 2.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.08&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.05&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;linspace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/optim/output_12_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The function we want to maximize is the inverse of the parabola because we want it to be as low as possible:&lt;/p&gt;

&lt;p&gt;… (ToDo: Find better example)&lt;/p&gt;

&lt;p&gt;These problems were all &lt;strong&gt;static optimization problems&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Linear opt: linear cost function, linear constraint&lt;/li&gt;
  &lt;li&gt;Quadratic optim.: quadratic cost function, linear constraint&lt;/li&gt;
  &lt;li&gt;Nonlinear optimization: either cost function or a constraint are non linear&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;nonlinear-optimization&quot;&gt;Nonlinear optimization&lt;/h3&gt;

&lt;p&gt;As long as the criteria function f(x) is linear it can be written in linear algebra as a matrix vector product: \(Ax\). Solving these problems comes down to inverting a matrix. There are different ways to do this. It depends on the size of the matrix and its conditioning. For most of the modules availabe these days &lt;strong&gt;LAPACK&lt;/strong&gt;/BLAS takes care of this.&lt;/p&gt;

&lt;p&gt;What can we do if we are facing a nonlinear function? 
Such a term appears for example in the loss function of neural networks.&lt;/p&gt;

&lt;p&gt;Performing local search (which is always iterative):
In this case we sample the value of the error function at the initial point. We could sample a neighbouring point assuming continuity of the function and calculate the difference quotient. But this does not work in practice because of numerical imprecisions.&lt;/p&gt;

&lt;p&gt;What we do instead is to calculate the gradient with backpropagation in our sampled point.&lt;/p&gt;

&lt;p&gt;Why should the gradient be of any interest? A short answer might be: We assumed continuity and therefore we can execute a step into the opposite direction (compare this to the Forward-Euler).&lt;/p&gt;

&lt;p&gt;A longer answer: What we do by using the gradient is that we linearize the nonlinear error surface around our sampled point (we assume the neighbourhood to be a plane). This is a standard linearization which can be justified by the Taylor approximation. The higher order terms are omitted. So the gradient tells us if we make an infinitesimal step into its direction whether the error will be higher or lower.&lt;/p&gt;

&lt;p&gt;Of course the local linearity is not always given. In theory we could for example determine whether a function is Lipschitz-continuous but what would this change? Maybe descrease the step size of gradient descent…&lt;/p&gt;

&lt;p&gt;Another option is Newton’s method which involves the second order of the taylor series expansion. With this method we can make faster progress in flat areas (because we now assume that the error is quadratic) but in general it does not help with arbitrary functions. The Hessian can be used to get the curvature of the surface around the point (&lt;em&gt;conditioning number&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Calculating the Hessian is resource intense. The &lt;strong&gt;Gauss Newton method&lt;/strong&gt; approximates the Hessian with the square of the Jacobian. The rest of it is comparable to the Newton method.&lt;/p&gt;

&lt;p&gt;The Gauss Newton Method can be damped. With this addition the method is called &lt;strong&gt;Levenberg-Marquardt algorithm&lt;/strong&gt; (also called damped least sqaures). The damping factor&lt;/p&gt;

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/personal/python/optimization&quot;&gt;Optimization&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on June 23, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Dead Reckoning 2d]]></title>
  <link>https://danielpollithy.github.io/localization/dead-reckoning</link>
  <id>https://danielpollithy.github.io/localization/dead-reckoning</id>
  <published>2019-05-19T00:00:00+02:00</published>
  <updated>2019-05-19T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;h2 id=&quot;dead-reckoning&quot;&gt;Dead reckoning&lt;/h2&gt;

&lt;p&gt;The following notebook contains a simple implementation of dead reckoning with the 
Explicit and Implicit Euler Method for a bi-cycle given the steering angle and 
velocity at every timestep t.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;math&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;numpy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;explicit-euler-method&quot;&gt;Explicit Euler Method&lt;/h3&gt;

&lt;p&gt;\(X_{k+1} = X_{k} + T \cdot X_{k}'\) where T is the discretization step size.&lt;/p&gt;

&lt;p&gt;The derivative can be approximated by a circular path around the instant center of rotation “ICR”).
\(X_{k}' = ( v \cdot cos(\theta_k) , v \cdot sin(\theta_k) , v \cdot \frac{tan(\alpha_t)}{l})^T\)&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;explicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# explicit euler
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;t_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# velocity and steer at time i
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;v_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;alpha_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.00001&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alpha_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# old X and derivative of old X
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;x_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_dot&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# store values and norm angles only between 0 and 2 pi
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;np_explicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;explicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np_explicits&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;implicit-euler-method&quot;&gt;Implicit Euler Method&lt;/h3&gt;

&lt;p&gt;\(X_{k+1} = X_{k} + T \cdot X_{k+1}'\) yields system of linear equations.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
\[x_{k+1} = x_{k} + T \cdot v \cdot cos(\theta_{k+1})\]
  &lt;/li&gt;
  &lt;li&gt;
\[y_{k+1} = y_{k} + T \cdot v \cdot sin(\theta_{k+1})\]
  &lt;/li&gt;
  &lt;li&gt;
\[\theta_{k+1} = \theta_{k} + T \cdot v \cdot 2 \cdot tan(\alpha_{k+1})\]
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The third equation yields $ \theta_{k+1} $ which can be inserted into the first and second.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;implicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;implicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;t_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ceil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# old state
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;x_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# next control variables
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;alpha_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;v_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# X_k+1
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;theta_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alpha_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;y_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_k_plus_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;theta_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# store values and norm angles only between 0 and 2 pi
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;implicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;theta_k_plus_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;implicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;np_implicits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;implicits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np_implicits&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;visualize_state_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scatter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Xs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;plt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;test-the-functions&quot;&gt;Test the functions&lt;/h2&gt;

&lt;p&gt;Assume a constant velocity and a stair function for steering angles.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c1&quot;&gt;# command variables
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.001&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;180.0&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;180.0&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;explicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;visualize_state_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_7_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_7_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;visualize_state_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_8_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_8_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;x3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;explicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;15.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;visualize_state_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_9_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_9_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;x4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implicit_euler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;15.0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;X_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;visualize_state_sequence&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_10_0.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/dead_reckon/output_10_1.png&quot; alt=&quot;png&quot; /&gt;&lt;/p&gt;


  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/localization/dead-reckoning&quot;&gt;Dead Reckoning 2d&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on May 19, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Harris Corner Detection]]></title>
  <link>https://danielpollithy.github.io/vision/tensorflowjs/harris-corner-detection</link>
  <id>https://danielpollithy.github.io/vision/tensorflowjs/harris-corner-detection</id>
  <published>2019-05-12T00:00:00+02:00</published>
  <updated>2019-05-12T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;script src=&quot;/images/tf.min.js&quot; charset=&quot;utf-8&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;

&lt;link href=&quot;/images/prism.css&quot; rel=&quot;stylesheet&quot; /&gt;

&lt;script src=&quot;/images/prism.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;

&lt;p&gt;This is an interactive demo for the Harris Corner
Detector running in your browser with tensorflow.js.&lt;/p&gt;

&lt;p&gt;The goal is to find points in an image which are corners. These points have Hessians with
large, similar eigenvalues. If only one of the eigenvalues would be large, then the point
might be part of an edge but not a corner.&lt;/p&gt;

&lt;p&gt;Instead of calculating the eigenvalues (which is by the way not straight forward to implement in
tensorflow.js) the authors suggested to calculate a score which is easier
to obtain from the Hessian. They named it the Harris-Cornerness-function f.&lt;/p&gt;

\[f = det(H) - kappa * trace^2 (H)\]

&lt;p&gt;det(H) is equal to the product of the eigenvalues.
And trace(H) is equal to the sum of the eigenvalues.&lt;/p&gt;

&lt;p&gt;Combined in the f value we get an indication about how different and how large
the eigenvalues are.&lt;/p&gt;

&lt;p&gt;See  for more details:
&lt;a href=&quot;https://en.wikipedia.org/wiki/Corner_detection#The_Harris_&amp;amp;_Stephens_/_Plessey_/_Shi%E2%80%93Tomasi_corner_detection_algorithms&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the case you are wondering what this is good for: I am attending multiple
computer vision courses this semester (video analysis, automotive vision,
  deep learning for computer vision) which have some overlaps. In order to practice
  matrix operations and get some visuals I decided to build a collection of demos
  with tensorflow.js that implement the classic cv algorithms.&lt;/p&gt;

&lt;p&gt;Note: Instead of the Hessian H the &lt;strong&gt;structure matrix&lt;/strong&gt; M is used most of the times.
(dy and dy are the gradient in x and y direction):&lt;/p&gt;

\[\begin{pmatrix} dx^2 &amp;amp; dx \cdot dy  \\ dy \cdot dx &amp;amp; dy^2 \end{pmatrix}\]

&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;img src=&quot;/images/left2.jpg&quot; id=&quot;image_left&quot; width=&quot;300px&quot; /&gt;&lt;/td&gt;
    &lt;td&gt;&lt;img src=&quot;/images/right2.jpg&quot; id=&quot;image_right&quot; width=&quot;300px&quot; /&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;canvas id=&quot;canvas_left&quot;&gt;&lt;/canvas&gt;&lt;/td&gt;
    &lt;td&gt;&lt;canvas id=&quot;canvas_right&quot;&gt;&lt;/canvas&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;Harris Corner Settings:&lt;/p&gt;

&lt;p&gt;
&lt;input type=&quot;range&quot; id=&quot;kappa&quot; name=&quot;kappa&quot; style=&quot;width:100%&quot; min=&quot;0.0&quot; max=&quot;0.15&quot; value=&quot;0.004&quot; step=&quot;0.001&quot; oninput=&quot;this.labels[0].innerHTML = 'Kappa='+this.value;&quot; /&gt;
&lt;label for=&quot;kappa&quot;&gt;Kappa&lt;/label&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;input type=&quot;range&quot; id=&quot;threshold&quot; name=&quot;threshold&quot; style=&quot;width:100%&quot; min=&quot;0.0&quot; max=&quot;1.0&quot; value=&quot;0.646&quot; step=&quot;0.001&quot; oninput=&quot;this.labels[0].innerHTML = 'Threshold='+this.value;&quot; /&gt;
&lt;label for=&quot;threshold&quot;&gt;Threshold&lt;/label&gt;
&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;
  &lt;script class=&quot;code language-javascript&quot;&gt;

  /**
   * Expands a gray value plane to a tensor which can be used by conv2d
   */
  function expand_img(tf_img) {
    return tf.expandDims(tf.expandDims(tf_img, axis=0), axis=-1)
  }

  /**
   * Scales the values into [0, 1.0]
   */
  function normalize_tensor(tf_img) {
    var tf_new_image = tf_img.sub(tf.min(tf_img))
    var img_span = tf_new_image.max().sub(tf_new_image.min())
    tf_new_image = tf_new_image.div(img_span)
    return tf_new_image
  }

  /**
   * Approximate the gradient in x direction with the sobel filter x
   */
  function gradient_x(tf_img) {
    let sobel_x = [
      [-1,0,1],
      [-2,0,2],
      [-1,0,1]
    ]
    let tf_sobel_x = tf.tensor2d(sobel_x)
    let expanded_filter_x = tf.expandDims(tf.expandDims(tf_sobel_x, axis=-1), axis=-1)
    let img_deriv_x = tf.conv2d(tf_img, expanded_filter_x, [1,1], 'same', &quot;NHWC&quot; )
    return img_deriv_x;
  }

  /**
   * Approximate the gradient in y direction with the sobel filter y
   */
  function gradient_y(tf_img) {
    let sobel_y = [
      [-1,-2,-1],
      [0,0,0],
      [+1,+2,+1]
    ]
    let tf_sobel_y = tf.tensor2d(sobel_y)
    let expanded_filter_y = tf.expandDims(tf.expandDims(tf_sobel_y, axis=-1), axis=-1)
    let img_deriv_y = tf.conv2d(tf_img, expanded_filter_y, [1,1], 'same', &quot;NHWC&quot; )
    return img_deriv_y;
  }

  /**
   * Calculate Harris Corner detector
   * https://en.wikipedia.org/wiki/Corner_detection#The_Harris_&amp;_Stephens_/_Plessey_/_Shi%E2%80%93Tomasi_corner_detection_algorithms
   */
  function harris(img, canvas_id, kappa, threshold){
    // expand the image for tf.conv2d
    let tf_img = expand_img(img)

    // get the gradients
    let grad_x = gradient_x(tf_img)
    let grad_y = gradient_y(tf_img)

    // 2nd order gradients = hessian matrix
    let gradient_xx = gradient_x(grad_x)
    let gradient_xy = gradient_y(grad_x)
    let gradient_yx = gradient_x(grad_y)
    let gradient_yy = gradient_y(grad_y)

    // hyperparameters
    let kappa_ = tf.scalar(kappa);  // 0.04 - 0.15
    let threshold_ = tf.scalar(threshold);  // 0.5

    // determinant is the product of the eigenvalues
    let determinant = tf.sub(tf.mul(gradient_xx, gradient_yy), tf.mul(gradient_xy, gradient_yx))

    // trace is the sum of the eigenvalues
    let trace = tf.add(gradient_xx, gradient_yy)

    // this function is a surrogate to compare the magnitudes of the eigenvalues
    let harris_cornerness_function = normalize_tensor(tf.sub(determinant, tf.mul(trace, trace).mul(kappa_)))

    // threshold the points of interest
    let harris_filtered = tf.greater(harris_cornerness_function, threshold_).asType('float32')

    // add original image to background and clip the povs to 1.0
    let norm_img = harris_filtered.squeeze().add(normalize_tensor(img).mul(tf.scalar(0.1)))
    norm_img = tf.clipByValue(norm_img, 0.0, 1.0)

    // display the result
    tf.browser.toPixels(norm_img, document.getElementById(canvas_id))
  }

  /**
   * Initialize code ASAP
   */
  window.onload=function(){
    let left_img_element = document.getElementById('image_left');
    let right_img_element = document.getElementById('image_right');

    let img_left = tf.browser.fromPixels(left_img_element)
    let img_right = tf.browser.fromPixels(right_img_element)

    img_left = img_left.mean(2).div(255.0)
    img_right = img_right.mean(2).div(255.0)

    let height = left_img_element.height;
    let width = left_img_element.width;

    harris(img_left, &quot;canvas_left&quot;, 0.005, 0.65);
    harris(img_right, &quot;canvas_right&quot;, 0.005, 0.65);

    let kappa_slider = document.getElementById('kappa')
    let threshold_slider = document.getElementById('threshold')

    function updateImages() {
      let kappa_value = parseFloat(kappa_slider.value)
      let threshold_value = parseFloat(threshold_slider.value);

      harris(img_left, &quot;canvas_left&quot;, kappa_value, threshold_value);
      harris(img_right, &quot;canvas_right&quot;, kappa_value, threshold_value);
    }

    kappa_slider.onchange = updateImages
    threshold_slider.onchange = updateImages
  }
  &lt;/script&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;


  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/vision/tensorflowjs/harris-corner-detection&quot;&gt;Harris Corner Detection&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on May 12, 2019.&lt;/p&gt;</content>
</entry>


<entry>
  <title type="html"><![CDATA[Information theory]]></title>
  <link>https://danielpollithy.github.io/machine-learning/vision/information-theory</link>
  <id>https://danielpollithy.github.io/machine-learning/vision/information-theory</id>
  <published>2019-04-27T00:00:00+02:00</published>
  <updated>2019-04-27T00:00:00+02:00</updated>
  <author>
    <name>Daniel Pollithy</name>
    <uri>https://danielpollithy.github.io</uri>
    <email>daniel@pollithy.com</email>
  </author>
  <content type="html">&lt;p&gt;Whether it is cryptography, automatic speech recognition or computer vision:
Information theory seems to be everywhere in computer science. This post is a
collection of intuitions and formulas.&lt;/p&gt;

&lt;p&gt;Information theory reasons about channels and how to optimally encode messages on a
channel with or without noise.&lt;/p&gt;

&lt;h2 id=&quot;self-information&quot;&gt;Self-Information&lt;/h2&gt;

&lt;p&gt;Imagine that a friend calls you every morning and tells you about the weather
in his hometown. He lives in the desert, therefore 99% of the days he just tells
you that the sun is shining (S). It is really rare that he calls you and it is raining (R).&lt;/p&gt;

&lt;p&gt;We can estimate the probability of what your friend says by maximum likelihood
estimation which essentially means in this case, that we are just counting the
occurrences and divide by the total.&lt;/p&gt;

&lt;p&gt;P(Rain) = 0.01 and P(Sun) = 0.99&lt;/p&gt;

&lt;p&gt;The first thing to realize is that there is an &lt;strong&gt;inverse proportionality&lt;/strong&gt;
between the probability of an event and the &lt;strong&gt;self-information&lt;/strong&gt; \(I\) with \(P \sim 1/I\)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Intuitively we know that the information contained in the unlikely event of
 rain is much more interesting than the sun.&lt;/li&gt;
  &lt;li&gt;If an event has probability 100%, then our code should have length 0 because
we don’t have to communicate anything&lt;/li&gt;
  &lt;li&gt;Improbable events should have longer codes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/log.png&quot; alt=&quot;logarithm&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The negative logarithm seems to be a natural choice for this relationship but we can
justify the usage of the negative logarithm from a better perspective:&lt;/p&gt;

&lt;p&gt;What is the ideal self-information for an event x. For example I(Rain)?
Let’s divide the probability space into subspaces of the size of the smallest
probability unit. So in our example we could draw a rectangle
(which illustrates the probability space omege), divide it into 100 cells of the
same size. Each cell shall be part of an event \(x \in \Omega\).
The more likely the event is, the more space will it cover.
In our example: 99 cells belong to the event Sun and only one cell to the event
Rain.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/probability_space.jpeg&quot; alt=&quot;probability space&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Imagine that we split the probability space recursively at halfs to form a
binary tree. The root in this tree divides the space into two areas with probability
split 50% to 50%. Stepping down into the left subtree has the code symbol “0” attached
and to the right subtree a “1”. The sequence of “0”s and “1”s is what we call the code of the
leaf node where we end up.
We repeat the splitting until the granularity is fine enough to capture the smallest probability
of our events (in our case 1%).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/tree_splitting.jpeg&quot; alt=&quot;tree splitting&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Obviously this depends on the smallest probability. For an Event x with probability P(x)
the amount of cells in the probability space is number_cells = 1/P(x).
For example for rain P(rain) = 0.01 =&amp;gt; number_cells = 1/0.01 = 100&lt;/p&gt;

&lt;p&gt;With the splitting from above we can form a binary tree that has 100 leaf nodes
(rounding errors are omitted). To answer the question for the optimal encoding
for the event “Rain” we only have to find the highest level at which the probability
space is divided fine-granular enough to contain a cell with the correct probability.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/log_tree_information.jpeg&quot; alt=&quot;tree reasoning&quot; /&gt;&lt;/p&gt;

&lt;p&gt;For a binary tree we know that the amount of nodes k at a given depth d is \(k = 2^d\).
We start to count the depth at 0. We can transform this to answer the question about
the depth: \(d = log_{2}{k}\)&lt;/p&gt;

&lt;p&gt;With k=number_cells we get the formula for the self-information I:&lt;/p&gt;

\[I(x) = log_{2}{(\frac{1}{P(x)})}\]

&lt;p&gt;This is equivalent to a more typical form:
\(I(x) = -log_{2}{(P(x))}\)&lt;/p&gt;

&lt;p&gt;Of course we could use a tree with a branching factor different to 2.
The base=2 means that our discrete alphabet has two symbols. We know some
of these alphabets:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;bits/shannons&lt;/strong&gt;: base=2&lt;/li&gt;
  &lt;li&gt;nats: base=e&lt;/li&gt;
  &lt;li&gt;trits: base=3&lt;/li&gt;
  &lt;li&gt;dits/hartleys: base=10&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Self-information tells us the optimal length to encode the event x.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We can calculate the length of the code for a sequence with this.
For example, we might receive the following sequence: “S,S,S,S,S,S,S,S,S,Rain”&lt;/p&gt;

&lt;p&gt;We just have to sum over:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;9 times Sun: 9 times the optimal length for the event sun =&amp;gt; 9 * I(Sun)&lt;/li&gt;
  &lt;li&gt;1 times Rain: 1 * I(Rain)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;shannon-entropy&quot;&gt;Shannon entropy&lt;/h2&gt;

&lt;p&gt;But what if we don’t have a given message and we are just interested in the
general case aka the mean case. So what would be the message length if we
received infinitely many sequences from the channel.&lt;/p&gt;

&lt;p&gt;Until now we only calculate the expected self-information of a single event x.
For example for Rain or Sun. But we know that these two events are transmitted over the same
channel. This is the reason why we might ask ourselves:
&lt;strong&gt;What is the expected information of the whole channel?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We define the random variable \(X\) from which we draw a sequence of
small \(x\). In our example: \(Rain \in X\) and \(Sun \in X\)&lt;/p&gt;

&lt;p&gt;We can rephrase the question from above: What is the expected information drawn
from an event from X. The expectation value means that we infinitely often draw
an event x from X and calculate the mean of the I(x).&lt;/p&gt;

&lt;p&gt;Let’s say we draw n samples with \(n \rightarrow \infty\)&lt;/p&gt;

\[\mathbb{E}_{x \sim P}[I(x)] = 1/n * \sum_{i=1}^{n}{I(x_i)}\]

&lt;p&gt;We can split the sum into |X| different sums (“distinct events of X”). For every event x one sum.
And we know, that every event x should appear P(x) * n times in the sum.
For example if drew 100 events from our friend’s weather sequences we “expect”
that 100 * 0.01 events of rain should be in there. Which is 1.&lt;/p&gt;

\[\begin{equation}
\begin{split}
   \mathbb{E}_{x \sim P}[I(x)]
   &amp;amp; = 1/n * \sum_{i=1}^{n}{I(x_i)} \\
   &amp;amp; = 1/n * \sum_{x_i \in X}{P(x) * n * I(x)} \\
   &amp;amp; = 1/n * n * \sum_{x_i \in X}{P(x) * I(x)} \\
   &amp;amp; = \sum_{x_i \in X}{P(x) * I(x)} \\
   &amp;amp; = H(x)
\end{split}
\end{equation}\]

&lt;p&gt;That’s it! H(x) is called the &lt;strong&gt;Shannon Entropy H(x)&lt;/strong&gt;:&lt;/p&gt;

\[H(x) = \mathbb{E}_{x \sim P}[I(x)] = \sum_{x_i \in X}{P(x) * I(x)}\]

&lt;p&gt;Because the probability distribution P is so central to this measure we denote
the shannon entropy &lt;strong&gt;H(P)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In our example:
H(P) = P(Sun) * I(Sun) + P(Rain) * I(Rain) = 0.99 * log_2(1/0.99) + 0.01 * log_2(1/0.01)
~= 0.08&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;So when your friend calls you the information transmitted is 0.08 bits ;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We observe that a low entropy means that we know what to expect when we draw an
event from a channel. Whereas a low entropy means that there is a high uncertainty.&lt;/p&gt;

&lt;p&gt;This is the reason why entropy is called the &lt;strong&gt;measure of surprise&lt;/strong&gt; of a channel.&lt;/p&gt;

&lt;p&gt;If P is a uniform distribution for example P(rain) = P(sun) = 0.5 then H(P) is
at its maximum which is H(P) = 0.5 * log(1/0.5) + 0.5 * log(1/0.5) = 2 * (0.5 * log(1/0.5))
= 2 * (0.5 * log_2(2)) = 2 * (0.5 * 1) = 2 * 0.5 = 1&lt;/p&gt;

&lt;h2 id=&quot;cross-entropy&quot;&gt;Cross entropy&lt;/h2&gt;

&lt;p&gt;Let’s start with the example again: Imagine that you also have a second friend
who lives in the same town as the first friend. The 2nd friend also calls you
to also tell you the weather every morning.&lt;/p&gt;

&lt;p&gt;Now you are wondering: How many errors happen here? Both sequences should be the
same, therefore the probability distributions P and Q should be equal.
P is estimated from the sequence of the first friend and Q from the 2nd friend.&lt;/p&gt;

&lt;p&gt;We can use the concept of entropy to compare two probability distributions P and Q
over the same random variable X. (It has to be the same random variable, don’t get
this confused with the conditional entropy which I explain in a later part of this
post.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main idea:&lt;/strong&gt; What is the entropy of the sequence of the first friend if we use the
probability distribution Q of the 2nd friend to calculate it.&lt;/p&gt;

\[\begin{equation}
\begin{split}
  H(P,Q) =  \mathbb{E}_{x \sim P}[I_{Q}(x)]
  &amp;amp; = \mathbb{E}_{x \sim P}[log(1/Q(x))] \\
  &amp;amp; = \sum_{x \in X}{P(x) \cdot log(\frac{1}{Q(x)})}
\end{split}
\end{equation}\]

&lt;p&gt;(formula of cross entropy)&lt;/p&gt;

&lt;p&gt;Let’s have a look at three examples to get a feeling for the cross entropy:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First Example: Let’s say that the 2nd friend reports less rain -&amp;gt; Q(Sun) = 0.999, Q(Rain) = 0.001
Then H(P,Q) = P(Sun) * log(1/Q(Sun)) + P(Rain) * log(1/Q(Rain)) =
0.99 * log_2(1/0.999) + 0.01 * log_2(1/0.001) ~= 0.101&lt;/li&gt;
  &lt;li&gt;Second Example: The friends tell you the same things -&amp;gt; P=Q
\(H(P,P) = \sum_{x \in X}{P(x) \cdot log(\frac{1}{P(x)})} = H(P)\)&lt;/li&gt;
  &lt;li&gt;Third example: the 2nd friend reports more rain -&amp;gt; Q(Sun) = 0.981, Q(Rain) = 0.019
Then H(P,Q) = P(Sun) * log(1/Q(Sun)) + P(Rain) * log(1/Q(Rain)) =
0.99 * log_2(1/0.981) + 0.01 * log_2(1/0.019) ~= 0.085&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We observe that the cross entropy is equal to the entropy if P==Q.&lt;/li&gt;
  &lt;li&gt;The function is not symmetric&lt;/li&gt;
  &lt;li&gt;The higher the distance to the entropy, the more are the distributions divergent&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;kullback-leibler-divergence&quot;&gt;Kullback-Leibler divergence&lt;/h2&gt;

&lt;p&gt;We have seen that the cross entropy always contains the entropy:
\(H(P,Q) = H(P) + divergence_of_P_and_Q\)&lt;/p&gt;

&lt;p&gt;This “divergence_of_P_and_Q” is used a lot and has its own name:
&lt;strong&gt;Kullback-Leibler divergence&lt;/strong&gt; \(D_{KL}(P \parallel Q)\).&lt;/p&gt;

\[H(P,Q) = H(P) + D_{KL}(P \parallel Q)\]

&lt;p&gt;Follows:&lt;/p&gt;

\[\begin{equation}
\begin{split}

D_{KL}(P \parallel Q) &amp;amp;= H(P,Q) - H(P) \\
   &amp;amp; = \mathbb{E}_{x \sim P}[I_{Q}(x)] - \mathbb{E}_{x \sim P}[I_{P}(x)] \\  
   &amp;amp; =\mathbb{E}_{x \sim P}[I_{Q}(x) - I_{P}(x)] = \\
   &amp;amp; =\mathbb{E}_{x \sim P}[log (1/Q(x)) - log (1/P(x))] = \\
   &amp;amp; =\mathbb{E}_{x \sim P}[log (\frac{1/Q(x)}{1/P(x)})] = \\
   &amp;amp; =\mathbb{E}_{x \sim P}[log (\frac{\frac{1}{Q(x)}}{\frac{1}{P(x)}})] = \\
   &amp;amp; = \mathbb{E}_{x \sim P}[log \frac{P(x)}{Q(x)}] = \\
   &amp;amp; =\mathbb{E}_{x \sim P}[log(P(x)) - log(Q(x))]   

\end{split}
\end{equation}\]

&lt;p&gt;The last term show that when P and Q are equal, the \(D_{KL}(P \parallel Q)\) becomes zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;From the observation about the cross entropy we can conclude that the KL-divergence
is also not symmetrical -&amp;gt; &lt;strong&gt;therefore it is per definition not a distance measure&lt;/strong&gt;
=&amp;gt; \(D_{KL}(P \parallel Q) \ne D_{KL}(Q \parallel P)\)&lt;/li&gt;
  &lt;li&gt;\(D_{KL}(P \parallel Q)\) is always positive&lt;/li&gt;
  &lt;li&gt;The Kullback-Leibler divergence has a nice intuition for probability distributions.
Namely &lt;strong&gt;how many additional bits do we need to encode a message with the true
probability distribution P if we are using a coding scheme that was developed
using the prob. dist. Q&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;log-loss&quot;&gt;Log loss&lt;/h2&gt;

&lt;p&gt;In machine learning we often use something called the “log loss”. For example
when we train a neural network for classification.
In this case we usually have training data X and a one-hot-encoded label y.
The network gets fed the data X. The data is feed forward through the network.
As a last layer we often find the softmax function which outputs a vector that
sums up to one and every value lies between 0 and 1. This is enough to count as
a probability distribution (although we have not checked the sigma-addition).&lt;/p&gt;

&lt;p&gt;The output of the network after the softmax is denoted ŷ as it is the estimator
for the true label y.
To train the neural network we would like to minimize the difference between y and ŷ.&lt;/p&gt;

&lt;p&gt;We could just compare the two and say that the error is 1 if they are not the
same and 0 if they are. But this would yield a step function which has the
disadvantage of having no gradient at important places. That is bad because we
need the gradient to perform gradient descent…&lt;/p&gt;

&lt;p&gt;Therefore we treat y and ŷ as probability distributions and calculate the cross
entropy between them.&lt;/p&gt;

\[H(Y, Ŷ) = \sum_{class ~ c}{Y(c) \cdot log( \frac{1}{Ŷ(x)} )}\]

&lt;p&gt;Because for classification there is only one correct class, we know that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For all classes which are not the true class c’: \(Y(c)=0\)&lt;/li&gt;
  &lt;li&gt;And for the true class c’: \(Y(c') = 1\)&lt;/li&gt;
&lt;/ul&gt;

\[\begin{equation}
\begin{split}

H(Y, Ŷ) &amp;amp;= Y(c^{'}) * log( \frac{1}{Ŷ(c^{'} )}) \\
           &amp;amp;= 1 * log( \frac{1}{Ŷ(c^{'} )}) \\
           &amp;amp;= log( \frac{1}{Ŷ(c^{'} )}) \\
           &amp;amp;= -log(Ŷ(c^{'}))

\end{split}
\end{equation}\]

&lt;p&gt;The last line is what we call &lt;strong&gt;log loss&lt;/strong&gt;. It can be found everywhere.
In tensorflow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tf.losses.log_loss&lt;/code&gt; or in sckit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sklearn.metrics.log_loss&lt;/code&gt;…&lt;/p&gt;

&lt;p&gt;It has the advantage that we only have to calculate the log of a single value.&lt;/p&gt;

&lt;h2 id=&quot;conditional-entropy&quot;&gt;Conditional entropy&lt;/h2&gt;

&lt;p&gt;With the two mentioned friends you can be pretty sure to know the weather in
the town. We will call the weather in the town “random variable X”.&lt;/p&gt;

&lt;p&gt;Then there is this third friend of you :D She is selling ice cream in the same town.
On a daily basis she informs you whether she sold ice cream today (“Ice”) or not (“No ice”).
We call this random variable Y.&lt;/p&gt;

&lt;p&gt;Now you are wondering:
&lt;strong&gt;How much additional information is necessary to tell whether she sold Ice Cream if we
  have the weather information (X) from the other two friends?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This can be calculated using the conditional entropy H(Y|X). Speak: Y conditioned on X.
Intuitively we can say, if the two events are independent of each others we have
to store the entire sequence of Y as if X did not exist.
If they are the same we don’t have to store anything additionally.&lt;/p&gt;

&lt;p&gt;The formula:&lt;/p&gt;

\[\begin{equation}
\begin{split}

H(Y|X) &amp;amp;=  \sum_{x \in X} {( P(x) \cdot \sum_{y \in Y}{P(y|x) \cdot log( \frac{1}{P(y|x)} )} )}\\
 &amp;amp;=   - \sum_{x \in X} ( P(x) \cdot \sum_{y \in Y}{P(y|x) \cdot log(P(y|x)} ) = \\
 &amp;amp;=   - \sum_{x \in X} (\sum_{y \in Y}{ P(x) P(y|x) \cdot log(P(y| x)} ) = \\
  &amp;amp;=  - \sum_{x \in X} (\sum_{y \in Y}{ P(x,y) \cdot log(P(y|x)} ) = \\
 &amp;amp;=   - \sum_{x \in X, y \in Y}  P(x,y) \cdot logP(y|x) = \\


\end{split}
\end{equation}\]

&lt;p&gt;(conditional entropy)&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/venn_information_theory.jpeg&quot; alt=&quot;information theory venn diagram explained&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;observations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;\(H(Y\vert X) = 0\), if H(Y)=H(X) -&amp;gt; “no additional information”&lt;/li&gt;
  &lt;li&gt;\(H(Y\vert X) = H(Y)\), iff X and Y are independent random variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;joint-entropy&quot;&gt;Joint entropy&lt;/h2&gt;

&lt;p&gt;We can define a random variable Z which is the union of X and Y.
P(Z) = P(X,Y)&lt;/p&gt;

&lt;p&gt;According to this we can “extend” the entropy definition to:&lt;/p&gt;

\[H(Z) = H(X,Y) = \sum_{x \in X, y \in Y}{P(x,y) \cdot I(x,y)}\]

&lt;h2 id=&quot;mutual-information&quot;&gt;Mutual Information&lt;/h2&gt;

&lt;p&gt;The mutual information H(X;Y) is the entropy of the intersection of two random variables X and Y.
It captures the dependence of two variables.&lt;/p&gt;

&lt;p&gt;\(I(X;Y) = MI(X;Y) = H(X) - H(X|Y)\)
(Mutual Infor)&lt;/p&gt;

&lt;p&gt;Mutual information maximization estimation (MMIE) can be used to train speech
recognition systems.&lt;/p&gt;

&lt;h2 id=&quot;perplexity&quot;&gt;Perplexity&lt;/h2&gt;

&lt;p&gt;\(2^{H(P)}\) is called perplexity in speech recognition. It can be interpreted
as the average branching factor in language models (for example a context-sensitive grammar).
The lower the perplexity the less ambiguities have to be resolved by the acoustic
model of the speech recognition system.&lt;/p&gt;

&lt;h2 id=&quot;entropy-distance&quot;&gt;Entropy distance&lt;/h2&gt;

&lt;p&gt;In ASR we got introduced to the entropy distance and the weighted entropy distance.
The context was the Kai-Fu Lee Clustering for subtriphones. For every subtriphone
you have to train a semi-continuous HMM on the pool of Gaussians.
Then we can use the mixture weights of the Gaussians as a probability distribution.
Now we can calculate the entropy distance between two subtriphones to get a
distance measure. The closest subtriphones are merged together. The big advantage
was that we don’t have to train a new HMM for the merged cluster but we can just
calculate the weighted sum of the two probability distributions.&lt;/p&gt;

&lt;p&gt;The entropy distance: \(d(P, Q) = H(P+Q) - 0.5 H(P) - 0.5 H(Q)\)&lt;/p&gt;

&lt;p&gt;The subtriphones differed in the amount of samples in the training data. We want
to trust the clusters with fet data points less than the clusters with many data points.
This is expressed in the weighted entropy distance:&lt;/p&gt;

\[d(P, Q) = (n_{P} + n_{Q})H(P+Q) - n_{P} H(P) - n_{Q} H(Q)\]

  &lt;p&gt;&lt;a href=&quot;https://danielpollithy.github.io/machine-learning/vision/information-theory&quot;&gt;Information theory&lt;/a&gt; was originally published by Daniel Pollithy at &lt;a href=&quot;https://danielpollithy.github.io&quot;&gt;Notes&lt;/a&gt; on April 27, 2019.&lt;/p&gt;</content>
</entry>

</feed>
