<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5829875</id><updated>2026-04-09T08:56:04.049+01:00</updated><category term="research"/><category term="coding"/><category term="opinion"/><category term="learning"/><category term="random"/><category term="puzzle"/><category term="teaching"/><category term="presentation"/><category term="quote"/><category term="meta"/><category term="graphs"/><title type='text'>Theory and Practice</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>273</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5829875.post-8488194732090983879</id><published>2018-04-30T13:52:00.000+01:00</published><updated>2018-05-02T13:59:23.118+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><title type='text'>Weak but Functional Pigeons</title><content type='html'>
&lt;p&gt;
&lt;i&gt;
A bird&#39;s eye view of [Razborov, Resolution Lower Bounds for the Weak Functional Pigeonhole Principle, 2003].
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Resolution refutations are interesting, among other reasons, because they correspond to how SAT solvers work.
A (general) resolution refutation $P$ is a sequence $C_1,\ldots,C_L$ of clauses such that
(a)&amp;nbsp;each clause is either an axiom or the resolution of two previous clauses, and
(b)&amp;nbsp;the last clause is empty.
As usual, a clause is a set of literals, which are possibly negated variables.
The &lt;i&gt;length&lt;/i&gt; $L(P)$ of the refutation $P$ is its number of clauses.
For practical SAT solving algorithms, it is true that if the solver says in time $T$ that the axioms are UNSAT then there exists a resolution refutation $P$ of length $L(P) \le O(T)$.
Conversely, if there exists a resolution refutation $P$ of length $L(P)$, then you &lt;i&gt;may&lt;/i&gt; get lucky and obtain an UNSAT answer from your solver in time $T\le O(L(P))$.

&lt;p&gt;
The resolution rule is the following:
$$
\frac{A\cup\{l\}\qquad \{\bar{l}\}\cup B}{A \cup B}
$$
We erase a literal $l$ and its negation $\bar{l}$, and keep the other literals.

&lt;p&gt;
The first lower bound on $L(P)$ was given by Haken, for resolution refutations $P$ that express the pigeonhole principle: for $m+1$ pigeons and $m$ holes, it is impossible that each pigeon goes in at least a hole and each hole gets at most one pigeon.
The proof is allegedly complicated.
(I should probably read it.)
Some simplification of this and other lower bounds came with [Ben-Sasson, Wigderson, &lt;i&gt;Short proofs are narrow&lt;/i&gt;, JACM2001], which shows that
$$
  w(P&#39;) \le O(\sqrt{n \lg L(P)}) \tag{BW}
$$
where $w(P&#39;)$ is the maximum size of a clause in $P&#39;$ (the &lt;i&gt;width&lt;/i&gt;) and $n$ is the number of variables.
The idea of the proof is as follows &amp;mdash; you give me some refutation $P$ and I&#39;ll give you back a refutation $P&#39;$ of width $O(\sqrt{n \lg L(P)})$ by iterating the following process:
&lt;ol&gt;
&lt;li&gt;find the literal $l$ that occurs most often in clauses longer than the axioms
&lt;li&gt;reorganize the proof to get rid of the said occurrences:
  &lt;ol&gt;
  &lt;li&gt;derive $\bar{l}$
  &lt;li&gt;by resolving with $\bar{l}$, erase $l$ from axioms
  &lt;li&gt;replay old proof but with $l$ removed
  &lt;/ol&gt;
  (these three chunks are concatenated to give a new, thinner refutation)
&lt;/ol&gt;

&lt;p&gt;
From $w \le O(\sqrt{n \lg L})$ and $w \ge \Omega(f(n))$, it follows that $L \ge \Omega\bigl(\exp(\alpha \frac{f(n)^2}{n})\bigr)$ for some $\alpha \gt 0$.
So, lower bounds on width $w \gt \omega(\sqrt{n})$ imply exponential lower bounds on length $L \ge \Omega\bigl( \exp(\alpha n^\beta)\bigr)$ for some $\alpha,\beta \gt 0$.
To finish off the lower bound for pigeons, Ben-Sasson and Wigderson show that indeed $w \ge \Omega(n)$ using some expander stuff that I&#39;m skipping here.
On the other hand, if $w \le O(\sqrt{n})$, then the result $w \le O(\sqrt{n \lg L})$ is of no help in deriving lower bounds on $L$.

&lt;p&gt;
Now let&#39;s get to the subject of this post, the weak and functional pigeonhole principle.
&lt;i&gt;Weak&lt;/i&gt; means that instead of having $m+1$ pigeons we have $p \gt m$ pigeons, where $m$ is the number of holes.
(One may think that if there are lots and lots of pigeons, then you might be able to notice quicker that you can&#39;t find homes for all.
So, potentially, the weak principle might have shorter proofs.)
&lt;i&gt;Functional&lt;/i&gt; means that you put each pigeon not in at least one hole but in &lt;i&gt;exactly&lt;/i&gt; one hole.
(Again, the extra no-pigeon-cloning axioms might make it possible to find shorter refutations.)
It turns out that in this case there are indeed refutations of width $O(\sqrt{n})$, so the (BW) lemma doesn&#39;t help.
That&#39;s where Razborov comes in.

&lt;p&gt;
The general plan is quite similar, except we replace the width by a pseudowidth:
&lt;ol&gt;
&lt;li&gt;upper bound the pseudowidth in terms of the length $L$, and
&lt;li&gt;lower bound the pseudowidth
&lt;/ol&gt;
From 1 and 2, we get a lower bound for the length $L$.

&lt;p&gt;
So, what&#39;s the pseudowidth?
Roughly, it is the number of pigeons that are given many options.
To say that more precisely, we need some notation.
Setting variable $x_{ij}$ means that pigeon $i$ goes in hole $j$.
For the functional principle, it turns out that we can use only positive literals: essentially, we systematically replace $\bar{x}_{ij}$ by $(x_{i1}\lor\ldots\lor x_{i(j-1)})\lor(x_{i(j+1)}\lor\ldots\lor x_{im})$.
Then, we can count how many options is pigeon $i$ given by clause $C$:
$$
d_i(C) \mathrel{:=} |C \cap \{\,x_{ij} : j\in[m]\,\}|
$$
We say that a pigeon has many options if this number is over some fixed threshold which depends on the pigeon.
Let $\mathbf{d}=(d_1,\ldots,d_p)$ be a vector with such thresholds, and let $w_{\mathbf{d}}(C)$ be the number of pigeons that have many options in clause $C$, according to thresholds $\mathbf{d}$.
The pseudowidth of a refutation $P$ is then $w_{\mathbf{d}}(P) \mathrel{:=} \max_{C\in P} w_{\mathbf{d}}(C)$.
Razborov shows that one can always find a thresholds $\mathbf{d}$ such that
$$
w_{\mathbf{d}}(P&#39;) \le O(w_0 + \lg L(P))
$$
More precisely, if we give Razborov a refutation $P$, he can reply with another refutation $P&#39;$ and some thresholds $\mathbf{d}$ such that the above holds.
The catch is that he might introduce a few extra axioms.
In fact, $P&#39;$ is obtained from $P$ by replacing some clauses with $(w_0,\mathbf{d})$-axioms, so $L(P&#39;)=L(P)$.
An &lt;i&gt;$(w_0,\mathbf{d})$-axiom&lt;/i&gt; mentions exactly $w_0$ pigeons, and each pigeon $i$ that is mentioned is given exactly $d_i$ options.
Step 2 of the proof, which lower-bounds the pseudowidth, needs to somehow deal with these extra axioms.

&lt;p&gt;
The main idea of the second part of the proof is to map clauses to certain vector spaces, and look at how the dimension of those spaces grows.
Let $V(C)$ be the vector space associated to clause $C$.
As long as the pseudowidth is below some threshold $O\bigl(\frac{m}{\lg p}\bigr)$, it turns out that new dimensions are seldom added.
More precisely, if a resolution step produces $C$ out of $C_0$ and $C_1$, then
$V(C) \;\subseteq\; V(C_0) + V(C_1)$.
So,
$$\dim V(C) \le \sum_{C&#39;}\dim V(C&#39;)$$
where $C&#39;$ ranges over the axioms used in deriving $C$.
For the original pigeonhole axioms, the dimension is 0.
For the extra axioms introduced in the step 1 of the proof, the dimension is some small number.
For the empty clause, the dimension is some big number.
So, either we reach the big number because we have many extra axioms, which means the refutation is long, or the pseudowidth is $\ge\Omega\bigl(\frac{m}{\lg p}\bigr)$.
In the latter case, we have the lower-bound on pseudowidth that we wanted to obtain in step 2.

&lt;p&gt;
From $\frac{m}{\lg p} \le w_0 + \lg L$ it looks like $L\ge \exp \Omega(\frac{m}{\lg p})$.
The lower bound is in fact only slightly worse:
$$
  L \ge \exp \Omega \biggl( \frac{m}{(\lg p)^2}\biggr)
$$
The reason is the first case, in which many extra axioms are introduced.
To see why, you&#39;d have to look in the paper to see what exactly did I meant by &amp;lsquo;small number&amp;rsquo; and &amp;lsquo;big number&amp;rsquo; in the previous paragraph.

&lt;p&gt;
&lt;b&gt;Nitpick.&lt;/b&gt;
I stop here because the post is already long.
Go read &lt;a href=&quot;https://scholar.google.co.uk/scholar?hl=en&amp;as_sdt=0%2C5&amp;q=resolution+lower+bounds+for+the+weak+functional+pigeonhole+principle&quot;&gt;the paper&lt;/a&gt;: it has some great ideas!
(Although, it does have quite a few small/silly mistakes as well.
Somewhat unusually for me, I did not find them confusing.)

&lt;p&gt;
&lt;b&gt;Edit 20180430:&lt;/b&gt;
Fixed the dimension claim, by making the sum going over axioms.
(Initially, I said that some dimension inequality holds for each resolution step, which is true but too weak for what follows.)
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/8488194732090983879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2018/04/weak-but-functional-pigeons.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8488194732090983879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8488194732090983879'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2018/04/weak-but-functional-pigeons.html' title='Weak but Functional Pigeons'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-8939227255572932939</id><published>2018-04-20T06:16:00.000+01:00</published><updated>2018-04-20T06:16:10.859+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><title type='text'>LYM Inequality</title><content type='html'>&lt;p&gt;
&lt;i&gt;
A simple proof.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
We start with universe $[n]=\{1,\ldots,n\}$, and consider families of sets ${\cal F}\subseteq 2^{[n]}$.
Such a family is called an &lt;i&gt;antichain&lt;/i&gt; when its sets are not related by $\subset$; that is, $F_1 \not\subset F_2$ for all $F_1,F_2\in{\cal F}$.
&lt;a href=&quot;https://en.wikipedia.org/wiki/Sperner%27s_theorem&quot;&gt;Sperner&#39;s Theorem&lt;/a&gt; says that, for any antichain ${\cal F}$,
$$
  |{\cal F}| \le \binom{n}{\lfloor n/2 \rfloor}
$$
and it is a consequence of the more general LYM inequality, which also holds for antichains:
$$
  \sum_{F \in {\cal F}} \binom{n}{|F|}^{-1} \le 1
$$

&lt;p&gt;
It is easy to see that Sperner follows from LYM because $\binom{n}{\lfloor n/2 \rfloor} \ge \binom{n}{k}$ for all $n$ and $k$.
It is perhaps not so easy to see why the LYM inequality holds.
Here is a proof by induction on $n$.
The base case $n=0$ is easy.
Otherwise, we can assume the induction hypothesis
$$
  \sum_{\substack{F\\ F\in{\cal F}\\x\not\in F}} \binom{n-1}{|F|}^{-1}  \le 1
$$
for any $x\in[n]$.
Then
$$
\begin{aligned}
1 \;&amp;amp;\ge\; \frac{1}{n} \sum_{x \in [n]} \sum_{\substack{F\\ F\in{\cal F}\\x\not\in F}} \binom{n-1}{|F|}^{-1}
  &amp;amp;&amp;amp;\text{average induction hypothesis over all $x\in [n]$}
\\\;&amp;amp;=\;
 \frac{1}{n} \sum_{x \in [n]} \sum_{\substack{F\in{\cal F}}} [x\not\in F] \binom{n-1}{|F|}^{-1}
  &amp;amp;&amp;amp;\text{use indicator function $[{\cdot}]$}
\\\;&amp;amp;=\;
 \sum_{\substack{F\in{\cal F}}} \frac{1}{n} \binom{n-1}{|F|}^{-1} \sum_{x \in [n]} [x\not\in F]
  &amp;amp;&amp;amp;\text{swap sums}
\\\;&amp;amp;=\;
 \sum_{\substack{F\in{\cal F}}} \frac{1}{n} \binom{n-1}{|F|}^{-1} (n-|F|)
 &amp;amp;&amp;amp;\text{compute the inner sum}
\\\;&amp;amp;=\;
  \sum_{\substack{F\in{\cal F}}} \binom{n}{|F|}^{-1}
  &amp;amp;&amp;amp;\text{property of binomial coefficients}
\end{aligned}
$$

&lt;p&gt;
We just proved the LYM inequality.
Or did we?
Where did I use that ${\cal F}$ is an antichain?
I didn&#39;t, so the proof above must be wrong.
Can you find the mistake and fix it?
(Hint: The mistake is subtle but silly, the fix is simple.)

&lt;div class=&quot;digression-head&quot;&gt;
&lt;a href=&quot;#&quot; onclick=&quot;return toggleShow(&#39;lym-answer&#39;)&quot;&gt;[toggle answer]&lt;/a&gt;
&lt;div class=&quot;digression-body&quot; id=&quot;lym-answer&quot;&gt;
&lt;p&gt;
The problem is in the step that introduces the indicator function $[{\cdot}]$.
That can be done only if $\binom{n-1}{|F|}\ne 0$.
This happens most of the time, except when $|F|=n$.
Such a case must be treated separately.
If $|F|=n$ then $|{\cal F}|=1$ because ${\cal F}$ is an antichain.
(There &amp;mdash; we used the antichain property.)
Thus, the inequality holds for this case as well.
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/8939227255572932939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2018/04/lym-inequality.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8939227255572932939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8939227255572932939'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2018/04/lym-inequality.html' title='LYM Inequality'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-3385587115291645722</id><published>2017-06-10T07:29:00.000+01:00</published><updated>2017-06-10T07:37:03.250+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><title type='text'>Cap Sets</title><content type='html'>
&lt;p&gt;
&lt;i&gt;
Why it&#39;s difficult to avoid arithmetic progressions.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
The following result was established in 2016:

&lt;p class=&quot;result&quot;&gt;
Let $A$ be a subset of $\mathbb{F}_3^n$
  containing no three-term arithmetic progression.
Then, $|A|=o(2.8^n)$.
&lt;/p&gt;

&lt;p&gt;
This has been described as a
  &lt;a href=&quot;https://www.quantamagazine.org/20160531-set-proof-stuns-mathematicians/&quot;&gt;big breakthrough&lt;/a&gt;.
Yet, the proof is simple enough to fit in 2&amp;nbsp;pages.

&lt;p&gt;
The elements of $\mathbb{F}_3^n$ are vectors with $n$&amp;nbsp;components,
  each component being an integer modulo&amp;nbsp;3.
Vectors $a_1,a_2,a_3$ are said to form a three-term arithmetic progression
  when $a_2-a_1=a_3-a_2$.
Because we are working modulo $3$, this is equivalent to $a_1+a_2+a_3=0$.
Thus, we can rephrase the result as follows.

&lt;p class=&quot;result&quot;&gt;
Let $A$ be a subset of $\mathbb{F}_3^n$
  such that $a_1+a_2+a_3\ne0$ for all distinct $a_1,a_2,a_3\in A$.
Then, $|A|=o(2.8^n)$.
&lt;/p&gt;

&lt;p&gt;
If we were to not require $a_1,a_2,a_3$ to be distinct,
  then the hypothesis would essentially be just &amp;lsquo;false&amp;rsquo;,
  because any nonempty set contains a trivial three-term arithmetic progression
    if we are allowed to pick the same element three times.
An equivalent formulation is to say
  &amp;lsquo;not all equal&amp;rsquo; instead of &amp;lsquo;distinct&amp;rsquo;,
  because $a+a+b \ne 0$ if $a \ne b$.


&lt;p class=&quot;result&quot;&gt;
Let $A$ be a subset of $\mathbb{F}_3^n$
  such that $a_1+a_2+a_3\ne0$ for $a_1,a_2,a_3\in A$ not all equal.
Then, $|A|=o(2.8^n)$.
&lt;/p&gt;

&lt;p&gt;
The overall idea is to find lower and upper bounds for the dimension
  of some vector space of polynomials.
We consider the set $M_n^d$ of monomials over $n$ variables
  that have total degree $\le d$ and all powers from $\{0,1,2\}$.
The restriction on powers is not serious
  because $x^3=x$ by Fermat&#39;s little theorem.
(One may think that $x^2=1$, but that is true only for nonzero $x$.)
Let us write $S_n^d$ for the vector space of polynomials
  written with monomials from $M_n^d$.
We have that $\dim S_n^d=|M_n^d|$;
  let us denote this quantity by $m_d$.
Observe that $m_{\infty}=3^n$;
  indeed, if we allow any total degree,
  then polynomials can represent any function $\mathbb{F}_3^n\to\mathbb{F}_3$,
  by combining indicator polynomials
  $I_a(x)\stackrel{\text{def}}=\prod_{k=1}^n \bigl(1- (x_k-a_k)^2\bigr)$.
&lt;!--
These indicator polynomials form an orthonormal basis for $S_n^{\infty}$,
  with the degenerate inner product
  $P \cdot Q \stackrel{\text{def}}= \sum_{a\in\mathbb{F}_3^n} P(a)Q(a)$.
--&gt;

&lt;p&gt;
We define two subsets of $\mathbb{F}_3^n$:
$$\begin{align}
  X &amp;amp;\stackrel{\text{def}}=
  \{\,a_1+a_2 \mid\text{$a_1,a_2\in A$ distinct}\,\}
\\
  Y &amp;amp;\stackrel{\text{def}}=
  \{\,-a_3 \mid a_3\in A\,\}
\end{align}$$
These sets are disjoint, if $A$ satisfies our hypothesis.
We will consider the subspace $V$ of the polynomials that vanish outside $Y$.
We will derive a lower bound on $\dim V$,
  by simply counting points outside $Y$;
and we will derive an upper bound on $\dim V$,
  using a lemma which says, roughly, that
  &amp;lsquo;any polynomial that is zero on all of $X$ is zero on much of $Y$&amp;rsquo;.
The reasoning will work for an arbitrary $d$;
  when comparing the upper with the lower bound, we shall pick for $d$ a convenient value.


&lt;p&gt;
The bounds we aim to prove are the following:
$$
  m_d - 3^n + |A| \le \dim V \le 2 m_{d/2}
$$

&lt;p&gt;
Let us first see how we use these bounds,
  and we will soon return to how to prove them.
By the correspondence $x^k \leftrightarrow x^{2-k}$,
  we see that monomials of total degree $\le d$
  are in a one-to-one correspondence with monomials of total degree $\ge 2n-d$.
Thus, $m_d$ equals $3^n-m_{2n-d-1}$.
It follows that $|A| \le 2 m_{d/2} + m_{2n-d-1}$.
If we pick $d$ such that $d/2=2n-d-1$, we get $|A| \le 3 m_{(2n-1)/3} \le 3m_{2n/3}$.
Finally, one can show that $m_{2n/3}=o(2.8^n)$.

&lt;div class=&quot;digression&quot;&gt;
&lt;div class=&quot;digression-head&quot;&gt;
Why is $m_{2n/3}=o(2.8^n)$?
&lt;a href=&quot;#&quot; onclick=&quot;return toggleShow(&#39;capsets-bound-on-m&#39;)&quot;&gt;[toggle answer]&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;digression-body&quot; id=&quot;capsets-bound-on-m&quot;&gt;
&lt;p&gt;
We can use a Chernoff bound.
Several useful inequalities involving probabilities have the form
$$
  \Pr(X\in S) \le \mathbb{E}f(X)
$$
where $X$ is a random variable, and $f$ is a function such that $f(x)\ge [x \in S]$.
The notation $[\phi]$ stands for $1$ when $\phi$ holds, and $0$ otherwise.
It is very easy to prove this:
$$\begin{align}
  \Pr(X \in S)
  &amp;amp;
  = \sum_{x} [x \in S] \Pr(X=x)
\\
  &amp;amp;\le \sum_x f(x) \Pr(X=x)
  = \mathbb{E} f(X)
\end{align}$$
We pick $S \stackrel{\text{def}}= \{\,x\mid x\le 0\,\}$
  and $f(x) \stackrel{\text{def}}= e^{-\alpha x}$.
This tells us that $\Pr(X \le 0) \le \mathbb{E} e^{-\alpha X}$ for any $\alpha\ge 0$.
Enough background &amp;ndash; let us move back to $m_{2n/3}$.

&lt;p&gt;
The number $m_{2n/3}$ says in how many ways we can choose $n$ numbers from the set
  $\{0,1,2\}$ such that their sum is $\le 2n/3$.
In other words, $m_{2n/3} = 3^n \cdot \Pr(Y_1+\cdots +Y_n\le 2n/3)$,
  where $Y_1,\ldots,Y_n$ are i.i.d. random variables taking values (uniformly) in
  $\{0,1,2\}$.
If we define $X_k \stackrel{\text{def}}= Y_k-2/3$ and we use the inequality from above, we can calculate
$$\begin{align}
\Pr\biggl(\sum_{i=1}^n Y_i \le \frac{2n}{3}\biggr)
  &amp;amp;
  = \Pr\biggl(\sum_{i=1}^n X_i \le 0\biggr)
  \\&amp;amp;\le
  \mathbb{E} \biggl(e^{-\alpha\sum_{i=1}^n X_i}\biggr)
  =
  \mathbb{E} \biggl( \prod_{i=1}^n e^{-\alpha X_i}\biggr)
  =
  \prod_{i=1}^n \mathbb{E} e^{-\alpha X_i}
  \\&amp;amp;=
  \biggl( \frac{e^{-\frac{4}{3}\alpha}+e^{-\frac{1}{3}\alpha}+e^{\frac{2}{3}\alpha}}{3} \biggr)^n
\end{align}$$
Now we optimize for $\alpha\ge0$, and we get that $m_{2n/3} \lt 2.75510462^n$.
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;
Now let us get back to proving the bounds on $\dim V$.

&lt;p&gt;
The lower bound is easy.
The definition of $V$ is
  $\{\,P\in S_n^d \mid\text{$P(a)=0$ for $a\in \mathbb{F}_3^n\setminus Y$}\,\}$.
The dimension of $S_n^d$ is $m_d$,
  and each of the $|\mathbb{F}_3^n\setminus Y|$ constraints
  reduces the dimension by at most $1$.
Done.

&lt;div class=&quot;digression&quot;&gt;
&lt;div class=&quot;digression-head&quot;&gt;
Why does adding a constraint $P(a)=0$
reduce the dimension by at most $1$?
&lt;a href=&quot;#&quot; onclick=&quot;return toggleShow(&#39;capsets-decrease-dim&#39;)&quot;&gt;
[toggle answer]&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;digression-body&quot; id=&quot;capsets-decrease-dim&quot;&gt;
&lt;p&gt;
Consider a basis $P_1,\ldots,P_k$.
Without loss of generality, we can assume that $P_i(a)\in\{0,1\}$ for all $i$.
We partition $P_1,\ldots,P_k$ based on whether $P_i(a)$ is $0$ or $1$:
  for $Q_1,\ldots,Q_{k_1}$, we have $Q_i(a)=0$ for all $i$;
  for $R_1,\ldots,R_{k_2}$, we have $R_i(a)=1$ for all $i$;
  and $k=k_1+k_2$.
If $k_2=0$, then the dimension is not reduced at all,
  as witnessed by the initial basis $P_1,\ldots,P_k$.
If $k_2\gt 0$, then the dimension is reduced by $1$,
  as witnessed by the basis formed by
    $Q_1,\ldots,Q_{k_1}$
    together with $R_2-R_1,R_3-R_1,\ldots,R_{k_2}-R_1$.
[This is an instance of the &lt;a href=&quot;https://en.wikipedia.org/wiki/Rank%E2%80%93nullity_theorem&quot;&gt;rank-nullity theorem&lt;/a&gt;.]
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;
The upper bound isn&#39;t quite so easy.
My understanding is that the upper bound is the tear that led to the breakthrough.
We&#39;ll do it in two steps, corresponding to these inequalities:
$$
  \dim V \le |\Sigma| \le 2 m_{d/2}
$$
where $\Sigma$ is a maximal support of a polynomial in&amp;nbsp;$V$.

&lt;p&gt;
For the first inequality, we will show the contrapositive:
  if a polynomial $P \in V$ has support $\Sigma$ with $|\Sigma|\lt\dim V$,
  then $\Sigma$ is not maximal.
We do this by finding another polynomial $Q \in V$
  whose support is nonempty and disjoint from $\Sigma$.
The support of $P+Q$ will be a strict superset of $\Sigma$.

&lt;div class=&quot;digression&quot;&gt;
&lt;div class=&quot;digression-head&quot;&gt;
Why does $Q$ exist?
&lt;a href=&quot;#&quot; onclick=&quot;return toggleShow(&#39;capsets-q-exists&#39;)&quot;&gt;[toggle answer]&lt;/a&gt;
&lt;/div&gt;
&lt;div class=&quot;digression-body&quot; id=&quot;capsets-q-exists&quot;&gt;
&lt;p&gt;
We reuse the argument from the previous gray box.
We start with space $V$,
  and each additional constraint $Q(a)=0$ reduces the dimension by at most $1$.
Thus, the space $\{\,Q\in V\mid\text{$Q(a)=0$ for $a\in\Sigma$}\,\}$
  has positive dimension.
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;
For the second inequality,
  we show that &lt;i&gt;any&lt;/i&gt; $P\in V$ has a support of size $\le 2 m_{d/2}$.
I&#39;ll start with an example.
Take $P({\bf x})=x_1 x_2 x_3+x_1^2$.
This is an element of $S_3^3$ because
  we use $3$ variables and the total degree of each monomial is $\le 3$.
The polynomial $P({\bf x}+{\bf y})$ will have monomials
  that use both $x$-variables and $y$-variables,
  but still have total degree $\le 3$:
$$\begin{align}
P({\bf x}+{\bf y})
  =
\left\{
\begin{aligned}
&amp;amp;x_{1} x_{2} x_{3} + x_{2} x_{3} y_{1} + x_{1} x_{3} y_{2} + x_{3} y_{1} y_{2}
\\
&amp;amp;+ x_{1} x_{2} y_{3} + x_{2} y_{1} y_{3} + x_{1} y_{2} y_{3} + y_{1} y_{2} y_{3}
\\
&amp;amp;+ x_{1}^{2} + 2 \, x_{1} y_{1} + y_{1}^{2}
\end{aligned}
\right.
\end{align}$$

&lt;p&gt;
For each monomial,
  in addition to the total degree (the sum of all powers),
  we can define
  an $x$-degree (the sum of all powers on $x$-variables), and
  a $y$-degree (the sum of all powers on $y$-variables).
Since the total degree is $\le3$,
  it follows that the $x$-degree is $\le3/2$ or the $y$-degree is $\le3/2$ (or both).
Let&#39;s put on the first line all those monomials with $x$-degree $\le3/2$,
  and on the second line the rest:

$$
  P({\bf x}+{\bf y}) =
  \left\{
  \begin{aligned}
  &amp;amp;
  x_{3} y_{1} y_{2}
  + x_{2} y_{1} y_{3}
  + x_{1} y_{2} y_{3}
  + y_{1} y_{2} y_{3}
  + 2 x_{1} y_{1}
  + y_{1}^{2}
\\
  &amp;amp;
  + x_{1} x_{2} x_{3}
  + x_{2} x_{3} y_{1}
  + x_{1} x_{3} y_{2}
  + x_{1} x_{2} y_{3}
  + x_{1}^{2}
  \end{aligned}
  \right.
$$

&lt;p&gt;
Now we group monomials on the first line by $x$,
  and we group monomials on the second line by $y$.

$$
  P({\bf x}+{\bf y}) =
  \left\{
  \begin{aligned}
  &amp;amp;
  x_{3} y_{1} y_{2}
  + x_{2} y_{1} y_{3}
  + x_{1} (y_{2} y_{3} + 2 y_1)
  + (y_{1} y_{2} y_{3} + y_{1}^{2})
  \\
  &amp;amp;
  + (x_{1} x_{2} x_{3} + x_1^2)
  + x_{2} x_{3} y_{1}
  + x_{1} x_{3} y_{2}
  + x_{1} x_{2} y_{3}
  \end{aligned}
  \right.
$$

&lt;p&gt;
Introducing some new notation, we can write the above as

$$
  P({\bf x}+{\bf y}) =
  \left\{
  \begin{aligned}
  &amp;amp;
  x_{3} F_{x_3}({\bf y})
  + x_{2} F_{x_2}({\bf y})
  + x_{1} F_{x_1}({\bf y})
  + F_1({\bf y})
  \\
  &amp;amp;
  + G_1({\bf x})
  + y_{1} G_{y_1}({\bf x})
  + y_{2} G_{y_2}({\bf x})
  + y_{3} G_{y_3}({\bf x})
  \end{aligned}
  \right.
$$

&lt;p&gt;
Finally, we instantiate this equality for all $({\bf x},{\bf y})\in A^2$.
For an example, let&#39;s say $A=\{100,020\}$,
  where $100$ is a compact notation for the point $(1,0,0)\in\mathbb{F}_3^3$.
Then,

$$\begin{align}
\begin{bmatrix}
P(100+100) &amp;amp; P(100+020) \\
P(020+100) &amp;amp; P(020+020)
\end{bmatrix}
=
&amp;amp;\begin{bmatrix} 0 \\ 0 \end{bmatrix}_{x_3}
\begin{bmatrix} F_{x_3}(100) &amp;amp; F_{x_3}(020) \end{bmatrix}\\
&amp;amp;+
\begin{bmatrix} 0 \\ 2 \end{bmatrix}_{x_2}
\begin{bmatrix} F_{x_2}(100) &amp;amp; F_{x_2}(020) \end{bmatrix}
+ \cdots
\end{align}$$

&lt;p&gt;
The matrix corresponding to the term $x_3 F_{x_3}({\bf y})$ was factored
  into a column vector corresponding to $x_3$,
  and a row vector corresponding to $F_{x_3}({\bf y})$.

&lt;p&gt;
Of course, we can do the same manipulations for any polynomial $P\in S_n^d$,
  obtaining
$$\begin{align}
  P({\bf x}+{\bf y})
  =
  \sum_{m\in M_n^{d/2}} m({\bf x}) F_m({\bf y})
  +
  \sum_{m\in M_n^{d/2}} m({\bf y}) G_m({\bf x})
\end{align}
$$

&lt;p&gt;
and we can instantiate this equation for all $({\bf x},{\bf y})\in A^2$
  to obtain a matrix identity.
If $P\in V$, which implies that $P$ vanishes on $X$, then its matrix is diagonal.
On the other hand,
  the matrix of each term $m({\bf x})F_m({\bf y})$ has rank&amp;nbsp;1,
  and similarly the matrix of each term $m({\bf y})G_m({\bf x})$.
&lt;a href=&quot;https://math.stackexchange.com/q/59459/512&quot;&gt;
  Because rank is subadditive&lt;/a&gt;,
  the matrix of a $P \in V$ has rank $\le 2 m_{d/2}$,
  which means that it has $\le2m_{d/2}$ nonzero elements on the diagonal.
In other words,
  $P(-a) = P(a + a)\ne 0$ for $\le 2 m_{d/2}$ points $a\in A$.

&lt;p&gt;
This concludes the proof.

&lt;p&gt;
This post follows &lt;a href=&quot;https://arxiv.org/abs/1605.09223&quot;&gt;[Ellenberg, Gijswijt, &lt;i&gt;On large subsets of $F_q^n$ with no three-term arithmetic progression&lt;/i&gt;]&lt;/a&gt;, which presents a slightly more general result, for $\mathbb{F}_q^n$ rather than $\mathbb{F}_3^n$.

&lt;p&gt;
[Stefan Kiefer provided feedback on several drafts of this post. Thanks!]

</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/3385587115291645722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2017/06/cap-sets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/3385587115291645722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/3385587115291645722'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2017/06/cap-sets.html' title='Cap Sets'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-576124000592040577</id><published>2017-05-06T08:07:00.003+01:00</published><updated>2017-05-06T09:44:32.802+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><title type='text'>Open Access</title><content type='html'>&lt;p&gt;
&lt;i&gt;
Preachy post about how I&#39;m not preachy on the subject of open access.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
I believe that scientific knowledge should be free to all.
For me, this is a core value.
Like with other core values,
  I would love if more people would share my opinion,
  but I am not the preacher type.
Nevertheless, I appreciate the work of those who preacher type they are.
Also,
  I think I have the right to act according to my core values,
  as long as I&#39;m not stepping on others&#39;.

&lt;p&gt;
How can we achieve free access to scientific knowledge?
Granted, much of scientific knowledge &lt;i&gt;is&lt;/i&gt; free,
  and the problem is that people aren&#39;t looking for it.
But, still, a significant part of scientific knowledge remains behind paywalls.

&lt;p&gt;
I believe that there is exactly one way
  to achieve true, lasting, and meaningful change:
reach a critical mass of people who hold the core value
  that scientific knowledge should be free.
How do we get there?
There is no royal way.
Multiple tools must be used.
Talk about it.
Write about it.
Change rules and guidelines of organizations.
Set up procedures that make sharing (rather than not sharing) the default.

&lt;p&gt;
But, don&#39;t lose sight of the big picture.
Rules and procedures are not the goal.
Changing hearts and minds is the goal.
And how people act is a barometer of how close we are to the goal.
For example, do people post their articles on arXiv?
Those who don&#39;t
  because it&#39;s slightly inconvenient
  or because they think it&#39;s beneath them and an admin person should do it,
those people are not true believers,
  even though they might be preachers.

&lt;p&gt;
Changing rules and procedures is a tool for achieving change.
Looking at how many papers are easy to access online
  is &lt;i&gt;not&lt;/i&gt; how you measure progress.
Looking at how individuals act is. 

</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/576124000592040577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2017/05/open-access.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/576124000592040577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/576124000592040577'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2017/05/open-access.html' title='Open Access'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-6663932938746289481</id><published>2017-02-07T09:47:00.001+00:00</published><updated>2017-02-07T09:47:48.611+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>POPL 2017</title><content type='html'>&lt;p&gt;
&lt;i&gt;
Some things I learned by attending POPL talks.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
&lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=Monadic+Second+Order+Logic+on+Finite+Sequences&quot;&gt;
Monadic Second Order Logic on Finite Sequences.&lt;/a&gt;&lt;/i&gt;

After two weeks, I do not quite remember what was the main contribution.
I do remember that during this presentation I finally understood symbolic automata.
As you know,
  traditional formalisms, such as finite automata, work over finite alphabets.
If we want to use such formalisms to talk about programs, we have a problem.
Often, we want the letters to be (references to) objects,
  but the number of objects is unbounded.
Other times, we want letters to be integers,
  but the number of integers is also unbounded.
A solution is to take an existing formalism, such as finite automata,
  and extend it to work over infinite alphabets.
One way to do so is to use nominal automata.
Roughly, instead of considering just an alphabet $\Sigma$,
  we also consider a group $G$ that acts on the alphabet,
    and has a finite number of orbits;
  for example, we could take all permutations, $G={\rm Sym}(\Sigma)$.
Then, nominal automata let you define a language $L$ as long as
  it is invariant under $G$&#39;s actions:
  $l_1\ldots l_n \in L$ iff $\pi(l_1)\ldots \pi(l_n) \in L$, for all $\pi \in G$.
Register automata offer a concrete way to think about nominal automata.
In register automata, you have one extra action
  &amp;ndash; you can store the current letter in a register,
  and you also have an extra guard
  &amp;ndash; you can test if the current letter equals the letter in a register.

&lt;p&gt;
An alternative to nominal automata is given by symbolic automata.
Intuitively,
  nominal automata allow you to state requirements that are simple
    (they only involve equality),
  but can talk about several letters in the input word.
Symbolic automata do the converse:
  You are allowed to use an arbitrary logic to express your tests,
  but you may only refer to the current letter when doing so;
  in particular, there is no moral equivalent of the memory.
When I say &amp;lsquo;arbitrary logic&amp;rsquo;,
  I mean that the definition of symbolic automata is modular
  &amp;ndash; you can choose your logic later and you should do so explicitly.

&lt;p&gt;
Now back to the main result.
As I said, I didn&#39;t quite get it
  (or, possibly, I forgot in the two intervening weeks).
But, it was something of the following form.
B&amp;uuml;chi, Elgot, and Trakhtenbrot (1957,1958) showed that MSO over finite words
  defines regular languages,
  by giving a procedure which builds an NFA from an MSO formula.
So, if somebody gives you an MSO formula,
  you can say whether it is satisfiable by building the NFA,
  and checking if its language is nonempty.
Loris D&#39;Antoni and Margus Veanes define a sort of MSO(T)
  &amp;ndash; MSO modulo what you&#39;re allowed to require of the current letter &amp;ndash;
  and then explain how to build a symbolic automaton for that.
Thus, one can check satisfiability of MSO(T),
  assuming that satisfiability(?) in T is decidable.
(BTW, here&#39;s a nice set of slides by Moshe Vardi,
  which mention the result from 1957:
  &lt;a href=&quot;http://movep.lif.univ-mrs.fr/documents/vardi-slides.pdf&quot;&gt;
  Logic, Automata, Games, and Algorithms&lt;/a&gt;.)


&lt;p&gt;
My understanding was also helped by a chat I had with Margus prior the talk.
I bombarded him with questions and he patiently answered all.
I also had a chat with Loris, but mostly about
  &lt;a href=&quot;http://automatatutor.com/&quot;&gt;Automata Tutor&lt;/a&gt;.
I&#39;m happy to report that my son (almost 8 years old now)
  started this week to solve problems from that website.
He thinks it&#39;s fun!
(But his approach is somewhat too random for my taste &amp;hellip;
  although I occasionally observe a spark in his eyes,
  followed by what seems to be the execution of a plan.)

&lt;p&gt;
&lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=LOIS%3A+Syntax+and+Semantics&quot;&gt;
LOIS: Syntax and Semantics
&lt;/a&gt;&lt;/i&gt;
and
&lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=learning+nominal+automata&quot;&gt;
Learning Nominal Automata.&lt;/a&gt;&lt;/i&gt;
LOIS stands for &lt;b&gt;l&lt;/b&gt;ooping &lt;b&gt;o&lt;/b&gt;ver &lt;b&gt;i&lt;/b&gt;nfinite &lt;b&gt;s&lt;/b&gt;ets.
It is an extension of C++ that lets you do what the name says.
Suppose that someone gives you a finite graph $G$ and asks if it is connected.
It is possible to answer this question with a simple program,
  which checks if each vertex $x \in V(G)$ can reach all vertices $V(G)$ of $G$;
that is,
  ${\it connected}(G) := \bigwedge_{x \in V(G)} \bigl({\it reach}(x) = V(G)\bigr)$,
  where $\it reach$ is implemented by BFS or DFS.
I&#39;m not going to write the code, because it&#39;s hopefully clear what I mean.
If we try to run the same code on an infinite graph, though,
  the program won&#39;t terminate.
In fact, we&#39;d also have a termination problem when trying to construct such a graph,
  although we could conceivable &amp;lsquo;solve&amp;rsquo; it by some laziness.
Yet, with LOIS you can use (almost) the same program you use for finite graphs,
  and it will terminate.
For example, you can construct a countably infinite random graph,
  which contains every finite graph as a subgraph,
  and ask whether it is connected.
How does it work?
It does symbolic manipulations.
So, not quite &lt;i&gt;any&lt;/i&gt; infinite set works:
  they must be definable (although I didn&#39;t quite get in which logic).
In particular, sets must be countable.
This restriction is what makes it impossible (unfortunately &amp;#9786;)
  to solve undecidable problems such as universality of register automata.

&lt;p&gt;
You can play with
  &lt;a href=&quot;https://www.mimuw.edu.pl/~erykk/lois&quot;&gt;
  LOIS&#39;s implementation&lt;/a&gt;.

&lt;p&gt;
Finding out whether a random graph is connected seems like an artificial example.
Are there any real applications?
It depends what you mean by &amp;lsquo;real&amp;rsquo;.
But, I can say that there was at least one (other) POPL paper
  can be viewed as an application: &lt;i&gt;Learning Nominal Automata&lt;/i&gt;.
Angluin&#39;s algorithm (1987) learns regular languages by using two queries:
  (1) &amp;lsquo;Is this word in the (secret) language?&amp;rsquo; and
  (2) &amp;lsquo;Does this automaton represent the (secret) language?&amp;rsquo;
Nowadays, as I mentioned, we care about automata that work over infinite alphabets.
It turns out that one can use Angluin&#39;s algorithm unchanged
  (or at least without major modifications &amp;ndash; I&#39;m not sure)
  to learn nominal automata.
The authors do not use LOIS, but another language NLambda.
It also has infinite sets but, as the name implies, it&#39;s functional.

&lt;p&gt;
One of the authors of LOIS is Eryk Kopczyński,
  whose code on Topcoder I used to read regularly more than ten years ago.
Eryk mentioned this puzzle:
Assume that P=NP.
&lt;b&gt;Input&lt;/b&gt;: An NP-complete problem $p$.
&lt;b&gt;Output&lt;/b&gt;: An algorithm that solves (any instance of) $p$ in polynomial time.


&lt;p&gt;
&lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=Component-Based+Synthesis+for+Complex+APIs&quot;&gt;
Component-Based Synthesis for Complex APIs.
&lt;/a&gt;&lt;/i&gt;
You have access to some existing functions,
  and you have to implement a function whose signature is given.
Often, a straight-line program would do.
This paper shows how to automate the task of finding such straight-line programs,
  by doing a search guided by types.
More specifically, the approach is to count.
Suppose you want to write a function with the type ${\rm string}\to{\rm int}$,
  and you have at your disposal two functions:
$$\begin{align*}
  f &amp;amp;: {\rm string} \to {\rm string} * {\rm string} \\
  g &amp;amp;: {\rm string} * {\rm string} * {\rm string} \to {\rm int} \\
\end{align*}$$
You can call $f$ twice and then $g$:
$$\begin{align*}
  &amp;amp;\{\,{\rm string}\,\} \\
  &amp;amp;f \\
  &amp;amp;\{\,{\rm string} * {\rm string}\,\} \\
  &amp;amp;f \\
  &amp;amp;\{\,{\rm string} * {\rm string} * {\rm string}\,\} \\
  &amp;amp;g \\
  &amp;amp;\{\,{\rm int}\,\}
\end{align*}$$
I chose this notation to get across an observation made by Hongseok Yang:
  the method has some similarities to separation logic.
Of course, just counting types has a problem:
In the example above,
  the second call to $f$ has two strings on which we could call it,
  and just by looking at types there&#39;s no way to choose.
Similarly, the last call to $g$ needs to fix some order for the $3$ arguments,
  and types provide no guidance.
In such cases, a human would need to intervene.
The hope is that types are sufficiently precise to make such situations rare.

&lt;p&gt;
The presentation used a formulation in terms of Petri-nets,
  and the synthesis problem as a reachability question.
This is a bit of a red-herring,
  because it makes it sound like the complexity of synthesis is horrible.
However, the synthesis works in a similar way as bounded model-checking:
  it puts a bound on the length of the program and tries to find a solution;
  if it fails, it increases the bound and repeats.

&lt;p&gt;&lt;i&gt;Others&lt;/i&gt;.
I also enjoyed other presentations, but I don&#39;t want to make this post too long.
(Or, rather, I don&#39;t want to spend too long on this post.)
These other presentations include:
  &lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=Thread+Modularity+at+Many+Levels%3A+a+Pearl+in+Compositional+Verification&quot;&gt;
    Thread Modularity at Many Levels: a Pearl in Compositional Verification&lt;/a&gt;&lt;/i&gt;
    (or, &amp;lsquo;how to avoid auxiliary variables
      for the benefit of automation&amp;rsquo;),
  &lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=Polymorphism%2C+subtyping+and+type+inference+in+MLsub&quot;&gt;
    Polymorphism, subtyping and type inference in MLsub&lt;/a&gt;&lt;/i&gt;
    (in which types get rather flexible),
  &lt;i&gt;&lt;a href=&quot;https://scholar.google.com/scholar?q=Exact+Bayesian+Inference+by+Symbolic+Disintegration&quot;&gt;
    Exact Bayesian Inference by Symbolic Disintegration&lt;/a&gt;&lt;/i&gt;
    (sounded a bit like abstract nonsense, but was very entertaining),
  &lt;i&gt;&lt;a href=&quot;https://scholar.google.co.uk/scholar?q=Coupling+proofs+are+probabilistic+product+programs&quot;&gt;
    Coupling proofs are probabilistic product programs&lt;/a&gt;&lt;/i&gt;
    (from which I learned a card &amp;lsquo;trick&amp;rsquo;).
Also, I was happy to see friends; for example, Hongseok:

&lt;p&gt;
&lt;!--
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdyX3f0PlfzmSPWZx5BF6YruFIKJjpqbos3_8iPchmkFSZqPrZELjJirCdkiA0JBa_MYDY26A7NIPpCf0iN2kbNx0BPpgr_hTr43aT-zalGcPjrN0sEgq1BAF9eaiy2dFOKkAl/s1600/hyrg.jpg&quot; imageanchor=&quot;1&quot; style=&quot;clear: left; float: left; margin-bottom: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdyX3f0PlfzmSPWZx5BF6YruFIKJjpqbos3_8iPchmkFSZqPrZELjJirCdkiA0JBa_MYDY26A7NIPpCf0iN2kbNx0BPpgr_hTr43aT-zalGcPjrN0sEgq1BAF9eaiy2dFOKkAl/s320/hyrg.jpg&quot; width=&quot;320&quot; height=&quot;180&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
--&gt;
&lt;img width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdyX3f0PlfzmSPWZx5BF6YruFIKJjpqbos3_8iPchmkFSZqPrZELjJirCdkiA0JBa_MYDY26A7NIPpCf0iN2kbNx0BPpgr_hTr43aT-zalGcPjrN0sEgq1BAF9eaiy2dFOKkAl/s320/hyrg.jpg&quot;/&gt;</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/6663932938746289481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2017/02/popl-2017.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6663932938746289481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6663932938746289481'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2017/02/popl-2017.html' title='POPL 2017'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdyX3f0PlfzmSPWZx5BF6YruFIKJjpqbos3_8iPchmkFSZqPrZELjJirCdkiA0JBa_MYDY26A7NIPpCf0iN2kbNx0BPpgr_hTr43aT-zalGcPjrN0sEgq1BAF9eaiy2dFOKkAl/s72-c/hyrg.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-6835224352429593977</id><published>2015-11-12T16:37:00.001+00:00</published><updated>2015-11-12T19:58:39.513+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Learning from Interpretations</title><content type='html'>&lt;p&gt;
&lt;i&gt;
The LFI-Problog algorithm, for doing inference on probabilistic logic programs.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
This is a brief summary of what I learned from
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=Learning+the+Parameters+of+Probabilistic+Logic+Programs+from+Interpretations&quot;&gt;
  [Gutmann et al.,
  &lt;i&gt;Learning the Parameters of Probabilistic Logic Programs from Interpretations&lt;/i&gt;,
  2011]&lt;/a&gt;.
It&#39;s also an abridged record
  of what I presented in the probabilistic programming reading group at Oxford.
Well, abridged in content but not in presentation.
The presentation here was done in one go.
On the first go, I tend to write rather chatty text, which I don&#39;t like.
But, others say they actually prefer it!
Go figure.
Anyway &amp;hellip;

&lt;p&gt;
ProbLog can be seen as a concise way to describe probability distributions over bitvectors.
Here is an example:

&lt;pre&gt;
  p :: foo(X).
  bar() :- foo(X).
&lt;/pre&gt;

&lt;p&gt;
In addition to the above, we know, from the type of $X$, that $X \in \{1,2\}$.
(In ProbLog it is more complicated,
  but I&#39;ll just assume the types of variables are given and fixed.)
The probability distribution this program describes has the type
  $\bigl(\{{\it foo}(1), {\it foo}(2), {\it bar}() \} \to 2\bigr) \to [0,1]$.
Earlier I said &amp;lsquo;bitvector&amp;rsquo; because this type is isomorphic to $2^3 \to [0,1]$,
  once we fix an order on the atoms ${\it foo}(1)$, ${\it foo(2)}$, ${\it bar}()$.
More precisely, the distribution is the following:

&lt;table border=&quot;1&quot;&gt;
&lt;tr&gt;&lt;th&gt;world&lt;/th&gt;
&lt;td&gt;000&lt;/td&gt;
&lt;td&gt;001&lt;/td&gt;
&lt;td&gt;010&lt;/td&gt;
&lt;td&gt;011&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;td&gt;110&lt;/td&gt;
&lt;td&gt;111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;probability&lt;/th&gt;
&lt;td&gt;$qq$&lt;/td&gt;
&lt;td&gt;$0$&lt;/td&gt;
&lt;td&gt;$0$&lt;/td&gt;
&lt;td&gt;$qp$&lt;/td&gt;
&lt;td&gt;$0$&lt;/td&gt;
&lt;td&gt;$pq$&lt;/td&gt;
&lt;td&gt;$0$&lt;/td&gt;
&lt;td&gt;$pp$&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;
Here, $p$ is the parameter that occurs in the ProbLog program,
  and I used $q$ to denote $1-p$.
The table is produced as follows.
First, identify the input atoms:
  these are the groundings of those facts labeled with probabilities.
In our case, the input atoms are ${\it foo}(1)$ and ${\it foo}(2)$.
Second, give a truth assignment to the input atoms and fix the probability.
For example, if we set ${\it foo}(1)=1$ and ${\it foo}(2)=0$,
  then the probability is $p \times (1-p)$:
  the $p$ for ${\it foo}(1)$ and the $1-p$ for ${\it foo}(2)$.
Finally, complete the world:
  this is done by applying the derivation rules until a fixed-point is reached.
This will be a &lt;i&gt;least&lt;/i&gt; fixed-point, so we say we use least fixed-point semantics.
All the worlds that can&#39;t be generated by this process
  (pick inputs arbitrarily, then do least fixed-point) get probability $0$.

&lt;p&gt;
Note that inputs should not appear as heads of any derivation rule.
Otherwise, you&#39;re in a bit of a pickle if you try to apply the algorithm from above.

&lt;p&gt;
OK, now we have a way to describe probability distributions.
In fact, parameterized probability distributions because $p$ is a parameter.
The next task is to do learning.
And by learning I mean MLE (maximum likelihood estimation).

&lt;p&gt;
What is MLE?
In MLE you observe some event which you assume come from some parameterized distribution,
  and you want to set the parameters to maximize the probability of the observed event.
For example,
  if we observe ${\it foo}(1)=1$ and ${\it foo}(2)=0$,
  then we compute the probability of this event to be $p(1-p)$,
  and we maximize it by taking $p=1/2$.
Or, we could observe just ${\it bar}()=1$,
  which has the probability $1-(1-p)^2=p(2-p)$,
  maximized by taking $p=1$.
In this latter case, we say that ${\it foo}$s are latent (or hidden) variables:
  we need to think about them to compute the probability, but we don&#39;t observe them.

&lt;p&gt;
MLE is very simple in principle,
  but the expression that you&#39;re supposed to optimize becomes unwieldy for examples of even moderate size,
  especially if latent variables are involved.
One general optimization strategy is the EM algorithm.
This is an iterative algorithm, which I&#39;ll illustrate on some examples.

&lt;p&gt;
Look at this table
  which lists for each observation of ${\it foo}(1),{\it foo}(2)$ how we should pick $p$:

&lt;table border=&quot;1&quot;&gt;
&lt;tr&gt;&lt;th&gt;observation&lt;/th&gt;&lt;th&gt;best $p$&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;00&lt;/td&gt;&lt;td&gt;$0$&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;01&lt;/td&gt;&lt;td&gt;$1/2$&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;$1/2$&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;$1$&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;
The best $p$ is the &lt;i&gt;average&lt;/i&gt; of ${\it foo}(0)$ and ${\it foo}(1)$!
But what do we do if we don&#39;t observe the $\it foo$s?
Well, we still have some &lt;i&gt;expectation&lt;/i&gt; for their values,
  given what we observed.

&lt;p&gt;
Let&#39;s see what this means for the case in which we observed ${\it bar}()=1$.
First, we guess $p=1/2$.
Under this guess, $\mathop{\rm E}\bigl({\it foo}(1)\mid {\it bar}()=1\bigr)$ is

$$\begin{align*}
\frac{pq+pp}{qp+pq+pp} = \frac{q+p}{q+q+p} = \frac{1}{1+q} = \frac{2}{3}
\end{align*}$$

&lt;p&gt;
By symmetry, $\mathop{\rm E}\bigl({\it foo}(2)\mid {\it bar}()=1\bigr)$ is also $2/3$.
So, their average is also $2/3$.
(Remember: We take averages of expectations.)
Thus, we update $p:=2/3$ (and $q=1/3$).

&lt;p&gt;
In the next iteration, we do the same, but with the new value of $p$:

$$\begin{align*}
\frac{pq+pp}{qp+pq+pp} = \frac{1}{1+q} = \frac{3}{4}
\end{align*}$$

&lt;p&gt;
If we keep doing this, then we end up with $p=1$,
  which is the same solution we got when we applied MLE directly,
  by maximizing $1-(1-p)^2$.
(You can check that the recurrence from above defines a sequence $q_n=1/n$.
So, when $n\to\infty$ we have $q_n \to 0$ and $p_n \to 1$.)
For the general case,
  you can find a proof in Wikipedia that
  &lt;a href=&quot;https://en.wikipedia.org/wiki/Expectation%E2%80%93maximization_algorithm#Proof_of_correctness&quot;&gt;
  applying one EM step doesn&#39;t reduce the likelihood
  &lt;/a&gt;
  (likelihood = the probability of the observed event).
The proof boils down to Gibbs inequality.
Since likelihood doesn&#39;t decrease, then we may hope it increases.

&lt;p&gt;
The EM algorithm can be seen as some sort of gradient ascent,
  specialized for maximizing likelihoods.
In particular, it is a numeric algorithm, not a symbolic one.


&lt;p&gt;
Let&#39;s see where we are.
We have a language for describing parametrized distributions.
We have a numeric algorithm for estimating good values for the parameters.
Each iteration of the numeric algorithm works by averaging some expectations.
The rest is about how to compute the expectations efficiently.
For this, I&#39;ll switch to a slightly more complicated example &amp;mdash; the one from the paper.

&lt;pre&gt;
  0.1 :: burglary.
  0.2 :: earthquake.
  0.7 :: awake(X).  // X is one of { mary, john }
  alarm :- burglary.
  alarm :- earthquake.
  calls(X) :- awake(X), alarm
&lt;/pre&gt;

&lt;p&gt;
Suppose we observe that ${\it alarm}()=1$ and ${\it calls}({\rm John})=0$.
First, we ground the program.
For efficiency, we also throw away stuff that can&#39;t influence what we observed.
In this case, we throw away &lt;tt&gt;mary&lt;/tt&gt;.

&lt;pre&gt;
  0.1 :: burglary.
  0.2 :: earthquake.
  0.7 :: awake(john).
  alarm :- burglary.
  alarm :- earthquake.
  calls(john) :- awake(john), alarm
&lt;/pre&gt;

&lt;p&gt;
Second, we build a formula whose models are the least fixed-points of the above program;
  that is, the worlds that can have nonzero probability.
This step is very easy if there are no cyclic dependencies.

$$\bigl({\it alarm} \leftrightarrow ({\it burglary} \lor {\it earthquake})\bigr)
\land \bigl({\it calls\_john} \leftrightarrow ({\it awake\_john} \land {\it alarm})\bigr)
$$

&lt;p&gt;
Third, we simplify the formula according to the observation.

$$\begin{align*}
&amp;amp;\bigl(1 \leftrightarrow ({\it burglary} \lor {\it earthquake})\bigr)
\land \bigl(0 \leftrightarrow ({\it awake\_john} \land 1)\bigr)
\\
&amp;amp;\quad=({\it burglary} \lor {\it earthquake}) \land \lnot{\it awake\_john}
\end{align*}$$

&lt;p&gt;
Let $\phi$ be this formula, corresponding to our observation.
We want to compute the expectation $\mathop{\rm E}(f\mid \phi=1)$
  for $f={\it burglary}$ and for $f={\it earthquake}$.
By definition of conditional probabilities (and using $\mathop{\rm E}{X}=\Pr(X=1)$),

$$
\mathop{\rm E} (f \mid \phi=1)
%  = \Pr(f=1\mid \phi=1)
%  = \frac{\Pr(\phi=1\mid f=1) \Pr(f=1)}{\Pr(\phi=1)}
  = \frac{\mathop{\rm E}(\phi\land f)}{\mathop{\rm E}\phi}
$$

&lt;p&gt;
In other words,
  the task is to evaluate the reliability polynomial of $\phi$ and of $\phi\land f$.
Both of these tasks are easy once we have $\phi$ represented as a BDD.
More precisely, they are linear in the size of the BDD.
I expect it is obvious why this is so. :-)
In our case, if the BDD has size $n$, then we would update the parameters in $\sim 4n$ steps:

&lt;ol&gt;
&lt;li&gt;compute $\mathbin{\rm E}\phi$ in $n$ steps
&lt;li&gt;compute $\mathbin{\rm E}(\phi \land {\it burglary})$ in $n$ steps
&lt;li&gt;compute $\mathbin{\rm E}(\phi \land {\it earthquake})$ in $n$ steps
&lt;li&gt;compute $\mathbin{\rm E}(\phi \land {\it awake\_john})$ in $n$ steps
&lt;li&gt;update $p_{\it burglary}:=
  \frac{\mathbin{\rm E}(\phi \land {\it burglary})}{\mathbin{\rm E}\phi}$
  in $1$ step
&lt;li&gt;update $p_{\it earthquake}:=
  \frac{\mathbin{\rm E}(\phi \land {\it earthquake})}{\mathbin{\rm E}\phi}$
  in $1$ step
&lt;li&gt;update $p_{\it awake}:=
  \frac{1}{2}
  \biggl(
  \frac{\mathbin{\rm E}(\phi \land {\it awake\_john})}{\mathbin{\rm E}\phi}
  +p_{\it awake}
  \biggr)$
  in $1$ step.
  (Here we averaged two expectations:
    $\mathbin{\rm E}({\it awake\_john}\mid \phi=1)$ and
    $\mathbin{\rm E}({\it awake\_mary}\mid \phi=1)$.
  The latter is just $\mathbin{\rm E}({\it awake\_mary})=p_{\it awake}$.)
&lt;/ol&gt;

&lt;p&gt;
The final trick is the observation that the four conjoined expectations
  &amp;mdash;
  $\mathbin{\rm E}(\phi\land f)$
  for $f\in\{{\it burglary}, {\it earthquake}, {\it awake\_john}, {\it awake\_mary}\}$
  &amp;mdash;
  can be done all in time linear in the size of the BDD.
More precisely, the time is $O(m+n)$,
  where $m$ is the number of expectations being computed, and $n$ is the size of the BDD.
In the first traversal you construct a slightly improper BDD
  that has each of ${\it burgalry}$, $\it earthquake$, $\it awake\_john$, $\it awake\_mary$
  on every path from root to leaves.
(The paper doesn&#39;t do this.
In fact, in an implementation you wouldn&#39;t do it either.
But, the equivalent computation that avoids constructing this pseudo-BDD
  is slightly annoying to describe.)
Then, you tag each node with two numbers, $\alpha$ and $\beta$.
Both can be understood in terms of downward random walk
  which at a node labeled by $\ell$ takes the 1-branch with probability $\Pr(\ell=1)$.
For example,
  at the node labelled by $\it burglary$ we take the 1-branch
  with probability $p_{\it burglary}$.
Thinking in terms of this random walk,
  the $\alpha$ of node $x$ is the probability that starting at $x$ you end up at a $1$-leaf.
Clearly, these numbers can be filled by one bottom-up traversal of the BDD.
The $\beta$ of node $x$ is the probability that starting at the root we end up visiting $x$.
Clearly, these numbers can be filled by one top-down traversal of the BDD.

&lt;p&gt;
How are these $\alpha$ and $\beta$ tags to be used?
Well, the $\alpha$ on the root is $\mathop{\rm E}\phi$, which we wanted to know.
It is the probability that the formula $\phi$ evaluates to $1$.
We can decompose this probability into a sum over all paths from the root to a $1$-leaf.
When we want to evaluate $\mathbin{\rm E}(\phi\land f)$,
  we are interested in summing only over those paths that have $f=1$.
Since we made sure that all paths test the value of $f$ exactly once,
  we can just look at each node labeled by $f$:

$$
\mathop{\rm E}(\phi\land f) =
  \sum_{\text{$x$ labeled by $f$}} \alpha(x) \beta(x)
$$

&lt;p&gt;
&lt;i&gt;Some comments&lt;/i&gt;.
After reading the paper, I was worried about two things.
First, what do you do if there are cycles in the program?
Second, are these BDDs small enough in practice?
So, I looked up subsequent work, and I saw that both issues are better addressed in
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=Inference+and+Learning+in+Probabilistic+Logic+Programs+using+Weighted+Boolean+Formulas&quot;&gt;
  [Fierens et al.,
  &lt;i&gt;Inference and Learning in Probabilistic Logic Programs using Weighted Boolean Formulas&lt;/i&gt;,
  2015]
  &lt;/a&gt;.
I only skimmed this paper (it&#39;s much longer!), so what I say below about it may be wrong.

&lt;p&gt;
&lt;i&gt;Cycles.&lt;/i&gt;
I was worrying about cycles because they gave me some headache recently,
  while working on
  &lt;a href=&quot;http://arxiv.org/abs/1511.01874&quot;&gt;
  [Grigore, Yang,
  &lt;i&gt;Abstraction Refinement Guided by a Learnt Probabilistic Model&lt;/i&gt;,
  2016]
  &lt;/a&gt;.
The paper by &lt;i&gt;Fierens et al.&lt;/i&gt; gives references to two standard ways to handle cycles.
I don&#39;t think it gives more detail.
Hongseok and I did use one of those methods,
  but we had to throw in a few more approximations and ideas to get something
  that works in any reasonable time.
The reference I like is
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=A+model-theoretic+counterpart+of+loop+formulas&quot;&gt;
  [Lee, &lt;i&gt;A model-theoretic counterpart of loop formulas&lt;/i&gt;, 2005]&lt;/a&gt;.
(The &amp;lsquo;novel&amp;rsquo; part of this paper is supposed to be
  what to do with cycles if you also have negations.
We didn&#39;t use that part.
But, the paper also reviews what you do with cycles when you don&#39;t have negations,
  and I think that review is very readable.)

&lt;p&gt;
By the way, now that I read this article carefully,
  I am convinced that it is &lt;i&gt;very&lt;/i&gt; closely related to the learning part
  in the article by Hongseok and me.
I should write-up some proper, in-depth comparison.

&lt;p&gt;&lt;i&gt;BDD size&lt;/i&gt;.
I was worried about size partly because the problem and a solution
  (automatic theory splitting) are mentioned in the paper I summarize here,
  and partly because I tend to be worried about size when the word &amp;lsquo;BDD&amp;rsquo; is mentioned.
Automatic theory splitting simply means that you decompose the formula into a conjunction
  of parts that don&#39;t share variables,
  and build one BDD for each part,
  rather than one BDD for the whole thing.
I suspect it&#39;s not too often that you can actually do this.
Also, this amounts to using a restricted form of decision-DNNF.
To remind you, a decision-DNNF has two types of nodes:
  a decision node that behave like those in a BDD, and a conjunction node.
The conjunction node requires that its two (decision-DNNF) children don&#39;t share variables.
In general, conjunction nodes and decision nodes can be interspersed.
Automatic theory splitting amounts to disallowing conjunctions below decisions.
The paper by &lt;i&gt;Fierens et al.&lt;/i&gt; doesn&#39;t have this limitation &amp;mdash;
  it uses more results from the area of knowledge compilation to build decision-DNNFs.

&lt;p&gt;
Right, I didn&#39;t say what an &amp;lsquo;interpretation&amp;rsquo; is.
It&#39;s what I call above &amp;lsquo;observation&amp;rsquo;.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/6835224352429593977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/11/learning-from-interpretations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6835224352429593977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6835224352429593977'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/11/learning-from-interpretations.html' title='Learning from Interpretations'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-3157394282646169499</id><published>2015-10-05T12:12:00.003+01:00</published><updated>2015-10-05T15:47:00.294+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Finding Counterexamples from Parsing Conflicts</title><content type='html'>&lt;p&gt;
&lt;i&gt;
How the CUP parser generator explains conflicts.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
I found the abstract of
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=finding+counterexamples+from+parsing+conflicts&quot;&gt;
  [Isradisaikul, Myers, &lt;i&gt;Finding Counterexamples from Parsing Conflicts&lt;/i&gt;, 2015]&lt;/a&gt;
  quite exciting.
After reading the paper, I think it delivers what the title and the abstract promise:
  better errors for parser generators.
If you ever worked with a LR parser generator,
  then you know that sometimes it reports shift/reduce or reduce/reduce conflicts.
The error usually points to a couple of grammar rules and says
  &amp;lsquo;here is the problem&amp;rsquo;.
I never feel like I understand what exactly the problem is
  until I have an example of what could go wrong.
So, once I see the warning/error from the parser generator, I try to come up with examples.
Well, according to this paper, the CUP parser generator &lt;i&gt;gives&lt;/i&gt; you examples.
How cool is that?

&lt;p&gt;
Still, I&#39;m not completely enthusiastic about the paper.
I think the algorithm could be better described.
For example, I would have preferred to see pseudocode.
I realize that it is not easy to add pseudocode,
  and I realize that the pseudocode could be too large to be useful.
But.
I think that adding pseudocode would&#39;ve forced the presentation to be more precise,
  which is a good thing.
I think that striving for small pseudocode would&#39;ve forced isolating the core idea,
  which is a good thing.
The heuristics that embellish the core idea could remain in prose, as they are now.

&lt;p&gt;
Now let&#39;s get technical, a bit.
Recall that the ambiguity problem is in P for NFAs (nondeterministic finite automata),
  and undecidable for CFGs (context free grammars).

&lt;p&gt;
The ambiguity problem for NFAs asks whether there are two runs that accept the same word.
To solve it, we explore pairs $(q_1,q_2)$ of states that can be reached by the same word.
For pairs with $q_1=q_2$ we also care whether they were reached through distinct runs.
Formally, we define a graph that has
  a transition $(q_1,q_2,b) \to (q&#39;_1,q&#39;_2,b&#39;)$
  when the NFA has transitions
    $t_1 = \bigl(q_1 \stackrel{\ell}{\to} q&#39;_1\bigr)$
    and $t_2 = \bigl(q_2 \stackrel{\ell}{\to} q&#39;_2\bigr)$ for some letter $\ell$
  and $b&#39;=b \lor (t_1 \ne t_2)$.
The third component is a boolean that keeps track of whether the runs have diverged.
We then ask if there is a path $(q,q,0) \leadsto (q&#39;,q&#39;,1)$
  with $q$ initial and $q&#39;$ final.
We answer this question with BFS (breadth first search).
If the NFA has $m$ transitions and $n$ states,
  then the graph we defined has $\le 2m^2$ edges and $2n^2$ vertices.
Thus, the BFS takes $O(m^2+n^2)$ time.
This, by the way, you can find in
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=On+Information+Lossless+Automata+of+Finite+Order&quot;&gt;
  [Even, &lt;i&gt;On Information Lossless Automata of Finite Order&lt;/i&gt;, 1965]&lt;/a&gt;.

&lt;p&gt;
(I have posted this previously as a problem
  &lt;a href=&quot;http://rgrig.blogspot.com/2009/09/ambiguity-in-clops.html&quot;&gt;on my blog&lt;/a&gt;
  and
  &lt;a href=&quot;http://www.spoj.com/problems/AMBIG/&quot;&gt;on SPOJ&lt;/a&gt;.
I believe my reference solution for SPOJ is slightly different from what I describe above,
  but I&#39;m too lazy to check.)

&lt;p&gt;
The paper by Isradisaikul and Myers essentially uses the same trick,
  of running two copies of the machine in parallel.
Except in their case, the machine is not an NFA but an LALR parser.
If you wonder how could the problem be undecidable, the answer is simple:
  a LALR parser has an infinite number of configurations, because of the stack.
Now, I should say that many other papers are based on the same trick
  of running two copies in parallel.
What Isradisaikul and Myers do is that they exploit a bit the structure of a LALR parser
  to squeeze some efficiency.

&lt;p&gt;
One thing they do is that they distinguish
  &lt;i&gt;nonunifying&lt;/i&gt; from &lt;i&gt;unifying&lt;/i&gt; counterexamples.
In the terminology from above,
  a nonunifying counterexample is a word that corresponds to
    a path $(q,q,0) \leadsto ({\cdot},{\cdot},1)$ with $q$ initial;
  a unifying counterexample is a word that corresponds to
    a path $(q,q,0) \leadsto (q&#39;,q&#39;,1)$ with $q$ initial and $q&#39;$ final.
The idea is that in some cases you can find where the paths diverge (the &lt;i&gt;conflict&lt;/i&gt;)
  but it&#39;s difficult to find the continuation that gives two different parse trees.
In fact, they give up after some timeout.
(Another way to describe the difference is to say that a unifying counterexample
  remains a counterexample even for a GLR parser.)

&lt;p&gt;
There are other optimizations they propose.
But, frankly, I didn&#39;t parse those carefully.
So, if you want to add better error messages to your favorite parser generator,
  then you&#39;ll have to read the paper yourself, not just this post. :)
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/3157394282646169499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/10/finding-counterexamples-from-parsing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/3157394282646169499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/3157394282646169499'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/10/finding-counterexamples-from-parsing.html' title='Finding Counterexamples from Parsing Conflicts'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-7099938405039323490</id><published>2015-09-19T18:28:00.001+01:00</published><updated>2015-09-21T15:07:57.244+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Verdi</title><content type='html'>&lt;p&gt;
&lt;i&gt;
A system for implementing and verifying distributed algorithms.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
The abstract of the paper
  &lt;a href=&quot;https://scholar.google.com/scholar?q=verdi%3A+a+framework+for+implementing+and+formally+verifying+distributed+systems&quot;&gt;
  [Wilcox et al.,
  &lt;i&gt;Verdi: a Framework for Implementing and Formally Verifying Distributed Systems&lt;/i&gt;,
  PLDI 2015]&lt;/a&gt;
  seemed quite exciting.
Alas, I can&#39;t say I recommend reading the paper.
For my taste, its information density is way too low.
I can&#39;t say that I recommend reading the
  &lt;a href=&quot;https://github.com/uwplse/verdi&quot;&gt;code&lt;/a&gt; either,
  but that&#39;s only because I didn&#39;t read it.
All indications point to it being a cool thing to read.

&lt;p&gt;
One worthwhile thing I learned from the paper is that
  there is a new and cool consensus algorithm:
  &lt;a href=&quot;https://raft.github.io/&quot;&gt;Raft&lt;/a&gt;.
I should probably check it out.

&lt;p&gt;
There is one thing that bugged me from the beginning to the end of the article.
The article states that,

&lt;blockquote&gt;
Verdi&#39;s key conceptual contribution is the use of verified system transformers
  to separate concerns of correctness and fault tolerance.
&lt;/blockquote&gt;

&lt;p&gt;
What does this mean?
Basically, you implement your algorithm assuming the network is perfect.
Then, if you want to run it on a network that, say, stutters,
  you invoke one of these transformers and you get an implementation for a stuttering network.
(And, of course, the proof of correctness gets transformed as well.)
That&#39;s all nice.
But.
But I studied networks in my undergrad degree,
  and I distinctly recall spending endless boring hours discussing
  &lt;b&gt;the&lt;/b&gt; solution to this kind of issues:
  add an abstraction layer.
So, naturally, I was expecting to see how this code transformation approach
  (which, by the way, is a functor) compares to abstraction layers.
Alas, there is no mention of the latter.

&lt;p&gt;
This tension (between the abstraction layers that I expected and the functors I was given)
  reminded me of another paper on my reading list:
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=Deep+Specifications+and+Certified+Abstraction+Layers&quot;&gt;
  [Gu et al., &lt;i&gt;Deep Specifications and Certified Abstraction Layers&lt;/i&gt;, POPL 2015]
  &lt;/a&gt;.
Its abstract seemed to imply that they explain how one is supposed
  to write formal specifications that correspond to the informal idea of abstraction layers.

</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/7099938405039323490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/09/verdi.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/7099938405039323490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/7099938405039323490'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/09/verdi.html' title='Verdi'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-5034057136518633026</id><published>2015-09-12T20:17:00.000+01:00</published><updated>2015-09-12T20:17:43.070+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Push/Pull for Transactions</title><content type='html'>
&lt;p&gt;
&lt;i&gt;
A unified model for understanding many transactional systems.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
There is little doubt about how one should write concurrent programs.
Like in all programming, you must care about correctness first, efficiency second.
If you care about correctness, you do not want to use &lt;i&gt;compare-and-swap&lt;/i&gt;.
You don&#39;t even want to use locks.
What you want to use is &lt;i&gt;atomic&lt;/i&gt; blocks.
When you mark a piece of code as atomic, you effectively say,
  &amp;lsquo;I want to reason about the correctness of this code &lt;i&gt;as if&lt;/i&gt;
    nothing runs concurrently&amp;rsquo;.
Now it is up to the language implementor to ensure that the &lt;i&gt;as if&lt;/i&gt; part holds.
The part of the language implementation that is responsible for this is called
  a &lt;i&gt;transactional system&lt;/i&gt;.

&lt;p&gt;
When the transactional system is implemented,
  there is a similar tension between correctness and efficiency.
At one end of the spectrum,
  one could use a global lock that each atomic block must hold while executing.
This is correct:
  Atomic blocks run &lt;i&gt;as if&lt;/i&gt; nothing runs concurrently
  because &lt;i&gt;nothing&lt;/i&gt; runs concurrently.
(I am assuming that every statement in the program is in an atomic block:
If a statement is not in an atomic block,
  then it is by default wrapped in a tiny atomic block, made just for it.)
At the other end of the spectrum,
  you let everything run concurrently, and pray that there is no interference.
This is really fast.
(And incorrect, obviously.)
Needless to say, no one wants an implementation at either end of the spectrum.
But, crafting something in the middle seems like a dark art.

&lt;p&gt;
This dark art may not remain so dark for long.
At least one recent paper aims to shed some light on it.
The paper is
  [Koskinen, Parkinson, &lt;i&gt;The Push/Pull Model of Transactions&lt;/i&gt;, PLDI 2015].

&lt;p&gt;
Here is how it works.
We start with some underlying sequential language.
It can be pretty much anything: We model its statements as relations on stores.
Then we add a few concurrency features:
  &lt;i&gt;fork&lt;/i&gt;, &lt;i&gt;atomic&lt;/i&gt;, and operations on the shared state.
(The latter are called &lt;i&gt;methods&lt;/i&gt; in the paper.)
Now we have a language for concurrent programming,
  and we can give it an operational semantics,
  which just encodes the intuitive idea that atomic blocks aren&#39;t interrupted by other threads.
This is the reference semantics.

&lt;p&gt;
The second step is to compile a program with atomic blocks into one without.
Instead of atomic blocks,
  we will use a small set of operations,
  the most important of which are &lt;i&gt;push&lt;/i&gt; and &lt;i&gt;pull&lt;/i&gt;.
For this compilation to be correct,
  certain conditions need to hold.
(These conditions appear in Figure 4b as assumptions.
And, by the way, the paper does &lt;i&gt;not&lt;/i&gt; describe this step as &amp;lsquo;compilation&amp;rsquo;.
I do.)

&lt;p&gt;
And here&#39;s the bang.

&lt;p&gt;
As long as the compilation is correct,
  the program with &lt;i&gt;push&lt;/i&gt; and &lt;i&gt;pull&lt;/i&gt; is guaranteed
  to do the same as the given one, the one with &lt;i&gt;atomic&lt;/i&gt;.
This is a big deal because the correctness conditions in Figure 4b are fairly simple,
  and because they allow you to do rather weird-looking stuff.

&lt;p&gt;
Now let&#39;s step back.
I described above my understanding of the paper and its claims.
I think the idea is really cool and useful.
But.

&lt;p&gt;
The paper did not convince me that the conditions in Figure 4b are sufficient.
The authors know this:
They repeatedly say
  that for lack of space they include only a proof sketch,
  and that their proof (from the technical report)
    needs to be checked mechanically in the future.
(By the way,
  the idea of the proof is a bisimulation
  that doesn&#39;t observe the insides of atomic blocks.)
On the one hand, I rather trust Erik and Matt.
  (Although my trust was slightly shaken when I saw that &lt;tt&gt;t&lt;/tt&gt; in Figure 1 is unused.
  Just joking.)
On the other hand, this kind of proof seems extremely brittle.
The authors are right: a mechanically checked proof would be cool.

&lt;p&gt;
Now go see the paper for yourself:
  &lt;a href=&quot;http://researcher.watson.ibm.com/researcher/files/us-ejk/pushpull.pdf&quot;&gt;
  [Koskinen, Parkinson, &lt;i&gt;The Push/Pull Model of Transactions&lt;/i&gt;, PLDI 2015]&lt;/a&gt;.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/5034057136518633026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/09/pushpull-for-transactions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/5034057136518633026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/5034057136518633026'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/09/pushpull-for-transactions.html' title='Push/Pull for Transactions'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-607550279418011933</id><published>2015-07-29T17:11:00.000+01:00</published><updated>2015-07-31T15:45:01.040+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coding"/><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><title type='text'>Coverability for Vector Addition Systems</title><content type='html'>
&lt;p&gt;
&lt;i&gt;
Vector addition systems are a model of computation.
For this model, coverability is one of the easiest decision problems.
This post presents an old (1978) upper bound, with accompanying code.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
A VAS (vector addition system) is a model of computation that pops up occasionally.
In this model, the state is a vector of $d$ nonnegative integers.
At each time step, the state changes from $v$ to $v+\delta$.
The shift $\delta$ is chosen nondeterministically from some given finite set $\Delta$.
If states $V$ are active now, then states $V&#39;$ are active next, where
$$
  V&#39; \;=\; \{\,v+\delta\mid\text{$v \in V$ and $\delta \in \Delta$ and $v+\delta \ge 0$}\,\}
$$
Here&#39;s how you compute $V&#39;$ from $V$ in Python:

&lt;pre class=&quot;prettyprint&quot;&gt;
def check_many(d, vs):
  for v in vs:
    assert d == len(v)
def check_one(d, *vs):
  check_many(d, vs)
def vas_step(d, Delta, vs):
  check_many(d, Delta)
  check_many(d, vs)
  ws = set()
  for v in vs:
    for delta in Delta:
      w = tuple(v[i] + delta[i] for i in range(d))
      if all(wi &amp;gt;= 0 for wi in w):
        ws.add(w)
  return ws
&lt;/pre&gt;

&lt;p&gt;
The reachability problem asks whether there is some run going from $u$ to $w$.
The coverability problem asks whether there is some run going from $u$ to $\ge w$.
Here&#39;s how coverability looks in Python:

&lt;pre class=&quot;prettyprint&quot;&gt;
def LE(u, v):
  assert len(u) == len(v)
  return all(u[i] &amp;lt;= v[i] for i in range(len(u)))
def vas_cover(d, Delta, u, w):
  check_many(d, Delta)
  check_one(d, u, w)
  vs = [u]
  while len(vs) &amp;gt; 0 and not any(LE(w, v) for v in vs):
    vs = vas_step(d, Delta, vs)
  return len(vs) &amp;gt; 0
&lt;/pre&gt;

&lt;p&gt;
For example, the code

&lt;pre class=&quot;prettyprint&quot;&gt;
print(vas_cover(2, [[1,-1], [-2,1]], [3,2], [10,10]))
print(vas_cover(2, [[1,-1], [-1,2]], [3,2], [10,10]))
&lt;/pre&gt;

gives

&lt;pre&gt;
False
True
&lt;/pre&gt;

&lt;p&gt;
The code I gave has a problem, though.
This doesn&#39;t terminate:

&lt;pre class=&quot;prettyprint&quot;&gt;
print(vas_cover(2, [[1,0]], [0,0], [0,1]))
&lt;/pre&gt;

&lt;p&gt;
Can we fix it?
One way to fix it is to stop after some time if we still didn&#39;t find a vector $\ge w$.
But, after how much time?
We can find one answer in
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=the+covering+and+boundedness+problem+for+vector+addition+systems&quot;&gt;[Rackoff,
    &lt;i&gt;The Covering and Boundness Problems for Vector Addition Systems&lt;/i&gt;,
    1978]&lt;/a&gt;.
The bound given by Rackoff depends on $\Delta$ and $w$ but not on $u$.
Let $N$ be the biggest absolute value of a number occurring in $\Delta$ or $w$.
Then it is sufficient to try $L_d$ steps, where
$$\begin{align}
L_0 &amp;amp;= 1 \\
L_k &amp;amp;= (N \cdot L_{k-1})^k + L_{k-1} &amp;amp;&amp;amp;\text{for $k \gt 0$}
\end{align}$$
The bounds $L_0, L_1, L_2, \ldots$
  are of order $N^0, N^1, N^{1 \cdot 2 + 2}, N^{1\cdot 2\cdot 3 + 2\cdot 3+3}, \ldots$;
  very roughly, $L_d \in O(N^{d\cdot d!})$.
Python code again:

&lt;pre class=&quot;prettyprint&quot;&gt;
def rackoff_bound(d, Delta, w):
  check_many(d, Delta)
  check_one(d, w)
  N = max(di for delta in Delta for di in delta)
  bound = 1
  for k in range(1, d + 1):
    bound = (N * bound) ** k + bound
  print(&#39;bound&#39;,bound)
  return bound

def rackoff_vas_cover(d, Delta, u, w):
  check_many(d, Delta)
  check_one(d, u, w)
  vs = [u]
  for i in range(rackoff_bound(d, Delta, w)):
    if any(LE(w, v) for v in vs):
      return True
    vs = vas_step(d, Delta, vs)
  return False
print(rackoff_vas_cover(2, [[1,-1], [-2,1]], [3,2], [10,10]))
print(rackoff_vas_cover(2, [[1,-1], [-1,2]], [3,2], [10,10]))
print(rackoff_vas_cover(2, [[1,0]], [0,0], [0,1]))
&lt;/pre&gt;

&lt;p&gt;
The output:

&lt;pre&gt;
bound 6
False
bound 39
True
bound 6
False
&lt;/pre&gt;

&lt;p&gt;
We can solve the case that previously didn&#39;t terminate, using a bound of 6.
But, &lt;i&gt;why&lt;/i&gt; is this bound sufficient?
Rackoff&#39;s proof uses two tricks: induction on coordinates, and a bounding box.
Let $I \subseteq \{0,1,\ldots,d-1\}$ be a set of coordinate indices.
For a vector $v \in \mathbb{Z}^d$,
  let $v[I] \in \mathbb{Z}^{|I|}$ be its restriction to the coordinates indicated by $I$.
We can lift the same notation to sets of vertices;
  for example, if $\Delta \subset \mathbb{Z}^d$,
  then $\Delta[I] \subset \mathbb{Z}^{|I|}$ and $|\Delta[I]| \le |\Delta|$.
We will prove by induction the following stronger statement:

&lt;blockquote&gt;
Fix the target $w$, and the set of moves $\Delta$.
For all $u$ and $I$,
  if there exists a run from $u[I]$ to $w&#39;[I]$ using moves from $\Delta[I]$
     such that $w&#39;[I]\ge w[I]$,
  then there exists such a run of length $\lt L_{|I|}$.
&lt;/blockquote&gt;

&lt;p&gt;
We will assume there exists a run,
  and we will show that there exists one of length $\lt L_{|I|}$,
  by induction on the size of $I$.

&lt;p&gt;
The base case $|I|=0$ holds because $w&#39;[\emptyset] \ge w[\emptyset]$ always holds.

&lt;p&gt;
For the inductive case, we use a bounding box of size $S$:
  that is, we split runs into those that use only coordinates $\lt S$, and the others.
If all coordinates are $\lt S$, then interesting runs have length $\lt S^{|I|}$.
(If $v_1[I]=v_2[I]$ and $v_1[I] \leadsto v_2[I]$ is a subrun, then we simply cut it out.)
But, maybe it&#39;s not possible to stay within this box.
Then, there is some vertex $v$ that is the first one outside the box.
We cut our run into two pieces, $u[I] \leadsto v[I]$ and $v[I] \leadsto w[I]$,
  which we analyze separately.
The first piece is of length $\lt S^{|I|}$ for the same reason as before.
Let&#39;s move to the second piece, $v[I] \leadsto w[I]$.
Let $I&#39; \subset I$ be those coordinates of $v$ that are still within the bounding box.
Then, by the induction hypothesis,
  there is a run from $v[I&#39;]$ to $w[I&#39;]$ using moves from $\Delta[I&#39;]$ of length $\lt L_{|I&#39;|}$.
What happens with the coordinates $I \setminus I&#39;$?
In $v$ they are $\ge S$, so they can become no smaller than $S-N(L_{|I&#39;|}-1)$.
We would like $w&#39;[I \setminus I&#39;] \ge w[I \setminus I&#39;]$,
  so we pick $S$ such that $S-N(L_{|I&#39;|}-1) \ge N$;
  that is, we pick $S \stackrel{{\rm def}}{=} N \cdot L_{|I|-1}$.
With this choice, we get exactly the inductive case from the definition of $L_k$.

&lt;p&gt;
That concludes the proof.

&lt;p&gt;
&lt;i&gt;Remark&lt;/i&gt;:
Apart from presentation issues,
  there are two minor differences between what I said above
  and what you will find in Rackoff&#39;s paper.
He does the induction on sets of indices of the form $\{0,1,\ldots,k-1\}$
  and justifies this by saying at some point &amp;lsquo;without loss of generality&amp;rsquo;.
That&#39;s perfectly fine once you understand the proof, but it confused me for awhile,
  although I can&#39;t say why.
I decided to just go through all subsets of $\{0,1,\ldots,d-1\}$.
The second is that I measure the length of runs by the number of moves,
  while Rackoff&#39;s paper uses the number of states.
I may have off-by-one errors, so I wasn&#39;t too explicit about this above. :p
(But, if I some such errors slipped through, please let me know
  so I can fix the text and the code.)

&lt;p&gt;
What does this give us?
A coverability algorithm that works in $O(d \cdot |\Delta|^{N^{d\cdot d!}})$ time.
Not terribly fast, but still better than Ackermannian or non-primitive recursive.

&lt;p&gt;
I should say that there are some ways to speed up the algorithm,
  although it probably won&#39;t help with the asymptotics.
One obvious change is to add a test in the loop of
  &lt;code class=&quot;prettyprint&quot;&gt;rackoff_vas_cover&lt;/code&gt;:
  if &lt;code&gt;vs&lt;/code&gt; is empty, then answer &lt;code class=&quot;prettyprint lang-python&quot;&gt;False&lt;/code&gt;.
A less obvious change is to run the whole thing backward.
[&lt;b&gt;update 20150731:&lt;/b&gt;
Actually, there &lt;i&gt;is&lt;/i&gt; a better upper bound for the backward algorithm.
&lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=Complexity+Analysis+for+the+Backward+Coverability+Algorithm+for+VASS&quot;&gt;
[Bozzelli, Ganty, &lt;i&gt;Complexity Analysis for the Backward Coverability Algorithm for VASS&lt;/i&gt;, 2011]&lt;/a&gt;
shows that the runtime of the algorithm below is of the same order of magnitude as $L_d$: doubly-exponential.
Compare their Theorem&amp;nbsp;1 with their Theorem&amp;nbsp;2.
Their Lemma&amp;nbsp;5 describes the algorithm from below, with minor differences.]

&lt;pre class=&quot;prettyprint&quot;&gt;
def vas_cover_backward(d, Delta, u, w):
  check_many(d, Delta)
  check_one(d, u, w)
  vs = [tuple(w)]
  while True:
    if any(LE(v, u) for v in vs):
      return True
    us = set()
    for v1 in vs:
      for delta in Delta:
        u1 = tuple(max(0, v1[i] - delta[i]) for i in range(d))
        if all(not LE(v2, u1) for v2 in vs):
          us.add(u1)
    if len(us) == 0:
      return False
    vs = set(v for v in vs if all(not LE(v, u1) for u1 in us))
    vs |= us
  assert False
print(vas_cover_backward(2, [[1,-1], [-2,1]], [3,2], [10,10]))
print(vas_cover_backward(2, [[1,-1], [-1,2]], [3,2], [10,10]))
print(vas_cover_backward(2, [[1,0]], [0,0], [0,1]))
&lt;/pre&gt;

&lt;p&gt;
After the $k$th iteration, the set &lt;code&gt;vs&lt;/code&gt;
  contains the minimal vectors that can reach $\ge w$ in $\le k$ steps.
I know this algorithm from Sylvain Schmitz
  and from the Section&amp;nbsp;2.2.2 of the
  &lt;a href=&quot;https://cel.archives-ouvertes.fr/cel-00727025v2&quot;&gt;algo-wqo lecture notes&lt;/a&gt;.
[&lt;b&gt;update&lt;/b&gt;: Sylvain also pointed some mistake I had in a previous version of the code.]
The algorithm is presented there in the more general setting of WSTSs
  (well structured transition system).
(A WSTS is essentially a transition system for which $a \le b$ encodes
  what we&#39;d intuitively describe as &amp;lsquo;$b$ is an abstraction of $a$&amp;rsquo;
  in program analysis.)
Since abstraction came into discussion,
  I should say that midway writing this post
  I googled for more recent presentations of Rackoff&#39;s proof.
I found an article that presents the proof in a more general (and abstract!) setting:
  &lt;a href=&quot;https://hal.inria.fr/hal-01176755&quot;&gt;
  [Lazic, Schmitz, &lt;i&gt;The Ideal View of Rackoff&#39;s Coverability Technique&lt;/i&gt;, 2015]
  &lt;/a&gt;.
I didn&#39;t read it, so I don&#39;t know what it says.

&lt;p&gt;
Let&#39;s move to a slightly higher vantage point.
The more complicated the model of computation, the harder its decision problems.
The more precise the question being asked by a decision problem, the harder to answer it.
VASs are more complicated than finite automata, and not too far behind Turing machines.
Coverability is one of the least precise questions one could ask of them,
  and it is doable in exponential space using the algorithms from above.
Reachability is a more precise question, so solving it seems harder.
Its story is in this post by Lipton:
&lt;a href=&quot;https://rjlipton.wordpress.com/2009/04/08/an-expspace-lower-bound/&quot;&gt;
  An EXPSPACE lower bound&lt;/a&gt;.
So, one way to make life harder is by asking more precise questions.
Another way is to make the model of computation more complicated:
  coverability is Ackermann-hard when you add reset
  &lt;a href=&quot;https://scholar.google.com/scholar?hl=en&amp;q=Revisiting+Ackermann-hardness+for+lossy+counter+machines+and+reset+Petri+nets&quot;&gt;
  [Schnoebelen, &lt;i&gt;Revisiting Ackermann-hardness for Lossy Counter Machines
    and Reset Petri-Nets&lt;/i&gt;, 2010]&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/607550279418011933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/07/coverability-for-vector-addition-systems.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/607550279418011933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/607550279418011933'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/07/coverability-for-vector-addition-systems.html' title='Coverability for Vector Addition Systems'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-2728622378843511693</id><published>2015-04-27T23:17:00.001+01:00</published><updated>2015-07-22T15:09:03.288+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Tree Buffers</title><content type='html'>&lt;script src=&quot;http://d3js.org/d3.v3.min.js&quot;&gt;&lt;/script&gt;

&lt;p&gt;
&lt;i&gt;Circular buffers are one of the most fundamental and pervasive data structures.
They are an efficient implementation for buffering linear sequences.
Tree buffers are a more general data structure.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
You heard of circular buffers:
Alice reads out a sequence $x_0$, $x_1$, $x_2$, &amp;hellip; of facts.
Bob&#39;s memory has size&amp;nbsp;$h$, and he stores&amp;nbsp;$x_k$ at address $k \bmod h$.
So, Bob always remembers the &lt;i&gt;last&lt;/i&gt;&amp;nbsp;$h$ facts that Alice read.

&lt;p&gt;
Let&#39;s see one way to generalize the problem.
Instead of reading out a sequence of facts, Alice gives reasons for the stated facts.
In other words, Alice describes a tree, not a sequence.
For example, Alice could describe the tree
&lt;br/&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7fq2mR0LITjYz85vKFEqan4xIkGL7sD50sLihaOLHIToUycimhN4jq6VrrRFp3dSQWPAM9PYLedGfeFGp1_G1uCFQe2eb7SjdjcGZCbSNPJNCEJS9jla66b_tFtTiXlVLTOkV/s1600/tb-fig-0.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7fq2mR0LITjYz85vKFEqan4xIkGL7sD50sLihaOLHIToUycimhN4jq6VrrRFp3dSQWPAM9PYLedGfeFGp1_G1uCFQe2eb7SjdjcGZCbSNPJNCEJS9jla66b_tFtTiXlVLTOkV/s1600/tb-fig-0.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br/&gt;
by saying
$$\begin{align*}
&amp;amp;\text{$0:a$} \\
&amp;amp;\text{$1:b$, follows from $0$}\\
&amp;amp;\text{$2:b$, follows from $0$}\\
&amp;amp;\text{$3:c$, follows from $1$}
\end{align*}$$
Each node has an identifier and a label.
In this example, the identifiers are $0$, $1$, $2$, and $3$,
  but they could be anything that doesn&#39;t repeat.
The labels put on nodes, on the other hand, could repeat.
Indeed, the label $b$ repeats in the example above.
You may think of identifiers as memory addresses, and of labels as memory content.

&lt;p&gt;
Alice could describe the same tree by saying
$$\begin{align*}
&amp;amp;\text{$0:a$} \\
&amp;amp;\text{$2:b$, follows from $0$}\\
&amp;amp;\text{$1:b$, follows from $0$}\\
&amp;amp;\text{$3:c$, follows from $1$}
\end{align*}$$
&lt;!--
On the other hand, saying
$$\begin{align*}
&amp;amp;\text{$0:a$} \\
&amp;amp;\text{$2:b$, follows from $0$}\\
&amp;amp;\text{$3:c$, follows from $1$}\\
&amp;amp;\text{$1:b$, follows from $0$}
\end{align*}$$
would make little sense,
  because Bob would be told that $3$ follows from $1$ before being told about&amp;nbsp;$1$.
--&gt;

&lt;p&gt;
In the case of the circular buffer, Bob recalls only the $h$&amp;nbsp;most recent facts.
What would the equivalent be for trees?
However we define the equivalent, the following properties are desirable:
&lt;ul&gt;
&lt;li&gt;What constitutes a recent fact should depend on the structure of the tree,
  not on the order in which Alice decided to describe the tree.
&lt;li&gt;The case of a skinny, chain-like tree
  should simplify to the case handled by circular buffers.
&lt;/ul&gt;
For example,
  if the last thing Alice said was &amp;lsquo;$y$ follows from $x$&amp;rsquo; (omitting the label of $y$),
  then we&#39;d expect to have in memory $h$ ancestors of $y$.
But, this implies that one timestep ahead, just before Alice said &amp;lsquo;$y$ follows from $x$&amp;rsquo;,
  we must have had in memory $h-1$ ancestors of $x$.
If $x$ can be &lt;i&gt;any&lt;/i&gt; of the nodes that Alice mentioned previously,
  then we must keep in memory all the nodes that Alice mentioned!
We just can&#39;t do better unless we ask for a little help from Alice:
We&#39;d like her to also tell Bob if she isn&#39;t going to add any more children to a node.

&lt;p&gt;
A node is implicitly &lt;i&gt;active&lt;/i&gt; when Alice adds it to the tree,
  then the node possibly receives some children,
  then the node is explicitly made &lt;i&gt;inactive&lt;/i&gt;,
  and then the node receives no more children.
In particular, a node is always active immediately after being added to the tree.
In this context, a natural generalization of the linear case is the following:
Ensure that Bob keeps in memory $h$ recent ancestors for each active node.
Another way to say this is that we want to keep in memory
  those nodes that are at distance $\le h$ from some active node.

&lt;p&gt;
Of course, Bob would like to not keep in memory much more than necessary.
Also, Bob wants to process each message from Alice in &lt;i&gt;constant time&lt;/i&gt;.
Can he do this?
The task is difficult because one message from Alice may change the height of &lt;i&gt;many&lt;/i&gt; nodes
  &amp;mdash; too many to process in constant time.
You can check this by playing with the tree below.

&lt;p&gt;(&lt;b&gt;Update:&lt;/b&gt; The &lt;a href=&quot;http://rgrig.appspot.com/static/talks/treebuffers/index.html&quot;&gt;slides from CAV2015&lt;/a&gt; have a better click-and-see interface.)&lt;/p&gt;

&lt;p&gt;
&lt;b&gt;Instructions&lt;/b&gt;:
Click on a green node to add a child.
Control-click a green node to deactivate it.
The $h$ is fixed to be $3$.
The nodes are labeled by their distance to an active node.
The green nodes are active,
  the yellow nodes are inactive but needed,
  the red nodes are not needed.
Example: To simulate a linear buffer, repeatedly do the following:
  (1) click on the green node,
  (2) control-click on the same node.

&lt;div id=&quot;treebuffer-playground&quot;&gt;&lt;/div&gt;

&lt;p&gt;
Yet, Bob can do it!
For details,
  see the
  &lt;a href=&quot;http://arxiv.org/abs/1504.04757&quot;&gt;paper&lt;/a&gt;
  and the
  &lt;a href=&quot;https://github.com/rgrig/treebuffers&quot;&gt;code&lt;/a&gt;.
There, you will also find a generic application for this data structure:
  tracing nondeterministic automata, not necessarily finite.
This application has special cases like
&lt;ul&gt;
&lt;li&gt;providing error traces during runtime verification, and
&lt;li&gt;providing functionality similar to that of regexp capturing groups
&lt;/ul&gt;

&lt;!-- RG: stolen from http://bl.ocks.org/NPashaP/7683252, and modified --&gt;
&lt;style&gt;
circle {
  stroke : black;
  stroke-width:2px;
}
line {
  stroke:grey;
  stroke-width:3px;
}
#treesvg g text:hover, #treesvg g circle:hover{
        cursor:pointer;
}
#navdiv{
        width : 600px;
}
#treesvg{
        border:1px solid grey;
}
#navdiv button, #navdiv textarea{
        width : 600px;
        vertical-align:middle;
}
#g_labels text{
        text-anchor:middle;
}
&lt;/style&gt;
&lt;script&gt;
function make_tree() {
  var svgW = 600, svgH = 700, vRad = 12
  var tree = { cx : svgW / 2, cy : 30, w : 40, h : 70 }
  tree.HEIGHT = 3

  reset = function() {
    tree.vis = { v : 0, l : 0, a : true, p : { x : tree.cx, y : tree.cy }, c : [] }
    tree.size = 1
  }

  tree.getVertices = function() {
    var v = []
    function getVertices(t, f) {
      v.push({ v : t.v, l : t.l, p : t.p, f : f } )
      t.c.forEach(function(child) {
         getVertices(child, { v : t.v, p : t.p })
      })
    }
    getVertices(tree.vis, { p : tree.vis.p })
    return v.sort(function(a,b){ return a.v - b.v;})
  }

  tree.getEdges = function() {
    var e =[];
    function getEdges(_){
      _.c.forEach(function(d){ e.push({v1:_.v, l1:_.l, p1:_.p, v2:d.v, l2:d.l, p2:d.p});});
      _.c.forEach(getEdges);
    }
    getEdges(tree.vis);
    return e.sort(function(a,b){ return a.v2 - b.v2;});
  }

  modifyVertex = function(id, f) {
    function mv(t) {
      if (t.v == id) f(t)
      t.c.forEach(mv)
    }
    mv(tree.vis)
  }

  tree.addLeaf = function(v){
    modifyVertex(v, function (t) {
      if (t.a) {
        t.c.push({ v : tree.size++, l : 0, a : true, p : {}, c : [] })
      }
    })
    reposition(tree.vis)
    relabel()
    redraw()
  }

  tree.deactivate = function(id) {
    modifyVertex(id, function(vertex) { vertex.a = false })
    relabel()
    redraw()
  }

  clickHandler = function(vertex) {
    if (d3.event.ctrlKey) {
      tree.deactivate(vertex)
    } else {
      tree.addLeaf(vertex)
    }
  }

  relabel = function() {
    function relbl(t) {
      t.c.forEach(relbl)
      if (t.a) {
        t.l = 0
      } else {
        t.l = 1000
        t.c.forEach(function(child) { t.l = Math.min(t.l, child.l) })
        t.l += 1
      }
    }
    relbl(tree.vis)
  }

  vertexcolor = function(vertex) {
    if (vertex.l == 0) {
      return &#39;#afa&#39;
    } else if (vertex.l &lt;= tree.HEIGHT) {
      return &#39;#ffa&#39;
    } else {
      return &#39;#faa&#39;
    }
  }

  vertextext = function(vertex) {
    if (vertex.l &gt;= 1000) return &#39;&#39;
    return vertex.l
  }

  redraw = function() {
    var edges = d3.select(&quot;#g_lines&quot;).selectAll(&#39;line&#39;).data(tree.getEdges())
    edges.transition().duration(500)
      .attr(&#39;x1&#39;,function(d){ return d.p1.x;}).attr(&#39;y1&#39;,function(d){ return d.p1.y;})
      .attr(&#39;x2&#39;,function(d){ return d.p2.x;}).attr(&#39;y2&#39;,function(d){ return d.p2.y;})
    edges.enter().append(&#39;line&#39;)
      .attr(&#39;x1&#39;,function(d){ return d.p1.x;}).attr(&#39;y1&#39;,function(d){ return d.p1.y;})
      .attr(&#39;x2&#39;,function(d){ return d.p1.x;}).attr(&#39;y2&#39;,function(d){ return d.p1.y;})
      .transition().duration(500)
      .attr(&#39;x2&#39;,function(d){ return d.p2.x;}).attr(&#39;y2&#39;,function(d){ return d.p2.y;})
    edges.exit().remove()

    var circles = d3.select(&quot;#g_circles&quot;).selectAll(&#39;circle&#39;).data(tree.getVertices())
    circles.transition().duration(500)
      .attr(&#39;cx&#39;,function(d){ return d.p.x })
      .attr(&#39;cy&#39;,function(d){ return d.p.y })
      .style(&#39;fill&#39;, vertexcolor)
    circles.enter().append(&#39;circle&#39;)
      .attr(&#39;cx&#39;, function(d) { return d.f.p.x })
      .attr(&#39;cy&#39;,function(d){ return d.f.p.y })
      .style(&#39;fill&#39;, vertexcolor)
      .attr(&#39;r&#39;, vRad)
      .on(&#39;click&#39;,function(d){ return clickHandler(d.v) })
      .transition().duration(500)
      .attr(&#39;cx&#39;,function(d){ return d.p.x })
      .attr(&#39;cy&#39;,function(d){ return d.p.y })
      .style(&#39;fill&#39;, vertexcolor)
    circles.exit().remove()

    var labels = d3.select(&quot;#g_labels&quot;).selectAll(&#39;text&#39;).data(tree.getVertices())
    labels.text(vertextext).transition().duration(500)
      .attr(&#39;x&#39;,function(d){ return d.p.x })
      .attr(&#39;y&#39;,function(d){ return d.p.y+5 })
    labels.enter().append(&#39;text&#39;)
      .attr(&#39;x&#39;,function(d){ return d.f.p.x })
      .attr(&#39;y&#39;,function(d){ return d.f.p.y+5 })
      .text(vertextext)
      .on(&#39;click&#39;,function(d){return clickHandler(d.v);})
      .transition().duration(500)
      .attr(&#39;x&#39;,function(d){ return d.p.x })
      .attr(&#39;y&#39;,function(d){ return d.p.y+5 })
    labels.exit().remove()
  }

  getLeafCount = function(_){
    if(_.c.length == 0) {
      return 1
    } else {
      return _.c.map(getLeafCount).reduce(function(a,b){ return a+b })
    }
  }

  reposition = function(v) {
    var lC = getLeafCount(v), left = v.p.x - tree.w*(lC-1)/2
    v.c.forEach(function(child) {
      var w = tree.w * getLeafCount(child)
      left += w
      child.p = { x : left-(w+tree.w)/2, y : v.p.y+tree.h }
      reposition(child)
    })
  }

  initialize = function() {
    reset()
    d3.select(&quot;#treebuffer-playground&quot;).append(&quot;div&quot;).attr(&#39;id&#39;, &#39;navdiv&#39;)
    d3.select(&quot;#navdiv&quot;)
      .append(&quot;button&quot;).attr(&#39;type&#39;, &#39;button&#39;).text(&#39;Reset&#39;)
      .on(&#39;click&#39;, function(_) { reset(); redraw() })
    d3.select(&quot;#treebuffer-playground&quot;)
      .append(&quot;svg&quot;).attr(&quot;width&quot;, svgW).attr(&quot;height&quot;, svgH)
      .attr(&#39;id&#39;, &#39;treesvg&#39;)
    d3.select(&quot;#treesvg&quot;).append(&#39;g&#39;).attr(&#39;id&#39;, &#39;g_lines&#39;)
    d3.select(&quot;#treesvg&quot;).append(&#39;g&#39;).attr(&#39;id&#39;, &#39;g_circles&#39;)
    d3.select(&quot;#treesvg&quot;).append(&#39;g&#39;).attr(&#39;id&#39;, &#39;g_labels&#39;)
    redraw()
  }

  initialize();
  return tree;
}
var tree = make_tree()
&lt;/script&gt;</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/2728622378843511693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/04/tree-buffers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2728622378843511693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2728622378843511693'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/04/tree-buffers.html' title='Tree Buffers'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7fq2mR0LITjYz85vKFEqan4xIkGL7sD50sLihaOLHIToUycimhN4jq6VrrRFp3dSQWPAM9PYLedGfeFGp1_G1uCFQe2eb7SjdjcGZCbSNPJNCEJS9jla66b_tFtTiXlVLTOkV/s72-c/tb-fig-0.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-5526594312629167938</id><published>2015-04-03T18:32:00.000+01:00</published><updated>2015-04-07T06:59:14.985+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>RIP Herman Conjecture (2005-2015)</title><content type='html'>&lt;p&gt;
&lt;i&gt;In 1990, Herman proposed a sweet self-stabilizing protocol.
In 2005, McIver and Morgan conjectured that its running time is $\frac{4}{27} N^2$.
Well &amp;hellip; they were right.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Do you remember playing tag as a kid?
What about hide-and-seek?
Of course you do.
In these games one kid is special:
  the one running after others in tag, or the seeker in hide-and-seek.
(Although &amp;lsquo;unlucky&amp;rsquo; would perhaps be a better word.)
The game usually has rules for picking this kid.
For example, the seeker is the person first found on the previous round of the game.
The problem is that these rules don&#39;t apply to the first round.
To pick the first seeker (or the first tagger)
  kids sit around in a circle and perform a well known ritual:
  They repeatedly recite a chant, for each syllable pointing to the next kid in the circle.
  Whoever gets the last syllable is out of the circle.
  The last person to remain is the chosen special person.
This algorithm has an obvious problem:
  You have to choose where you start pointing in the first place,
  and once you do that the outcome is completely determined.
  Thus, all appearance of randomness is illusory.
It only appears random because the outcome is somewhat hard to figure out quickly.
But not impossible:
  &lt;a href=&quot;http://en.wikipedia.org/wiki/Josephus_problem&quot;&gt;
  Josephus was able to do it.
  &lt;/a&gt;

&lt;p&gt;
It&#39;s possible to do better, using a sweet little algorithm of Herman.
Kids start standing in a circle, as before.
Some of them (maybe all) have chocolate coins.
On each round, all kids with chocolate coins throw them.
If they get heads, they have to pass the coin to the left.
If they get tails, they get to keep the coin.
And here comes the sweet part:
If a kid has two coins, THEY GET TO EAT THEM!
Anyway, since coins only get eaten in pairs,
  at some point only one coin will be left if you started with an odd number of coins.
The kid that holds this last coin is chosen as the seeker (or the tagger).

&lt;p&gt;
Obviously, the outcome is random and unpredictable, because it depends on the coin tosses.
But, how long does this take?
In 1990, Herman showed that the expected time is $O(N^2 \log N)$, where $N$ is the number of kids.
(This is independent of the number of chocolate coins you started with.
The initial number of chocolate coins could be any odd number $3\le K\le N$.)
In 2004, Fribourg et al. improved the upper bound to $2N^2$.
In 2005, Nakata improved the upper bound to $0.936 N^2$.
Also in 2005, McIver and Morgan showed that the upper bound needs to be $\ge\frac{4}{27}N^2$,
  and conjectured that it is $\frac{4}{27}N^2$.
Subsequently, various papers showed upper bounds of
  $0.64N^2$, $0.521N^2$, $0.167N^2$, and $0.156N^2$.
Now we know that McIver and Morgan were right:

&lt;blockquote&gt;
Maria Bruna, Radu Grigore, Stefan Kiefer, Joel Ouaknine, and James Worrell,
&lt;i&gt;
&lt;a href=&quot;http://arxiv.org/abs/1504.01130&quot;&gt;
Proving the Herman-Protocol Conjecture&lt;/a&gt;&lt;/i&gt;,
2015
&lt;/blockquote&gt;

&lt;p&gt;
Here&#39;s how the proof goes.

&lt;p&gt;
First, we describe configurations of chocolates by the distances between them.
For example, $(1,2,3,4,2,3,1)$ describes the following situation:

&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkmMZhzvK4mslbpsRPy-3CL9OR2PkiTt_D-Plz94XzWDwpeZM0LjJIcJBYD3Xfndy5CQ74wL-2mA4KkaNrazhEdLJ0IEHnlVQnvc97c69G29hXqs9W6z-AnZJbAKR9Gv3OXCSM/s1600/h-fig-1.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkmMZhzvK4mslbpsRPy-3CL9OR2PkiTt_D-Plz94XzWDwpeZM0LjJIcJBYD3Xfndy5CQ74wL-2mA4KkaNrazhEdLJ0IEHnlVQnvc97c69G29hXqs9W6z-AnZJbAKR9Gv3OXCSM/s320/h-fig-1.png&quot; /&gt;&lt;/a&gt;

&lt;p&gt;
The chocolate is brown and the arrow on the right shows from where we start.
We call these numbers gaps $(g_0,\ldots,g_6)$, and their sum is $N=16$, the number of kids.
After we normalize them so their sum is $1$, we just call them &amp;lsquo;ex&amp;rsquo;:
  In this case $(x_0,\ldots,x_6)=
  \bigl(\frac{1}{16},\frac{2}{16},\frac{3}{16},\frac{4}{16},
  \frac{2}{16},\frac{3}{16},\frac{1}{16}\bigr)$.
Then we define the function

$$
  f(x_0,\ldots,x_{K-1}) =
    \hskip-1em
    \sum_{\substack{
      0\le i_0\lt i_1\lt i_2\lt K\\
      \text{$i_2-i_1$ and $i_1-i_0$ odd}}}
    \hskip-2em
        x_{i_0} x_{i_1} x_{i_2}
    -
    \hskip-1em
    \sum_{\substack{
      0\le i_0\lt i_1\lt i_2\lt i_3\lt i_4\lt K\\
      \text{$i_4-i_3, \ldots, i_1-i_0$ all odd}}}
    \hskip-2em
        24 x_{i_0} x_{i_1} x_{i_2} x_{i_3} x_{i_4}
$$

and show that $4 N^2 f(x_0,\ldots,x_{K-1})$ is an upper bound for
  the expected stabilization time if the initial configuration is described by
  $(x_0,\ldots,x_{K-1})$.
Finally, we show that in the simplex

$$
  D \;=\; \{\,(x_0,\ldots,x_{K-1}) \mid
  \text{$x_0+\cdots+x_{K-1}=1$ and $x_0,\ldots,x_{K-1}\ge0$}\,\}
$$

the maximum of $f$ is $1/27$:

$$
  \max_{{\bf x}\in D} f({\bf x}) = \frac{1}{27}
$$

&lt;p&gt;
This last part is trickier than it may seem.
For details, see the
  &lt;a href=&quot;http://arxiv.org/abs/1504.01130&quot;&gt;
  paper&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/5526594312629167938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2015/04/rip-herman-conjecture-2005-2015.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/5526594312629167938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/5526594312629167938'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2015/04/rip-herman-conjecture-2005-2015.html' title='RIP Herman Conjecture (2005-2015)'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkmMZhzvK4mslbpsRPy-3CL9OR2PkiTt_D-Plz94XzWDwpeZM0LjJIcJBYD3Xfndy5CQ74wL-2mA4KkaNrazhEdLJ0IEHnlVQnvc97c69G29hXqs9W6z-AnZJbAKR9Gv3OXCSM/s72-c/h-fig-1.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-207509267506446427</id><published>2014-12-26T16:08:00.001+00:00</published><updated>2014-12-26T16:08:30.848+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><title type='text'>Why I use MOOCs</title><content type='html'>&lt;p&gt;
&lt;i&gt;
I saw a Google Plus post saying &amp;lsquo;I hope to hear less about MOOCs in 2015&amp;rsquo;.
Well, I hope to hear more.
Here&#39;s why.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
The author of the Google Plus post is a popular blogger, Daniel Lemire.
The Google Plus post links to a blog post, in which Lemire explains why
  &lt;a href=&quot;http://lemire.me/blog/archives/2014/12/24/moocs-are-closed-platforms-and-probably-doomed/&quot;&gt;
  MOOC advocates don&#39;t understand what they do&lt;/a&gt;,
  and concludes that MOOCs are probably doomed.
The two main arguments are:

&lt;ul&gt;
&lt;li&gt;MOOCs are supposed to be open, but they are in fact closed, and
&lt;li&gt;content itself is of little value.
&lt;/ul&gt;

&lt;p&gt;
None of these arguments is remotely relevant to why I use MOOCs.
I will first explain why and how I use MOOCs.
Then I&#39;ll come back to Lemire&#39;s arguments.

&lt;p&gt;
For my work, I get most of the information from articles and books.
I never pay myself for articles because all the prices I&#39;ve seen are ridiculous.
For this reason, I sympathize with the recent movement pro open access.
Books, however, often provide sufficient value to justify their cost.
So, I buy them.

&lt;p&gt;
I don&#39;t use MOOCs for work.
I use MOOCs either in the morning while waking up to the smell of coffee,
  or in the evening while cuddling in bed.
I use MOOCs to find out things for which I wouldn&#39;t otherwise have time.
I use MOOCs because they have a game-like quality that keeps me addicted.
What quality am I talking about?
I&#39;m talking about the quality of homeworks to come with deadlines and points.
They are exactly like the small tasks that you find in games.
For me, homeworks are the core of MOOCs, not lectures.
In fact, I rarely look at the lectures, unless I can&#39;t do the homeworks otherwise.

&lt;p&gt;
In short, I play MOOCs just like I play games.

&lt;p&gt;
Let&#39;s get back now to Lemire&#39;s arguments.

&lt;p&gt;
First, suppose I agree that MOOCs are closed.
So what?
I only care whether I pay or not;
I don&#39;t care about idealistic definitions of openness.
By Lemire&#39;s own account, Facebook is closed as well.
Plenty of people still use it.
That&#39;s because most people are pragmatic about openness.

&lt;p&gt;
Second, Lemire says colleges offer something of value, but that something is not content &amp;mdash;
  content is cheaply available online and from books.
Instead, according to Lemire, the value of colleges resides in
(a)&amp;nbsp;diplomas,
(b)&amp;nbsp;physical meetings, and
(c)&amp;nbsp;an &amp;lsquo;experience&amp;rsquo;.
(I don&#39;t know what point&amp;nbsp;(c) is supposed to mean.)
Here, I kind of agree.
Colleges indeed do not offer content:
  for my work, I do indeed easily get content from Google and Amazon.
And indeed physical meetings are valuable.
More precisely, it is great to interact regularly with colleagues and lecturers.


&lt;p&gt;
But, what does this have to do with MOOCs?
Oh, it must be that some people see MOOCs as an alternative to colleges.
That is indeed not a very balanced alternative: colleges win hands down.
But, I see MOOCs as an alternative to Candy Crush.
And, here, &lt;i&gt;MOOCs&lt;/i&gt; win hands down.

&lt;p&gt;
Long live the MOOCs, the best games I ever played!



&lt;!--
vim:spell:
--&gt;</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/207509267506446427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/12/why-i-use-moocs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/207509267506446427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/207509267506446427'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/12/why-i-use-moocs.html' title='Why I use MOOCs'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-2237146506818911885</id><published>2014-10-31T20:34:00.000+00:00</published><updated>2014-11-01T07:58:03.474+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coding"/><category scheme="http://www.blogger.com/atom/ns#" term="teaching"/><title type='text'>Dynamic Dispatch</title><content type='html'>&lt;p&gt;
&lt;i&gt;In which I explain how to solve puzzle questions involving dynamic dispatch.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Goto is considered harmful.
For example, it is tedious to specify which statement to execute next with absolute precision.
Hence, modern languages like INTERCAL do not have goto.
Instead they have the much better comefrom.

&lt;pre&gt;
10 comefrom 20
20 print &quot;forever&quot;
&lt;/pre&gt;

&lt;p&gt;
The statement comefrom is so much better than goto.
The exercise of building the flowgraph of a program stops being boring.
Instead, reconstructing the flowgraph feels like solving an entertaining puzzle.
The statements of the program are the pieces of the puzzle.
Initially, you can&#39;t tell much by looking around them.
You have to spread your net wide until you find two pieces that click.
You join them, and then repeat, trying to find another fit.

&lt;p&gt;
Popular languages like Java are worse in this respect.
For the most part, the flow of control is rather clear, boring.
There is one exception, though: dynamic dispatch.
I have seen several puzzles who, at their core,
  were about figuring out what dynamic dispatch does.

&lt;p&gt;
Alas, if you understand how dynamic dispatch is implemented,
  all these puzzles become rather boring.
It&#39;s not so bad as it sounds, though,
  because most people don&#39;t know or don&#39;t want to know how dynamic dispatch is implemented.
Even better, there are different ways of implementing it.
Adepts of one implementation find it difficult to communicate with adepts of the other.

&lt;p&gt;
Let&#39;s look at an example.

&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
class A {}
class B extends A {}
class X { void f(A a) { } }
class Y extends X { void f(A a) {} void f(B b) {} }
public class Main {
  public static void main(String[] args) {
    A a; B b; X x; Y y;
    a = b = new B();
    x = y = new Y();
    x.f(a); x.f(b);
    y.f(a); y.f(b);
  }
}
&lt;/pre&gt;

&lt;p&gt;
Let&#39;s pretend to be a compiler.
First, we get rid of classes.

&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
void f_X_A(X this, A a) { }
void f_Y_A(Y this, A a) { }
void f_Y_B(Y this, B b) { }
void Main_main_StringA(String[] args) {
  a = b = new_B();
  x = y = new_Y();
  f_X_A(x,a); f_X_B(x,b);
  f_Y_A(y,a); f_Y_B(y,b);
}
&lt;/pre&gt;

&lt;p&gt;
The argument &lt;code&gt;this&lt;/code&gt; used to be implicit, but is now explicit.
The function names are decorated with the types of the arguments:
  otherwise we&#39;d confuse them.
At the call sites, we plugged in function names based on the static types;
  that is, we don&#39;t track the flow of any execution.
Oh &amp;hellip; oops &amp;hellip; the function &lt;code&gt;f_X_B&lt;/code&gt; is called but not defined.
The closest one is &lt;code&gt;f_X_A&lt;/code&gt;.
Perhaps we should call that one?
Sure.
Why not? (says the compiler to itself)

&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
void f_X_A(X this, A a) { }
void f_Y_A(Y this, A a) { }
void f_Y_B(Y this, B b) { }
void Main_main_StringA(String[] args) {
  a = b = new_B();
  x = y = new_Y();
  f_X_A(x,a); f_X_A(x,b);
  f_Y_A(y,a); f_Y_B(y,b);
}
&lt;/pre&gt;

&lt;p&gt;
This doesn&#39;t feel right.
I was to dispatch something at runtime, but the code from above does no work at runtime.
Oh, right, let&#39;s see which function overrides which.
In this case, &lt;code&gt;f_Y_A&lt;/code&gt; overrides &lt;code&gt;f_X_A&lt;/code&gt;:
  the first argument is subtyped ($Y \lt: X$),
  the others are exactly the same.
So, I&#39;ll introduce some code that does that dispatch.

&lt;pre class=&quot;prettyprint lang-java&quot;&gt;
void f_X_A(X this, A a) {
  if (this instanceof Y) { f_Y_A(this, a); }
  else { /* old body */ }
}
void f_Y_A(Y this, A a) { }
void f_Y_B(Y this, B b) { }
void Main_main_StringA(String[] args) {
  a = b = new_B();
  x = y = new_Y();
  f_X_A(x,a); f_X_A(x,b);
  f_Y_A(y,a); f_Y_B(y,b);
}
&lt;/pre&gt;

&lt;p&gt;
&lt;b&gt;Notes.&lt;/b&gt;
The implementation from above is what I&#39;d call C++-like.
The alternative is the Java-like implementation, which I won&#39;t describe here.
Even the C++-like one I described is a caricature.
The trouble is that once all details are put in,
  the description becomes pretty horrendous.
Still, the details that do appear above are usually enough to figure out
  what happens in $99\%$ of puzzles.

&lt;p&gt;
Finally, what we really care about is not the implementation.
We only care about having some simple rules
  that let us figure out the control flow of any program.
The particular set of rules exemplified above
  is easy to remember as a set of actions that a compiler does.
(The Java compiler certainly does &lt;i&gt;not&lt;/i&gt; do this.)
Pretending that a compiler does this and then that is just a useful mnemonic.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/2237146506818911885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/10/dynamic-dispatch.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2237146506818911885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2237146506818911885'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/10/dynamic-dispatch.html' title='Dynamic Dispatch'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-1336696317372491217</id><published>2014-10-28T08:44:00.000+00:00</published><updated>2014-10-28T08:51:43.787+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coding"/><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Why Do We Fail?</title><content type='html'>&lt;p&gt;
&lt;i&gt;What is there to do if a problem refuses to be knocked down?
There&#39;s a generic problem solving strategy for that.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Suppose you work on a problem and fail to solve it.
You could take a break, step back, and try a different technique.
If after repeated attempts the problem fails to fall,
  then it is time for a change in strategy.
Instead of seeing patterns in the problem itself,
  try to see a pattern in your failed attempts.
Ask yourself:
&lt;i&gt;Why&lt;/i&gt; did all these attempts fail?
What do they have in common?
There are two things that may happen.
One is that you find a criterion that lets you quickly rule out techniques that won&#39;t work,
  thus saving time.
Another is that you&#39;ll find you cannot solve the problem:
  &lt;i&gt;all&lt;/i&gt; techniques are doomed to fail.

&lt;p&gt;
Let&#39;s see how this advice applies in three situations:
  writing correct programs,
  proving $P \ne NP$,
  and automatically proving properties of programs.
The last is what I&#39;ve been working on for awhile.

&lt;p&gt;
&lt;b&gt;Coding.&lt;/b&gt;

Designing and coding are similar activities.
The difference is in scale, level of detail, and precision.
When designing, you erect a tall skeleton.
To work quickly, you leave out much detail, but you try to be precise.
Nevertheless, designs are less precise than code,
  because code has to meet the minimal standard of being understood by a compiler.
When coding, you flesh out the details, one organ at a time.
An &amp;lsquo;organ&amp;rsquo; is a functional unit, which you should code in one sitting.

&lt;p&gt;
There are two tricks that improve the quality of code considerably.
These apply to individual coding sessions, not across coding sessions.

&lt;ol&gt;
&lt;li&gt;
Begin by clarifying to yourself the high-level structure of the code.
You should be able to explain why the structure is correct and good.
You should also know the time and space complexity.
Only once this is done, you can move on to writing the first line of code.
There are some caveats to this rule of thumb.
First, if it takes more than 15&amp;nbsp;minutes to clarify the structure,
  then you are probably trying to code more than you can in one sitting.
In such a situation, the best attitude is to scale down your ambitions for the day.
Second, the level of detail depends on experience:
  more experienced coders need less detail.
As a rough guide, you should know what functions you will write,
  and what each of them does.
&lt;li&gt;
Once you finish writing the code, move away from the keyboard for 5&amp;nbsp;minutes.
Then come back with a new attitude.
Pretend the author is a rookie programmer (not you!), so some bugs &lt;i&gt;must&lt;/i&gt; be lurking.
Get into the meanest mindset you can &amp;mdash; your job is to break the code.
&lt;/ol&gt;

&lt;p&gt;
For the second trick, the problem you are trying to solve is this:
  find an input that causes the program to exhibit a bug.
If repeated attempts failed to exhibit a bug,
  then it&#39;s time for a change in strategy.
Instead of trying to find a new input that may cause the program to fail,
  look at the ones that you already tried
  and make sure you understand why they don&#39;t uncover a bug.
There are two things that may happen.
One is that you find a criterion that lets you quickly rule out classes of inputs.
The criterion would usually be a proof that the program is correct on a class of inputs.
Another thing that may happen, is that you realize that the program always works.
That&#39;s when you find a full proof.

&lt;p&gt;
In other words,
  the search for bugs is an instance of the general strategy laid out at the beginning.

&lt;p&gt;
&lt;b&gt;P versus NP.&lt;/b&gt;
Some results in theoretical computer science are known as &amp;lsquo;barriers&amp;rsquo;.
These are results that say a certain proof technique will not work.
One example is that small monotone circuits cannot solve the Clique problem.

&lt;p&gt;
Let me remind you what the Clique problem is.
Think of a graph with $n$ vertices.
It can be described by a bitstring of length $\binom{n}{2}$.
Each bit says whether its corresponding edge is in the graph.
For example, for a graph with vertices 1, 2, 3, and 4,
  the possible edges are 12, 13, 14, 23, 24, 34.
So, the bitstring $110110$ represents the graph that contains edges 12, 13, 23, 24.
The &lt;i&gt;Clique problem&lt;/i&gt; asks for a family of boolean circuits,
  one for each number of vertices,
  that takes such a bitstring and outputs whether the graph contains a clique of size $k$.
The constant $k$ is fixed in advance.
A &lt;i&gt;clique&lt;/i&gt; is a subset of vertices that are all pairwise connected.
In the previous example, 123 is a clique, because 12, 13, and 23 are all edges of the graph.
Thus, if $k$ would be 3, the answer would be &amp;lsquo;yes&amp;rsquo;;
  but, if $k$ would be 4, the answer would be &amp;lsquo;no&amp;rsquo;.

&lt;p&gt;
The result I mentioned says that if you try to build circuits using only
  AND and OR gates, then the circuits will get big.
More precisely, there is some $k$ for which the size of the circuit for $n$ vertices
  is &lt;i&gt;not&lt;/i&gt; polynomial in $n$.
The argument is based on approximations of the AND and OR gates,
  and it is asymmetric in how it handles AND and OR.
Once negations are allowed, you can easily simulate an AND with an OR and some NOTs.
So, the same argument stops working,
  because it may not handle AND and OR asymmetrically anymore.
We do not know what happens if NOT gates are allowed.
We suspect that big circuits are still needed, but don&#39;t know for sure.
If we would be able to prove that the result still holds in the presence of NOT gates,
  then we would know that $P \ne NP$.
The reason is a theorem
  &amp;lsquo;whose exact authorship is apparently quite difficult to establish&amp;rsquo;&amp;nbsp;[1]:

&lt;blockquote&gt;
  &lt;b&gt;Theorem.&lt;/b&gt;
  Let $\{f_n\}_{n \in \mathbb{N}}$ be a family of boolean functions, where $f_n$ has $n$ inputs.
  Let $\mathcal{L}$ be the language whose words of length $n$ are the models of $f_n$.
  Let $M$ be a Turing machine that recognizes the language $\mathcal{L}$.
  Then
  $$ T_M(n) S_M(n) = \Omega(L(f_n))$$
  where $T_M$ and $S_M$ are the time and space used by the Turing machine,
  and $L(f_n)$ is the size of the smallest circuit that computes $f_n$.
&lt;/blockquote&gt;

&lt;p&gt;
Proof sketch:
  Given a Turing machine and a fixed $n$,
  you can build a circuit that handles inputs of size $n$ just like the machine.
  We say that Turing machines describe families of circuits;
  and we say the families of circuits are uniform, because they have a concise description
    &amp;mdash; the machine.
  If &lt;i&gt;no&lt;/i&gt; family of circuits is smaller than a certain limit,
    then certainly no &lt;i&gt;uniform&lt;/i&gt; family of circuits is smaller than that limit.

&lt;p&gt;
In this storyline, several people attempt to prove $P \ne NP$ and fail.
One of them steps back and asks &lt;i&gt;why&lt;/i&gt; do these attempts fail?
The result is a nice theorem about boolean circuits and the Clique problem.
This theorem says that any attempt that does not seriously consider negation,
  one way or another, is doomed to fail to prove $P \ne NP$.
So, this storyline is an instance of the general strategy laid out at the beginning.


&lt;p&gt;
&lt;b&gt;Parametric Static Analysis.&lt;/b&gt;

Static analyzers are programs that goggle other programs, looking for bugs.
A naive way to analyze a program is to run it and see what it does.
The trouble with this approach is that it takes forever,
  especially if you run the program on all possible inputs.
Static analyzers do use the naive approach, but with a twist:
  they approximate the semantics.
As an aside,
  note that something very similar happened in the Clique barrier:
It is difficult to track what the circuit does exactly,
  but easier to track what the circuit does approximatively.
Approximation is a fundamental tool in static analysis,
  and it is studied systematically in the area of &lt;i&gt;abstract interpretation&lt;/i&gt;.

&lt;p&gt;
A &lt;i&gt;parameterized&lt;/i&gt; static analyzer is one that can try various approximations,
  tweakable by parameters.
Given a program and a potential bug,
  the question is whether some setting of the analyzer&#39;s parameters
  would succeed in ruling out the bug.

&lt;p&gt;
Let&#39;s apply the general strategy to this problem.

&lt;p&gt;
The first step is to try several parameter settings.
If all of them fail to rule out the bug, then it is time to ask why.
We analyze the failures and we conclude
  that some other parameter settings won&#39;t rule out the bug either.
This is exactly what we did in
  &lt;a href=&quot;http://scholar.google.com/scholar?hl=en&amp;q=on+abstraction+refinement+for+program+analyses+in+datalog&quot;&gt;
  [Zhang et al., &lt;i&gt;On Abstraction Refinement for Program Analyses in Datalog&lt;/i&gt;, 2014]
  &lt;/a&gt;.

&lt;p&gt;
&lt;b&gt;Which attempts to analyze?&lt;/b&gt;
The general strategy involves making some attempts at solving the problem.
The hope is then that analyzing the failed attempts helps us solve the problem.
But, not all attempts are created equal.
If an attempt is too simple and fails for trivial reasons,
  then analyzing it won&#39;t give us too much information.
Thus, the attempts should seriously jab at the problem.

&lt;p&gt;
In the case of writing code, the test cases should be tough.
One option is to cover a corner case.
Another option is make them involved enough to exercise most of the code.
(Look at &lt;a href=&quot;http://texdoc.net/texmf-dist/doc/generic/knuth/tex/tripman.pdf&quot;&gt;
A Torture Test for $\TeX$&lt;/a&gt; to see what I mean.)

&lt;p&gt;
In the case of $P \ne NP$ you should look at serious proof attempts.
In the case of parametric static analysis $\ldots$ I&#39;m still working out what it means.
Literally.
That&#39;s what I&#39;m working on now.
In &lt;i&gt;On Abstraction Refinement for Program Analyses in Datalog&lt;/i&gt; we focused
  on cheap attempts.
But, that&#39;s like trying to break code by throwing at it the smallest test cases:
  a fairly good strategy, actually, but not quite the best.

&lt;p&gt;
&lt;b&gt;Conclusion.&lt;/b&gt;
Remember:
If you work on a problem, first try to solve it in earnest, and record your attempts.
If after repeated attempts the problem fails to fall,
  then it is time for a change in strategy.
Instead of seeing patterns in the problem itself,
  try to see a pattern in your failed attempts.
Ask yourself:
&lt;i&gt;Why&lt;/i&gt; did all these attempts fail?
What do they have in common?
There are two things that may happen.
One is that you find a criterion that lets you quickly rule out techniques that won&#39;t work,
  thus saving time.
Another is that you&#39;ll find you cannot solve the problem:
  &lt;i&gt;all&lt;/i&gt; techniques are doomed to fail.

&lt;p&gt;
&lt;b&gt;Notes.&lt;/b&gt;
For more unsolicited advice on coding from yours truly,
  see &lt;a href=&quot;/2009/02/advice-to-beginner-programmers.html&quot;&gt;
  Advice to Beginner Programmers&lt;/a&gt;.
(But you should know that &lt;a href=&quot;/2013/06/rules-of-thumb.html&quot;&gt;
  when I say &amp;lsquo;rule&amp;rsquo; I don&#39;t mean &amp;lsquo;law&amp;rsquo;&lt;/a&gt;.)
For the Clique barrier, see the expository article
 &lt;a href=&quot;http://gowers.files.wordpress.com/2009/05/razborov2.pdf&quot;&gt;
 [Gowers, &lt;i&gt;Razborov&#39;s Method of Approximations&lt;/i&gt;, 2009]&lt;/a&gt;.
The theorem and the quote&amp;nbsp;[1] is from
  &lt;a href=&quot;http://scholar.google.com/scholar?hl=en&amp;q=razborov+lower+bounds+for+monotone+complexity&quot;&gt;
  [Razborov, &lt;i&gt;Lower Bounds for Monotone Complexity of Boolean Functions&lt;/i&gt;, 1986]
  &lt;/a&gt;.
For more on parametric static analyses,
  you could see a rather long previous post
  (&lt;a href=&quot;/2014/06/datalog-and-maxsat-unexpected-match.html&quot;&gt;Datalog and MaxSat: an Unexpected Match&lt;/a&gt;)
  or a rather abstract video
  (&lt;a href=&quot;https://www.youtube.com/watch?v=TzP-DybRZFk&quot;&gt;On Abstraction Refinement for Program Analyses in Datalog&lt;/a&gt;).
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/1336696317372491217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/10/why-do-we-fail.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1336696317372491217'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1336696317372491217'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/10/why-do-we-fail.html' title='Why Do We Fail?'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-8249840787080464666</id><published>2014-10-13T06:51:00.001+01:00</published><updated>2014-10-13T20:22:24.393+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><title type='text'>Research and Startups</title><content type='html'>
&lt;p&gt;
&lt;i&gt;In which I argue that research is an extreme form of startup.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Folklore says that nine in ten startups fail.
The number 0.9 comes out of the hat of a cat.
But, there seems to be agreement that very few startups are highly successful.
Some plod along like zombies for a long time.
Only few become Twitters or acquired by Twitter (or some other social network).

&lt;p&gt;
The situation is seen as satisfactory.
Startups carry out activities that have high risk and high reward.
Any one particular startup is more likely to fail than succeed.
But, the sheer number of startups ensures that we have a steady stream of innovation.
This stream is undoubtedly useful for society.

&lt;p&gt;
The situation &amp;mdash; high risk and high reward &amp;mdash; is even more extreme for research.

&lt;p&gt;
Every now and then I encounter the opinion that startups rock and research sucks;
for example, a few months ago, when I was reading Antifragile.
The book extols the virtues of entrepreneurship.
It even goes as far as asking for more safety nets so that entrepreneurs take more risks.
It&#39;s OK to fail, because progress is made by trial and error.
At the same time, researchers are seen as a useless bunch.
They spend their time on theories, instead on what they should be doing: try and err.
Sure, every once in a while they build an atomic bomb, but that&#39;s an &lt;i&gt;exception&lt;/i&gt;!

&lt;p&gt;
As if the startup that becomes Facebook is the rule.

&lt;p&gt;
(I still recommend reading the book.
It is entertaining and thought provoking, even if rude.)

&lt;p&gt;
I like to think of big companies, startups, and research in terms of a travel metaphor.
You live in a small village.
On one side you see a deep forest.
Across the road there is a huge mountain.
What would you rather do?

&lt;ol&gt;
&lt;li&gt;You could take the bus to visit the city.
  The bus trip may involve some unexpected delays, but it&#39;s rather predictable nevertheless.
  That bus is the service that big companies offer.
  There may be big differences between two companies
    &amp;mdash; how comfortable the chair is, how entertaining the driver is,
      how often the bus is on time.
  But, no matter which bus you pick, it&#39;s a safe bet that you will get to the city.
&lt;li&gt;
  You could go on a hiking expedition to the summit of the mountain.
  You might find this a lot more exciting than a bus trip.
  But you also need to make sure you have enough stamina and resolve.
  There may be a few footpaths along the way,
    but they are far in-between, badly marked,
    and you&#39;ll certainly not get to the summit by just following them.
  This expedition is what startups do.
  Their aim is clear &amp;mdash; the summit is in sight.
  It&#39;s also fairly sure that someone &lt;i&gt;will&lt;/i&gt; get there eventually.
  But it&#39;s not clear at all that you are sufficiently well trained
    to get there before night falls.
  Even if you are, you might get unlucky and take a turn of a road
    that makes the trip more difficult than necessary.
&lt;li&gt;
  Finally, you could go into the deep forest.
  Here, there are no footpaths, and you have no idea what you&#39;ll see,
    or whether you&#39;ll be able to get back home.
  For some, this might be even more exciting than a hiking expedition.
  This trip through the deep forest is what research does.
  It discovers hidden gems that you couldn&#39;t even imagine
    if you wouldn&#39;t bump into them, mostly by accident.
  That is not to say that finding gems in a forest is done only by pure luck.
  You need survival skills.
  You need to have a sense of direction.
  You need to fend of animals.
  You need to be able to climb trees.
  You need to chart a map as you go, and use it to avoid going in circles.
  And you have better chances if you join a group,
    but it can be difficult for people to agree on what is the best course of action.
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/8249840787080464666/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/10/research-and-startups.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8249840787080464666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/8249840787080464666'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/10/research-and-startups.html' title='Research and Startups'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-831430174400980692</id><published>2014-10-05T20:09:00.000+01:00</published><updated>2014-10-06T07:25:09.825+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="teaching"/><title type='text'>Nitpicking Distance</title><content type='html'>&lt;p&gt;
&lt;i&gt;
I recently wrote down what I thought is
  a completely standard definition of distance on graphs.
I was asked if I&#39;m sure that the definition is well-behaved.
Well &amp;hellip; let&#39;s see.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Let&#39;s define a distance on a directed graph:
To go from $x$ to $z$, we first go to $y$, and then take one more step.
$$ d(x,z) = 1 + \min \{\,d(x,y)\mid y \to z \,\} $$
Question: Is this definition good?
Suppose the digraph is $0 \leftrightarrow 1$.
According to the equation above,
$$\begin{align}
&amp;amp;\bbox[2px,border:2px solid red,pink]{d(0,1)} \\
&amp;amp;= 1 + \min \{ d(0,0) \}
  &amp;amp;&amp;amp;\text{by decomposing $0\leadsto 1$ as $0\leadsto 0\to 1$} \\
&amp;amp;= 1 + d(0,0) \\
&amp;amp;= 1 + 1 + \min \{ d(0,1) \}
  &amp;amp;&amp;amp;\text{by decomposing $0\leadsto 0$ as $0\leadsto 1\to 0$} \\
&amp;amp;= \bbox[2px,border:2px solid red,pink]{2 + d(0,1)}
\end{align}$$
Something is fishy.
There are in fact at least two problems with the definition.
One problem is illustrated above:
It leads to weird consequences when applied for $x=z$.
Another problem:
What happens when the minimum is taken over the empty set?
This second problem leads to a third:
What is the type of the function $d$?
Let&#39;s say
$$ d : V \times V \to \mathbb{N} \cup \{\infty\} $$
Now $\infty$ was promoted to a proper distance value.
We can agree that $\min\emptyset=\infty$, by convention.
Also, we can solve the equation $d(0,1)=2+d(0,1)$:
The only solution in $\mathbb{N}\cup\{\infty\}$ is $\infty$.
It&#39;s nice that we can solve that equation, but we probably don&#39;t want $d(0,1)$ to be $\infty$.
It&#39;s time to fix the definition by adding a special case for $x=z$.
$$\begin{align}
d(x,z) =
  \begin{cases}
  0 &amp;amp;\text{if $x=z$} \\
  1 + \min\{\,d(x,y)\mid y\to z\,\} &amp;amp;\text{otherwise}
  \end{cases}
\end{align}$$

&lt;p&gt;
Question: How can we tell for sure that $d$ is uniquely determined by the equation above?
This question really has two parts:
&lt;ol&gt;
&lt;li&gt;Is there always a solution?
&lt;li&gt;Is there at most one solution?
&lt;/ol&gt;

&lt;p&gt;
The first subquestion is suitably addressed by a sledgehammer
  that goes by the name of the Knaster&amp;ndash;Tarski theorem.
In the limited form that we need here,
  it says that an order-preserving function on a complete lattice has a fixed-point.
In our case, the lattice is the set $L\;=\;V \times V \to \mathbb{N}\cup\{\infty\}$.
The partial order on the lattice is defined pointwise:
$$ d \le e \quad\stackrel\Delta=\quad \bigl(\forall x \forall y\; d(x,y) \le e(x,y)\bigr)$$
The order-preserving function is $D:L\to L$, defined by
$$
D(d)(x,z) =
  \begin{cases}
  0 &amp;amp;\text{if $x=z$} \\
  1 + \min\{\,d(x,y) \mid y\to z\,\} &amp;amp;\text{otherwise}
  \end{cases}
$$
Let&#39;s check that it is order-preserving.
We pick $d,e : L$ such that $d\le e$, and we&#39;d like to show that $D(d)\le D(e)$.
The case $x=z$ reduces to showing $0\le 0$.
The case $x\ne z$ reduces to showing that
$$ \min\{\,d(x,y)\mid y\to z\,\} \le \min\{\,e(x,y)\mid y\to z\,\}$$
which follows from the assumption $d\le e$.
At this point, we know that the conditions of the Knaster&amp;ndash;Tarski theorem are fulfilled,
  so $D$ has at least one fixed-point.
In other words, there is at least one function $d$ that satisfies our recursive equation,
  no matter on which graph we apply it.
(This is true even for infinite graphs.)

&lt;p&gt;
Now on to the second subquestion:
Is there at most one function in $L$ that satisfies the recursive equation?
Let&#39;s assume that $D(d)=d$ and $D(e)=e$.
By way of contradiction, assume also that $d\ne e$;
  that is, $d(x,z)\ne e(x,z)$ for some $(x,z)\in V\times V$.
Since $d$ and $e$ are fixed-points of $D$, the second assumption is equivalent to
$$ D(d)(x,z) \ne D(e)(x,z)$$
If $x=z$, then $D(d)(x,z)=0=D(e)(x,z)$, which is a contradiction.
If $x\ne z$, then
  $$\min\{\,d(x,y)\mid y\to z\,\} \ne \min\{\,e(x,y)\mid y\to z\,\}$$
Without loss of generality, let&#39;s assume that
  $$\min\{\,d(x,y)\mid y\to z\,\} \lt \min\{\,e(x,y)\mid y\to z\,\}$$
We fix $y$ to make the left hand side minimum, and now we have
  $$d(x,y) \lt e(x,y) \qquad d(x,y) \lt d(x,z)$$
(Exercise: How do we know that $d(x,y)\lt d(x,z)$? Why not $d(x,y)=d(x,z)=\infty$?)
To recap,
  if $d\ne e$,
  then it must be that $d(x,z)\lt e(x,z)$ (or, symmetrically, $d(x,z)\gt e(x,z)$),
  and then in turn it must be that $d(x,y)\lt e(x,y)$ and $d(x,y)\lt d(x,z)$ for some $y$.
But, this process can&#39;t be repeated forever,
  because $\mathbb{N}$ has no infinite descending chains.
Done.
Again, this also works for infinite graphs.

&lt;p&gt;
You may expect that $d(x,y)=\infty$ means that $x$ and $y$ are disconnected.
This is not the case.
Let $V=\mathbb{N}\to\{0,1\}$,
  and say there are arcs $x\leftrightarrow y$
  when $x$ and $y$ differ in exactly one place.
In this graph you can get from any sequence to any other sequence,
  but you may need to walk forever to do so.
(A very similar example would be to take $V=\mathbb{R}$ and define arcs in terms of
  decimal representations of real numbers.)

&lt;p&gt;
Believe it or not, after all this work, we&#39;re not done yet.
To be allowed to use the word &amp;lsquo;distance&amp;rsquo; with a straight face,
  we should check some axioms.
Here&#39;s what Wikipedia says:
$$\begin{align}
&amp;amp;d : V\times V \to \mathbb{R} \\
&amp;amp;d(x,y)=0 \iff x = y \\
&amp;amp;d(x,y)=d(y,x) \\
&amp;amp;d(x,z)\le d(x,y)+d(y,z)
\end{align}$$
I suppose we&#39;re in trouble,
  because $\mathbb{N}\cup\{\infty\}$ is &lt;i&gt;not&lt;/i&gt; a subset of $\mathbb{R}$.
Also, if the graph is directed then the sort-of distance we defined isn&#39;t symmetric.
Oh, well.

&lt;p&gt;
The other axioms should hold.
For finite connected undirected graphs we do have a metric.
For finite directed strongly connected graphs we have a quasimetric,
  although Wikipedia says this terminology is not completely standard.
  (Is it?)
I wouldn&#39;t lose sleep about calling it a distance for other graphs, though.

&lt;p&gt;
&lt;b&gt;PS:&lt;/b&gt; Feel free to nitpick, obviously.</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/831430174400980692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/10/nitpicking-distance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/831430174400980692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/831430174400980692'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/10/nitpicking-distance.html' title='Nitpicking Distance'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-1451233698849152118</id><published>2014-09-13T08:40:00.000+01:00</published><updated>2014-09-15T07:08:45.732+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="teaching"/><title type='text'>The Effect of Discouragement</title><content type='html'>&lt;p&gt;
&lt;i&gt;How many books will one write? (Or blog posts, for that matter.)&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Terry Tao recently explained
  &lt;a href=&quot;https://plus.google.com/u/0/114134834346472219368/posts/bLMjUbEgeqS&quot;&gt;
  why most bad books are written by good authors&lt;/a&gt;.
The basic idea is that bad authors are are discouraged and give up writing.
The model he used describes each author by the probability $p$ to produce good books.
But, there&#39;s no model for discouragement.
Instead, it just sneaks in in an example.
Let&#39;s try to rectify that.
We add a probability $q_0$ of giving up after writing a good book,
  and a probability $q_1$ of giving up after writing a bad book.

&lt;p&gt;
How many books will one write on average, in this model?
There&#39;s a picture below, for $q_0=1\%$ and various values of $q_1$.
The $x$-axis is $p$.
So, for example, we see that if all written books are good ($p=1$),
  then we expect 100&amp;nbsp;books.
But, if all books are bad ($p=0$) and $q_1=2\%$,
  then we expect 50&amp;nbsp;books.
[&lt;b&gt;Edit:&lt;/b&gt; I should perhaps state explicitly what I see in this graph:
The number of books you&#39;ll write doesn&#39;t depend too much on how good you are.
Unless you are very good ($p&gt;0.8$), in which case you&#39;ll write a lot of books.]

&lt;p&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkDVmwKUs7uR7qkahj93cuN5VBj1sOIlPqChDXj_rgK0WtECo6ZURaovSw-jhbSuSeD3hphuhNwWegWVSseiqDs6_0MksstuwkWru6yFQQxWU95Ln_ZaJGpqtdgm62ACxWj2II/s1600/expected_write.png&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkDVmwKUs7uR7qkahj93cuN5VBj1sOIlPqChDXj_rgK0WtECo6ZURaovSw-jhbSuSeD3hphuhNwWegWVSseiqDs6_0MksstuwkWru6yFQQxWU95Ln_ZaJGpqtdgm62ACxWj2II/s640/expected_write.png&quot; /&gt;&lt;/a&gt;

&lt;p&gt;
In case you are curious, here&#39;s how I drew this.
One writes $n\ge1$ books if one writes $n-1$ books without giving up and gives up after the $n$th.
Thus, the probability of writing $n$ books is $\alpha^{n-1}\beta$, where
$$\begin{align}
\alpha &amp;amp;= p(1-q_0) + (1-p)(1-q_1) \\
\beta &amp;amp;= pq_0 + (1-p)q_1
\end{align}$$
If we define
$$G(x) = \sum_{n\ge 1} \alpha^{n-1} \beta x^n$$
then the expected value we search for is $G&#39;(1)$.
Since, $G$ is a geometric series, it&#39;s easy to compute the sum.
$$\begin{align}
G(x) &amp;amp;= \beta x \sum_{n\ge 0} (\alpha x)^n \\
  &amp;amp;= \beta x\frac{1-(\alpha x)^\infty}{1-\alpha x} \\
  &amp;amp;= \frac{\beta x}{1-\alpha x}
\end{align}$$
Derive:
$$\begin{align}
G&#39;(x) &amp;amp;=\frac{\beta(1-\alpha x)+\alpha\beta x}{(1-\alpha x)^2} \\
  &amp;amp;=\frac{\beta}{(1-\alpha x)^2}
\end{align}$$
So, the plot you see above is for the function
$$
\frac{\beta}{(1-\alpha)^2}
$$

&lt;p&gt;
&lt;b&gt;Edit 2:&lt;/b&gt;
There are two things that are kinda misleading above.
Let me try to rectify, if only briefly.
One: Tao shows that most bad books &lt;i&gt;could&lt;/i&gt; be written by good authors, not that they &lt;i&gt;are&lt;/i&gt;.
Two: In the model from above with $q_0$ and $q_1$ it is &lt;i&gt;not&lt;/i&gt; true that most bad books are written by bad authors.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/1451233698849152118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/09/the-effect-of-discouragement.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1451233698849152118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1451233698849152118'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/09/the-effect-of-discouragement.html' title='The Effect of Discouragement'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkDVmwKUs7uR7qkahj93cuN5VBj1sOIlPqChDXj_rgK0WtECo6ZURaovSw-jhbSuSeD3hphuhNwWegWVSseiqDs6_0MksstuwkWru6yFQQxWU95Ln_ZaJGpqtdgm62ACxWj2II/s72-c/expected_write.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-6035806828852881587</id><published>2014-09-11T07:32:00.000+01:00</published><updated>2014-09-11T07:32:40.203+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="teaching"/><title type='text'>Beta Function</title><content type='html'>&lt;p&gt;
&lt;i&gt;How to compute $\int_0^1 dp\, p^k(1-p)^{n-k}$ without symbol manipulation.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
The symbols I used to write it might be a giveaway.
We&#39;ll imagine throwing a coin and obtaining sequences of head and tail like
$$HTTTTHTHHH$$
This one has probability $p^5(1-p)^5$.
If $p$ is the probability of obtaining&amp;nbsp;H and $k$ is the number of Hs,
  then the general form is $p^k(1-p)^{n-k}$.
The chances of obtaining &lt;i&gt;some&lt;/i&gt; sequence with $k$ Hs is
$$ \binom{n}{k} p^k(1-p)^{n-k}$$

&lt;p&gt;
But, what if we don&#39;t know the value of $p$?
Instead, we just have some guess about where its value is.
(For example, perhaps we just know it&#39;s very likely in $[0.4,0.6]$.)
In general, we&#39;d model this with a probability density:
We say that value $p$ happens with probability $h(p)\,dp$,
  where the function $h(p)$ is the probability density.
Then, to get an expectation for the probability of seeing $k$ Hs,
  we average over the possible values of $p$:
$$ \int_0^1 dp\, h(p) \binom{n}{k} p^k(1-p)^{n-k}$$
The integral is from 0 to 1, because $h(p)$ must be $0$ elsewhere;
  after all, we know that $p$ is a probability.

&lt;p&gt;
If we have no idea what value $p$ has,
  then we should expect to see all values of $k$ with equal probability.
The possible values are $0,1,\ldots,n$, so the probability is $1/(n+1)$.
How do we express in terms of $h(p)$ that we have no idea what value $p$ has?
That&#39;s right, we simply choose a uniform distribution $h(p)=1$,
  to say that we don&#39;t prefer one guess over another.
Hence,
$$ \int_0^1 dp\, \binom{n}{k} p^k(1-p)^{n-k} = \frac{1}{n+1} $$
and
$$ \int_0^1 dp\, p^k(1-p)^{n-k} = \frac{1}{(n+1)\binom{n}{k}} $$

&lt;p&gt;
Sure, this reasoning is fast and loose.
Nevertheless, this is what I did when I had to compute the integral,
  and, because I thought it&#39;s kinda cute, I&#39;ll probably not forget the trick.
If you want a more rigouros derivation,
  &lt;a href=&quot;http://en.wikipedia.org/wiki/Beta_function#Relationship_between_gamma_function_and_beta_function&quot;&gt;Wikipedia has one&lt;/a&gt;.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/6035806828852881587/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/09/beta-function.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6035806828852881587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6035806828852881587'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/09/beta-function.html' title='Beta Function'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-4942637974388080101</id><published>2014-08-26T06:45:00.002+01:00</published><updated>2014-09-12T14:35:48.018+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coding"/><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>Watching Horn</title><content type='html'>&lt;p&gt;
&lt;i&gt;How to use watched literals (or, rather, vertices) to do breadth-first search in Horn hyperdigraphs.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Satisfiability solvers use a technique called &amp;lsquo;watched literals&amp;rsquo;.
I&#39;ll present it here in the context of Horn clauses, for two reasons:
(1)&amp;nbsp;it is a slightly unusual context, and
(2)&amp;nbsp;I actually needed to implement this for my work.

&lt;p&gt;
Horn clauses can be difficult to visualize.
So, I&#39;ll use an equivalent formulation in terms of directed hypergraphs.
Unlike their undirected relatives, directed hypergraphs are less famous.
A directed (hyper)arc is a pair $(X, Y)$ of vertex sets.
If you are familiar with SAT, think of $X$ as the set of negative literals, and $Y$ the set of positive literals.
Then, a Horn formula corresponds to a hypergraph with $|Y| \le 1$ for all arcs.
(And a Horn &lt;i&gt;clause&lt;/i&gt; corresponds to a hypergraph &lt;i&gt;arc&lt;/i&gt;.)
A &lt;i&gt;definite&lt;/i&gt; Horn formula corresponds to the case $|Y|=1$.

&lt;p&gt;
We want to perform breadth-first search on definite Horn hyperdigraphs.

&lt;p&gt;
Let&#39;s first clarify what reachability means.
For digraphs, if vertex $x$ is reachable and the digraph has an arc $(x,y)$, then vertex $y$ is reachable.
For hyperdigraphs, if &lt;i&gt;all&lt;/i&gt; vertices in $X$ are reachable and the hyperdigraph has an arc $(X, Y)$, then &lt;i&gt;some&lt;/i&gt; vertices in $Y$ are reachable.
Saying that &lt;i&gt;some&lt;/i&gt; vertex is reachable sounds a bit weird.
I chose this definition so that it corresponds on satisfiability of formulas.
And, the weirdness doesn&#39;t matter as we look at the definite Horn case $|Y|=1$.
(But, I should say there are other definitions of reachability on hyperdigraphs.)

&lt;p&gt;
How should we implement this?

&lt;p&gt;
For digraphs, we use a flag on each vertex to put them in one of three categories:
(1)&amp;nbsp;not seen,
(2)&amp;nbsp;seen,
(3)&amp;nbsp;done.
At every step we pick a seen vertex $x$.
Then we mark all its successors that were previously not seen as seen.
And then we mark $x$ as done.
This schema works for every traversal.
For breadth-first search, we must pick vertices in a certain order.
One way is to use a queue.
But, if you are interested in distances, there is a more convenient way.
We keep two sets, the current level and the next level, of seen nodes.
The $x$ is picked from the current level, its successors added to the next.
Also, $x$ is removed from the current level when marked done.
(Not strictly necessary:
The invariant that these two levels contain only seen nodes can be relaxed.)
When the current level becomes empty, it gets swapped with the next level.
The process ends when both levels are empty.

&lt;p&gt;
If we try to do the same for hypergraphs, we run into an efficiency problem.
Previously, given $x$, we had to find all arcs of the form $(x,y)$.
That&#39;s just the adjacency list representation of digraphs.
But now, given $x$, we must find all arcs of the form $(X,y)$ such that $x\in X$ and all vertices of $X$ are seen (or done).
This is a considerably more difficult problem, solved by watching literals.

&lt;p&gt;
Consider an arc $(X,y)$.
If all nodes in $X$ are done, then $y$ must be seen or done.
To ensure this is the case, we need a quick way to find arcs whose all sources are done.
The trick is to think of a data structure that enforces the negation:
&lt;i&gt;For each arc $(X,y)$ there is at least one vertex in $X$ that is not done.&lt;/i&gt;
When we fail to maintain the invariant, it is because an arc has the required property.

&lt;p&gt;
How do we make sure that every arc has an undone vertex?
Well, we designate one particular vertex, which is undone, as being watched.
Then, we still use the adjacency list representation, as for digraph.
For digraphs, the adjacency list maps a vertex $x$ to the list of arcs of the form $(x,y)$.
For Horn hyperdigraphs, the adjacency list maps a vertex $x$ to the list of arcs $(X,y)$ such that $x \in X$ is the designated watched vertex for this arc.

&lt;p&gt;
Finally, let&#39;s see what happens when we pick a seen vertex $x$ in the traversal algorithm.
This time we begin by marking $x$ as done.
This is like promising to have done the work before actually doing it.
So, we&#39;d better do it.
We have to go through the adjacency list of $x$, because $x$ cannot be a watched vertex anymore.
For each of the arcs, we must pick a different undone vertex to watch.
For each arc $(X,y)$ we simply scan all members of $X$ until we find a suitable replacement.
If there isn&#39;t any, then all sources are done, so we must mark $y$ as seen if it was not seen.

&lt;p&gt;
That&#39;s it.

&lt;p&gt;By the way, according to Blogger this is my 100000000th post.</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/4942637974388080101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/08/watching-horn.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/4942637974388080101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/4942637974388080101'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/08/watching-horn.html' title='Watching Horn'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-7563041285674849004</id><published>2014-08-18T09:57:00.000+01:00</published><updated>2014-08-18T09:57:04.637+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><title type='text'>Genius! How Not to Be Wrong</title><content type='html'>&lt;p&gt;
&lt;i&gt;Why math is for everybody.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
The book &lt;i&gt;How Not to Be Wrong&lt;/i&gt; says that math can enrich your life.
It doesn&#39;t matter whether you like the math drills from school.
Those are for math like running is for football:
useful, but not quite the fun part.
Unless you turn pro.
In that case, running exercises are necessary, rather than merely useful.

&lt;p&gt;
I agree with this message wholeheartedly.
But I learned something from Kahneman&#39;s &lt;i&gt;Thinking Fast and Slow&lt;/i&gt;:
If you find yourself &lt;i&gt;completely&lt;/i&gt; agreeing, then you&#39;re probably not paying enough attention.
It&#39;s easy to do so, because attention is a scarce resource.
People instinctively tend to conserve it.

&lt;p&gt;
For a while I was worried that I agree too much with Ellenberg.
(He is the author of &lt;i&gt;How Not to Be Wrong&lt;/i&gt;.)
But then I got to the section about genius, and I stopped worrying.

&lt;p&gt;
This section is aligned with the main message.
It says that it&#39;s stupid to give up math because someone else is better than you.
That&#39;s not the problem.
With that I agree.
But then, Ellenberg starts saying &lt;i&gt;why&lt;/i&gt; you should go on.
One reason is that more brains will make math advance faster.
That&#39;s not the problem either.
But &lt;i&gt;then&lt;/i&gt; he says things like this:

&lt;blockquote&gt;
It can be hard for me to make this case, because I was one of those prodigious kids myself.
[&amp;hellip;]
[I] won a neckful of medals in math contests.
[&amp;hellip;]
That group of young stars produced many excellent mathematicians.
[&amp;hellip;]
But most of the mathematicians I work with now weren&#39;t ace mathletes at thirteen;
they developed their abilities and talents on a different time-scale.
Should they have given up in middle school?
&lt;/blockquote&gt;

&lt;p&gt;
Well, &amp;hellip; this comes after a few sections warning of the dangers of ignoring base rates.
Having a neckful of medals in math contests is a very rare event almost by definition.
Given this, the statement that &amp;lsquo;most mathematicians &lt;i&gt;don&#39;t&lt;/i&gt; have a neckful of medals&amp;rsquo; contains very close to 0&amp;nbsp;bits of information.

&lt;p&gt;
Let&#39;s put it differently.
Suppose a country has about 150000 students in a certain school year.
Out of those 10000 participate in math contests.
Out of those 30 do really well, and get some medals at the national level.
(Incidentally, I think these figures are in the right ballpark for Romania.)
Now, out of these 150000 students, 20 become professional mathematicians.
Most professional mathematicians (say, 15) come from those without medals.
The rest (5 in this case) come from those with medals.
And yet, having a medal gives you chance of 17% of becoming a mathematician, while not having a medal gives you a chance of 0.01% of becoming one.
That is, not having a medal decreases your chances more than 1600&amp;nbsp;times.
(Again incidentally, this reasoning mirrors an argument from Ellenberg&#39;s book.)

&lt;p&gt;
So, yes, most mathematicians were not mathlets.
But, no, this is not such great news for your math future as it may sound.

&lt;p&gt;
It is easy to misinterpret what I said above, so I&#39;ll linger on the point.
Suppose you are a student and you don&#39;t have a &amp;lsquo;neckful of medals&amp;rsquo;.
Do I think you should not try to become a mathematician?
I most certainly &lt;i&gt;do not&lt;/i&gt; think that.
Do I think being a mathematician is a perfectly valid career choice for you?
Yes, I most certainly &lt;i&gt;do&lt;/i&gt; think that.
But, the reason &lt;i&gt;why&lt;/i&gt; I think so is &lt;i&gt;not&lt;/i&gt; that most mathematicians weren&#39;t mathletes.
You see, I can agree with the conclusion but disagree with the argument.

&lt;p&gt;
Why, then, should you not care about medals?
I&#39;ll tell you some of my reasons.

&lt;p&gt;
My family encouraged me to take part in the Romanian Math Olympiad.
But, I never did well.
And I was never worried about it.
In fact, I thought that being a mathlete would be rather boring.
The reason is the following conversation about the problems of one contest.
Me: &amp;lsquo;So how would you solve problem 1?&amp;rsquo;
Other: &amp;lsquo;Oh, you use Theorem&amp;nbsp;X.&amp;rsquo;
Me: &amp;lsquo;Ah, I didn&#39;t know Theorem&amp;nbsp;X.
  How do you prove it?&amp;rsquo;
Other: &amp;lsquo;I don&#39;t know. But it doesn&#39;t matter. You can just use it.&amp;rsquo;
Me: &amp;lsquo;What about problem 2?&amp;rsquo;
Other: &amp;lsquo;For that one you use Theorem&amp;nbsp;Y.&amp;rsquo;
Me: &amp;lsquo;Hmm. I don&#39;t know that one either. Can you tell me why this theorem is true?&amp;rsquo;
Other: &amp;lsquo;I don&#39;t remember now. But it&#39;s in the textbook.&amp;rsquo;
After going through a few more problems, I decided that I could do a lot better in these contests if I knew a bunch of theorems, even if I don&#39;t know why they&#39;re OK.
I thought that knowing theorems without understanding why they hold is no fun.
And, more often than not, it seemed like the theorem was more interesting than the problem.
It felt like someone knew the theorem and said &amp;lsquo;I&#39;ll make a problem out of it by applying some make-up&amp;rsquo;.
Then, the contestants&#39; job was to remove the make-up, an recognize the theorem underneath.
This simply doesn&#39;t sound like fun.

&lt;p&gt;
I should disclose that this memory is &lt;i&gt;so&lt;/i&gt; vague that I&#39;m not sure I actually had that conversation.
Whether I had it or not, it captures my point of view from high-school.

&lt;p&gt;
I no longer hold that view; not entirely.
It&#39;s true: one can do well in these contests by memorizing theorems.
But, one can do &lt;i&gt;really&lt;/i&gt; well only by knowing many theorems and techniques.
And one simply can&#39;t remember so many things unless one also understands them.
Another thing I realized in the meantime is that contests cover a tiny corner of math.

&lt;p&gt;
So, here&#39;s why you need not worry about contests.
Your goal should be to have fun.
&lt;i&gt;Understanding&lt;/i&gt; is the supreme kind of fun.
Figuring out &lt;i&gt;on your own&lt;/i&gt; something that you didn&#39;t know feels awesome.
(I sometimes joke that it&#39;s better than an orgasm.)
This feeling I describe doesn&#39;t come often, and certainly not after solving easy problems.
The harder the problem, the better the feeling.
But, it can be difficult to keep going.
Here is were contests come in: they are a great motivational tool.
But, only for people with a certain psyche.
Contests aren&#39;t good in themselves.
Contests are good because they make you prepare for them.
&lt;i&gt;The work you do while preparing for them is the valuable part.&lt;/i&gt;
And also the part where you&#39;ll ultimately have most fun.

&lt;p&gt;
I couldn&#39;t see the value of contests because I was not preparing for them.
I just showed up.
Of course they weren&#39;t fun!

&lt;p&gt;
&lt;i&gt;The important thing is to keep punching hard problems.
Whether you use a contest as an excuse to do it is a secondary concern.
&lt;/i&gt;
(Obviously, the problems need to be within your reach; otherwise, you can&#39;t punch them.)

&lt;p&gt;
Going back to the book, I concede that my objection amounts to nitpicking.
Which makes me worry again that I didn&#39;t pay enough attention.
I plan to do a second reading with a more critical eye.

&lt;p&gt;
Here&#39;s a link: &lt;a href=&quot;http://www.amazon.com/How-Not-Be-Wrong-Mathematical/dp/1594205221&quot;&gt;Ellenberg, &lt;i&gt;How Not to Be Wrong&lt;/i&gt;&lt;/a&gt;.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/7563041285674849004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/08/genius-how-not-to-be-wrong.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/7563041285674849004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/7563041285674849004'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/08/genius-how-not-to-be-wrong.html' title='Genius! How Not to Be Wrong'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-2287358671704387197</id><published>2014-08-17T15:46:00.000+01:00</published><updated>2014-08-17T15:55:42.083+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><category scheme="http://www.blogger.com/atom/ns#" term="presentation"/><category scheme="http://www.blogger.com/atom/ns#" term="random"/><title type='text'>ROSE 1995</title><content type='html'>&lt;p&gt;
&lt;i&gt;What I remember from the first computer-related conference I attended.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
I have rather vague memories about this conference, from almost 20 years ago.
But, I managed to find its program in some dark corner of the Internet.
From it, I learned several things.
The name stands for &lt;i&gt;Romanian Open Systems Event&lt;/i&gt;.
It was in the beginning of November, so I must have missed school to attend.
It was in 1995, so I was just starting Year&amp;nbsp;10 of school.

&lt;p&gt;
I also remember several things that aren&#39;t in the program.
Two of these memories are most vivid.

&lt;p&gt;
First, that&#39;s when I learned of Java.
There was a presentation by some marketing guy from Sun.
(According to the program, it was Darryl Parker.)
I had never seen such a good presentation before.
He really did convince me that Java is the future of the Internet.
Even now I remember that one main selling point of Java is &amp;lsquo;Write Once, Run Everywhere&amp;rsquo;.
And (I&#39;m almost sure) I remember it from that presentation.
I learned in the meantime that people are prone to mistake presentation quality for content quality.

&lt;p&gt;
Second, at some point Linus Torvalds was working on his laptop.
Nobody dared to interrupt, but my father nudged me, and I did.
The only thing I knew about him at the time was that he was supposed to be the celebrity guest of the conference.
I remember he was extremely nice.
When I asked what is he doing he said he&#39;s preparing his presentation, which is in one of the next sessions.
&amp;lsquo;What do you use?&amp;rsquo;
&amp;lsquo;Powerpoint.
People sometimes think I&#39;m anti-Microsoft, but I&#39;m not.
Powerpoint is really good.&amp;rsquo;
And that&#39;s why I learned to use Powerpoint.
I don&#39;t recall the rest.
But I do recall that he patiently waited until I finished quizzing him, despite having an unfinished presentation to make later on.
I never met him since.

&lt;p&gt;
Sometimes people describe Linus as nasty.
I find it very hard to agree, and I think it&#39;s because of that meeting.
Another result of that meeting was that 5&amp;nbsp;years later I decided to try Linux.
I&#39;m glad I did &amp;mdash; it fits my style.
(Powerpoint doesn&#39;t.)
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/2287358671704387197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/08/rose-1995.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2287358671704387197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2287358671704387197'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/08/rose-1995.html' title='ROSE 1995'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-2130065838738711944</id><published>2014-08-07T10:31:00.000+01:00</published><updated>2014-08-11T11:22:02.100+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="opinion"/><title type='text'>Coursera Courses</title><content type='html'>&lt;p&gt;
&lt;i&gt;In this post I review some of the Coursera courses that I completed.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/algo2&quot;&gt;
&lt;b&gt;Algorithms: Design and Analysis, Part 2.&lt;/b&gt;
&lt;/a&gt;

The course covers greedy, dynamic programming, and NP-completeness.
The lectures were very clear, not too fast and not too slow.
Caveat: I watched lectures only when I needed.
My strategy was to try to solve the problems.
If I had trouble, I looked at the slides.
If the slides were cryptic, then I looked at the lectures.
So, I ended up seeing very few lectures.

I even learned an algorithm that I knew I should know but didn&#39;t: Karger&#39;s.
I think it&#39;s my favorite example of a randomized algorithm.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/geneticsevolution&quot;&gt;
&lt;b&gt;Introduction to Genetics and Evolution.&lt;/b&gt;
&lt;/a&gt;

The course covers the basic math of genetics.
I&#39;ll give two examples of things I remember now, more than one year after.

&lt;p&gt;
One idea is the Hardy-Weinberg equilibrium.
Suppose each individual has one of the three genes $aa$, $aA$, and $AA$.
I&#39;ll use the fancy word &lt;i&gt;allele&lt;/i&gt;: it means one of $a$ and $A$.
Reproduction works as follows:
Randomly choose an allele from each of the two parents, and put them together.
Hardy-Weinberg says that in an infinite population, the percent of each allele is constant.
So, if you start with half $a$s and half $A$s, you&#39;ll remain with half $a$s and half $A$s.

&lt;p&gt;
The other idea is genetic drift.
It says what happens when the population is not infinite.
What happens is that you&#39;ll have random variations.
Eventually, these lead to the extinction of one of the alleles.


&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/proglang&quot;&gt;
&lt;b&gt;Programming Languages.&lt;/b&gt;
&lt;/a&gt;

This course uses ML, Racket, and Ruby to illustrate basic principles of programming languages.
As usual in this kind of courses, you write a few interpreters.
The best time to take this course is after you&#39;ve learned your second language.
(I learned BASIC when I was 6; Pascal and C++ came when I was 14.
I think I would&#39;ve benefited most from this course when I was 15.
So, if you are 15, then you should try it!)

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/modernworld&quot;&gt;
&lt;b&gt;The Modern World: Global History since 1760.&lt;/b&gt;
&lt;/a&gt;

What I remember most vividly about this course is rather strange.
It is the soothing voice of the lecturer.
Even when I was disagreeing with what he said, I felt compelled to keep listening.

&lt;p&gt;
From what I recall, the quizzes were boring:
They simply tested a bunch of facts that happened to be mentioned in lectures.
The videos, on the other hand, always told a nice story.
These stories were clearly addressed to someone living in 2013.
For example, the lectures not only said that the West was weak in 1760.
They stressed this fact repeatedly, because a world in which the West is weak and insignificant is really difficult to imagine for the typical user of Coursera.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/nlangp&quot;&gt;
&lt;b&gt;Natural Language Processing.&lt;/b&gt;
&lt;/a&gt;

For this course, like for the Algorithms one, I did problems first.
I looked at the slides and watched the lectures only when I needed.
I ended up looking at most slides and almost no lecture video.
Which, I guess, means that the slides are self-sufficient.
From what I recall, doing the homeworks involved a substantial effort.

&lt;p&gt;
The topics covered are things like probabilistic grammars, tagging problems (e.g., noun, verb, &amp;hellip;), log-linear models, learning.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/optimization&quot;&gt;
&lt;b&gt;Discrete Optimization.&lt;/b&gt;
&lt;/a&gt;

Like for the other computer-related courses, I went directly for the homeworks.
In addition, I delayed doing most homeworks for the last week.
That turned out to be a huge mistake.
I simply couldn&#39;t do the homeworks at the rate of one per day, as I planned.
In fact, I thought at some point that I won&#39;t even get a passing grade.
I did, but I also learned that Coursera sometimes has tough courses.

So, what were the homeworks like?
I recall: knapsack, graph coloring, euclidean traveling salesman.
There was also some combination of bin packing and euclidean traveling salesman.
More importantly, I recall some tricks that I learned while doing the homeworks.
For example, for knapsack I used two tricks to get a good solution.
The standard dynamic programming runs in time proportional to the total weight.
This is troublesome because weight can be very large.
In that case, use a trick from physics: pick your units of measurement.
Strictly speaking, the unit of measure doesn&#39;t matter.
But, when one works in kilometers, one usually doesn&#39;t keep track of millimeters.
Thus, by &amp;lsquo;picking the unit&amp;rsquo; I actually mean &amp;lsquo;ignore the less important bits&amp;rsquo;.
When ignoring bits, you&#39;ll want to round up.
This way, you never try to fit more than possible in the knapsack.
The other trick is to repeat this process using the items that remained out, with better precision.

&lt;p&gt;
For travelling salesmen, I wrote some complicated solution that barely got medium points.
It did two main things, as I recall.
First, it used dynamic programming to do local optimizations.
Second, it greedily improved the tour by using a set of moves that I noticed empirically.
For an example of move, think of a crossing of edges.
These two edges are far apart in the current best tour, so local optimizations won&#39;t notice the crossing.
But, of course, you can look at all pairs of edges and check for intersections.
Once you notice the interesection, it&#39;s clear what to do to shorten the tour.


&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/humankind&quot;&gt;
&lt;b&gt;A Brief History of Humankind.&lt;/b&gt;
&lt;/a&gt;

This course was like the other history course: trivial (useless?) quizzes, but fascinating lectures.
Where the Modern History course would talk about personalities and their decisions, the Humankind History course would talk about the way of life of a typical person.
In this sense, the two courses complement each-other nicely.

&lt;p&gt;
The most vivid image that this course left in my mind is that of &amp;lsquo;shared imaginary worlds&amp;rsquo;.
Why do money have value?
Because we &lt;i&gt;believe&lt;/i&gt; that others believe that money have value.
This kind of circular reasoning has a certain appeal for a computer scientist.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/linearprogramming&quot;&gt;
&lt;b&gt;Linear and Integer Programming.&lt;/b&gt;
&lt;/a&gt;

This course was too easy for my taste.
They do recommend a resource that looks intriguing:
&lt;a href=&quot;http://stanford.edu/~boyd/cvxbook/&quot;&gt;the convex optimization book by Stephen Boyd&lt;/a&gt;.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/automata&quot;&gt;
&lt;b&gt;Automata.&lt;/b&gt;
&lt;/a&gt;

This course had two kinds of homework: multiple-choice quizzes and programming assignments.
Unexpectedly, I enjoyed the quizzes more.
Each quiz question tries to test whether you understood some concept.
You get treated as a computer program:
The quiz presents you with some (smallish) input data, you have to provide the right output.
If you repeat the quiz, you get some other input data that you have to process.
For one of the first quizzes, I managed to get a question wrong three times in a row.
I was trying to do it quickly, and I ended up being very slow.
The fourth time I moved slowly and checked my work.
I think this phenomenon appears often in real life:
People make fun of those that appear slow, but the slow ones often finish first.

&lt;p&gt;
Back to the course.
Why did I not like the programming assignments?
Because I was supposed to modify some Python scripts that were kinda crap.

&lt;p&gt;
To answer some questions, I had to look at the slides.
These were extremely clear &amp;mdash; I never needed to look at the video lectures.

&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/networksonline&quot;&gt;
&lt;b&gt;Social and Economic Networks: Models and Analysis.&lt;/b&gt;
&lt;/a&gt;

I learned something new from almost every video lecture.
The quizzes were rather easy, but only after I learned the vocabulary.
It wasn&#39;t possible to grasp the definitions from the slides, but the videos were very clear.
In other words, if you take this course and you don&#39;t already work in social networks, you&#39;ll have to watch the videos.
Which is a good thing.

&lt;p&gt;
Here&#39;s an example of the kind of stuff I remember.
Social networks are graphs.
In various circumstances it makes sense to talk about the utility of a social network.
A simple way to define this is as the sum of utilities of each vertex.
For an example, think of the co-author graph.
The vertices are authors, the edges represent an ongoing collaboration.
One particular author benefits from the time given by its co-authors.
In turn, this particular author offers his time to their co-authors.
In the simplest model, the time is divided equally.
Thus, the utility of a vertex $x$ is $1+\sum_{y \in N(x)} 1/|N(y)|$.
(The $1$ comes from the time spent by $x$ on their own stuff, and $1/|N(y)|$ appears because $y$ divides its time equally between its neighbors $N(y)$, one of those neighbours being $x$.)
Once you have such a simple model, you can ask questions like:
Which configurations are pairwise stable (meaning that there is no local incentive to create or delete edges)?
Which configurations correspond to global optima?
For the answers, you&#39;ll have to take the course.
(Well, you &lt;i&gt;could&lt;/i&gt; find out the answers yourself, of course.)


&lt;p&gt;
&lt;a href=&quot;https://www.coursera.org/course/smac&quot;&gt;
&lt;b&gt;Statistical Mechanics: Algorithms and Computations.&lt;/b&gt;
&lt;/a&gt;

This course is mostly about Markov chains.
You can think of Markov chains as a way to sample complicated probability distributions, or as a way to estimate integrals.
Come to think of it, the course is more about sampling and integrating than about Markov chains.
For example, when you get to the quantum stuff, you see that computing path integrals is better done using Levy paths.
These are a direct sampling technique, which works better than the Markov chain approach, in this case.

&lt;p&gt;
Also, these techniques can be used for optimization problems.
One example is the traveling salesman problem, which makes an appearance in one of the reviews above.
I was conceited, and expected that the program I wrote with more than one day of work would do better.
After all, I looked at the Python program provided by the instructors and it seemed very similar, except:
(1)&amp;nbsp;it did no local optimization using dynamic programming,
(2)&amp;nbsp;the vocabulary of moves was a small subset of the one I accumulated.
And yet, their implementation worked &lt;i&gt;much&lt;/i&gt; better.
Wat??
I had to take a look.
It turns out there was only one difference:
They sometimes allowed a move that made the tour worse.
(They used simulated annealing, rather than greedy.)
In other words, my solution was getting stuck in local optima.
I&#39;m not sure why I didn&#39;t think of this when I was doing the discrete optimization course.
(It seems obvious with hindsight.)
A good rule of thumb:
&lt;i&gt;Whenever you use greedy for an optimization problem, at least consider trying simulated annealing.&lt;/i&gt;


&lt;p&gt;
&lt;b&gt;Starting Soon.&lt;/b&gt;

Out of these courses, the ones that start soon are the following:

&lt;ul&gt;
&lt;li&gt;
  &lt;a href=&quot;https://www.coursera.org/course/humankind&quot;&gt;A Brief History of Humankind&lt;/a&gt;
  on August 10.
&lt;li&gt;
  &lt;a href=&quot;https://www.coursera.org/course/automata&quot;&gt;Automata&lt;/a&gt;
  on September 1.
&lt;li&gt;
  &lt;a href=&quot;https://www.coursera.org/course/networksonline&quot;&gt;Social and Economic Networks: Models and Analysis&lt;/a&gt;
  on September 21.
&lt;/ul&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/2130065838738711944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/08/coursera-courses.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2130065838738711944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/2130065838738711944'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/08/coursera-courses.html' title='Coursera Courses'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-1363145734306114901</id><published>2014-07-30T22:05:00.000+01:00</published><updated>2014-07-30T22:09:20.113+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="learning"/><category scheme="http://www.blogger.com/atom/ns#" term="research"/><title type='text'>At Most R</title><content type='html'>
&lt;p&gt;
&lt;i&gt;How to encode a cardinality constraint as boolean constraints.&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
&lt;b&gt;Motivation.&lt;/b&gt;
All problems in NP can be encoded as a SAT problem, because SAT is NP-complete.
Often you need to say that $x_1+\cdots+x_n \le r$.
For example, you might want to do this to reduce MAXSAT to SAT.
(And we know that &lt;a href=&quot;http://rgrig.blogspot.com/2014/06/datalog-and-maxsat-unexpected-match.html&quot;&gt;MAXSAT is useful for static analysis&lt;/a&gt;.)
MAXSAT is an optimization problem; SAT is its decision version.
The general strategy to reduce optimization to decision is to use binary search.
So that&#39;s what we&#39;ll do.

&lt;p&gt;
The input of MAXSAT is a set $\{C_1,\ldots,C_n\}$ of clauses.
The question is what is the maximum number of clauses that can be satisfied.
To solve this, we ask several SAT questions of the following form:

$$\begin{align}
(C_1 \lor y_1) \land (C_2 \lor y_2) \land\ldots\land (C_n \lor y_n)
  \land {\it encode}(y_1+\cdots+y_n \le r)
\end{align}$$

&lt;p&gt;
If $r=0$, then all the auxiliary variables $y_1,\ldots,y_n$ must be $0$.
In this case, the question asks if all clauses can be satisfied.
On the other hand, if $r=n$, then the answer is yes, by setting $y_1=\cdots=y_n=1$.
In general, the question asks the following:
&amp;lsquo;Is it possible to satisfy $n-r$ clauses (simultaneously)?&amp;rsquo;

&lt;p&gt;
&lt;b&gt;How to Do It.&lt;/b&gt;
I knew for some time that efficient encodings exist, but I didn&#39;t look them up.
At some point I needed the case $r=1$, and I was able to find a good solution.
Now that I read how the general $r$ works I think the encoding is kinda cute.
The encoding was found by Carsten Sinz in 2005.

&lt;p&gt;
Here&#39;s an example for $r=6$:

&lt;pre&gt;
&lt;span style=&quot;background:gray&quot;&gt;10100001011010110111&lt;/span&gt;
 1&lt;span style=&quot;background:gray&quot;&gt;100001011010110111&lt;/span&gt;
  11&lt;span style=&quot;background:gray&quot;&gt;0001011010110111&lt;/span&gt;
   11&lt;span style=&quot;background:gray&quot;&gt;001011010110111&lt;/span&gt;
    11&lt;span style=&quot;background:gray&quot;&gt;01011010110111&lt;/span&gt;
     11&lt;span style=&quot;background:gray&quot;&gt;1011010110111&lt;/span&gt;
      111&lt;span style=&quot;background:gray&quot;&gt;11010110111&lt;/span&gt;
       11111&lt;span style=&quot;background:gray&quot;&gt;10110111&lt;/span&gt;
        &lt;span style=&quot;background:red&quot;&gt;1111111&lt;/span&gt;&lt;span style=&quot;background:gray&quot;&gt;10111&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;
What&#39;s happening here?
I&#39;m pushing the &lt;tt&gt;1&lt;/tt&gt;s to the right.
Once I see a group of more than $6$ I say &lt;span style=&quot;background:red&quot;&gt;BAD!&lt;/span&gt;.
But how exactly do we push &lt;tt&gt;1&lt;/tt&gt;s with a boolean circuit?
And how many auxiliary variables do we need?
Clearly, the &lt;span style=&quot;background:gray&quot;&gt;gray&lt;/span&gt; ones are just the original values.
But what&#39;s the general rule to compute the others?

&lt;p&gt;
Here&#39;s the same computation, but more explicit this time.

&lt;pre&gt;
&lt;span style=&#39;background:#f00&#39;&gt;1&lt;/span&gt;0&lt;span style=&#39;background:#0f0&#39;&gt;1&lt;/span&gt;0000&lt;span style=&#39;background:#00f&#39;&gt;1&lt;/span&gt;0&lt;span style=&#39;background:#ff0&#39;&gt;11&lt;/span&gt;0&lt;span style=&#39;background:#f0f&#39;&gt;1&lt;/span&gt;0&lt;span style=&#39;background:#0ff&#39;&gt;1&lt;/span&gt;10111
0000000
&lt;span style=&#39;background:#f00&#39;&gt;1&lt;/span&gt;000000            drop
 1000000           shift
 1&lt;span style=&#39;background:#0f0&#39;&gt;1&lt;/span&gt;00000           drop
  1100000          shift
   1100000         shift
    1100000        shift
     1100000       shift
     11&lt;span style=&#39;background:#00f&#39;&gt;1&lt;/span&gt;0000       drop
      1110000      shift
      111&lt;span style=&#39;background:#ff0&#39;&gt;11&lt;/span&gt;00      drop
       1111100     shift
       11111&lt;span style=&#39;background:#f0f&#39;&gt;1&lt;/span&gt;0     drop
        1111110    shift
        111111&lt;span style=&#39;background:#0ff&#39;&gt;1&lt;/span&gt;    drop
&lt;/pre&gt;

&lt;p&gt;
This time the original variables are in the first line, and all the others are auxiliaries.
There are two kinds of steps that alternate.
First, there are steps in which the group of $r+1$ auxiliaries are shifted to the right.
Second, there are steps where a group of consecutive &lt;tt&gt;1&lt;/tt&gt;s are dropped from the first row.
These &lt;tt&gt;1&lt;/tt&gt;s are dropped only if they would come adjacent to the &lt;tt&gt;1&lt;/tt&gt;s that were dropped earlier.
I omit some of these steps when they are not interesting.
For example, if no &lt;tt&gt;1&lt;/tt&gt;s are dropped, then I omit the dropping step.

&lt;p&gt;
Hongseok Yang described this process as &amp;lsquo;moving a basked underneath the original values, and collecting the &lt;tt&gt;1&lt;/tt&gt;s&amp;rsquo;.
I think that&#39;s a pretty good image to have in mind.

&lt;p&gt;
It should now be clear how this is done with a boolean circuit.
Dropping is done with AND-gates, between the auxiliary from the left and the original from above.
Next, any boolean circuit can be transformed into a conjunctive normal form, using the Tseitin transformation.

&lt;p&gt;
&lt;b&gt;Details.&lt;/b&gt;
If the original variables are $x_1,\ldots,x_n$, then we introduce auxiliaries $y_i^j$ for $1 \le i \le r+1$ and $0 \le j$ and $i+j \le n$.
The clauses are
$$\begin{align}
y_i^{j-1} &amp;amp;\to y_i^j &amp;amp;&amp;amp;\text{for shifting} \\
y_{i-1}^j \land x_{i+j} &amp;amp;\to y_i^j &amp;amp;&amp;amp;\text{for dropping} \\
y_1^j\land y_2^j \land\ldots\land y_{r+1}^j &amp;amp;\to 0 &amp;amp;&amp;amp; \text{for detecting bad situations}
\end{align}$$

&lt;p&gt;
Yes, I am being sloppy with some boundary situations.
Also, I&#39;m using slightly more variables than necessary:
Can you see how batches of $r$ auxiliaries (rather than batches of $r+1$ auxiliaries) are enough?

&lt;p&gt;
&lt;b&gt;Others.&lt;/b&gt;
There&#39;s also an encoding based on dividing the array of booleans in half.
You compute for each half if you have &lt;i&gt;at least&lt;/i&gt; $k$ &lt;tt&gt;1&lt;/tt&gt;s, for $1 \le k \le r+1$.
You then aggregate the results for halves into the result for the whole array.

&lt;p&gt;
Using either of these methods you can encode equality constraints, like $x_1+\cdots+x_n=r$.
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/1363145734306114901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/07/at-most-r.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1363145734306114901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/1363145734306114901'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/07/at-most-r.html' title='At Most R'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5829875.post-6599395327929278708</id><published>2014-07-24T21:17:00.000+01:00</published><updated>2014-07-24T21:17:42.885+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="coding"/><title type='text'>Depth First Search in Python</title><content type='html'>&lt;p&gt;
&lt;i&gt;Everybody thinks they understand depth-first search.
The algorithm is indeed simple.
But &amp;mdash; I think &amp;mdash; it is deceptively simple.
In this post I play with some code.
&lt;/i&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;p&gt;
Given a graph like

&lt;pre class=&quot;prettyprint&quot;&gt;
g = { 0 : [1, 2]
    , 1 : [0, 3]
    , 2 : [0, 3]
    , 3 : [1, 2] }
&lt;/pre&gt;

&lt;p&gt;
you are most likely to see DFS implemented as some variation of the following:

&lt;pre class=&quot;prettyprint&quot;&gt;
def dfs_a(g, root):
  seen = set()
  def rec(x):
    seen.add(x)
    for y in g[x]:
      if y not in seen:
        rec(y)
  rec(root)
&lt;/pre&gt;

&lt;p&gt;
This is not bad, but it has two issues.
One is that it hides lots of cool features of DFS.
Another is that Python is crap at recursion.

&lt;p&gt;
Let&#39;s first expand the code to expose a few properties of the algorithm.

&lt;pre class=&quot;prettyprint&quot;&gt;
def dfs_b(g):
  seen, done = {}, {}
  time = 0
  def previsit(x):
    nonlocal time
    time += 1
    seen[x] = time
    print(&#39;previsit&#39;,x,&#39;at time&#39;,time)
  def postvisit(x):
    nonlocal time
    time += 1
    done[x] = time
    print(&#39;postvisit&#39;,x,&#39;at time&#39;,time)
  def rec(y):
    for z in g[y]:
      if z in done:
        print(&#39;cross arc from&#39;,y,&#39;to&#39;,z)
        continue
      if z in seen:
        print(&#39;back arc from&#39;,y,&#39;to&#39;,z)
        continue
      previsit(z)
      rec(z)
      postvisit(z)
  for x in g.keys():
    if x in done:
      print(&#39;already visited&#39;,x)
      continue
    previsit(x)
    rec(x)
    postvisit(x)
&lt;/pre&gt;

&lt;p&gt;
A few things to notice:

&lt;ul&gt;
&lt;li&gt;Sometimes you&#39;ll want to iterate over all vertices, instead of using one root.
&lt;li&gt;
  There is a time when you first get to a vertex, and a time when you leave the vertex.
  These times are well-bracketed.
  That is if the times for vertex $x$ are $(a_x,b_x)$ and those for vertex $y$ are $(a_y,b_y)$,
    then these two intervals either are disjoint, or one includes the other.
&lt;li&gt;
  The post-order of the vertices is what you get if you grep for &lt;tt&gt;postvisit&lt;/tt&gt;.
  The pre-order of the vertices is what you get if you grep for &lt;tt&gt;previsit&lt;/tt&gt;.
  The post-order is useful, for example, in
    &lt;a href=&quot;http://en.wikipedia.org/wiki/Kosaraju&#39;s_algorithm&quot;&gt;Kosaraju&#39;s algorithm&lt;/a&gt;
  to find strongly connected components.
&lt;li&gt;
  There is a difference between back arcs and cross arcs!
  To distinguish them, you need &lt;i&gt;two&lt;/i&gt; bits per vertex.
  In this implementation I used the dictionaries &lt;tt&gt;seen&lt;/tt&gt; and &lt;tt&gt;done&lt;/tt&gt;.
  If you know you don&#39;t have cycles, you can get rid of &lt;tt&gt;seen&lt;/tt&gt;.
  (You might know this, say, if you look at the graph of GIT commits.)
  If you know you don&#39;t have cross arcs, you can get rid of &lt;tt&gt;done&lt;/tt&gt;.
  (Note: A graph is reducible iff its set of back arcs doesn&#39;t depend on the order of the
  &lt;tt&gt;for&lt;/tt&gt; loops above.)
&lt;/ul&gt;

&lt;p&gt;
What about complexity?
If the graph has $m$ arcs and $n$ vertices, then the time is $\Theta(m+n)$ and the space is $\Theta(n)$.

&lt;p&gt;
Now on to the second problem.
Run this code:

&lt;pre class=&quot;prettyprint&quot;&gt;
n = 0
try:
  def go():
    global n
    n += 1
    go()
  go()
except:
  print(&#39;gave up at&#39;,n)
&lt;/pre&gt;

&lt;p&gt;
On my computer it says &lt;tt&gt;gave up at 999&lt;/tt&gt;.
Even puny graphs have 999 vertices!

&lt;p&gt;
But we can make the call stack explicit.
For this, we need to notice what state does &lt;code&gt;rec&lt;/code&gt; have.
Very little: the current vertex and the state of the iterator.
The transformation into the code below is almost automatic.

&lt;pre class=&quot;prettyprint&quot;&gt;
def dfs_c(g):
  seen, done = {}, {}
  time = 0
  def previsit(x):
    nonlocal time
    time += 1
    seen[x] = time
    print(&#39;previsit&#39;,x,&#39;at time&#39;,time)
  def postvisit(x):
    nonlocal time
    time += 1
    done[x] = time
    print(&#39;postvisit&#39;,x,&#39;at time&#39;,time)
  for x, ys in g.items():
    if x in done:
      print(&#39;already visited&#39;,x)
      continue
    previsit(x)
    stack = [(x, ys.__iter__())]
    while stack:
      y, i = stack.pop()
      try:
        z = next(i)
        stack.append((y, i))
        if z in done:
          print(&#39;cross arc from&#39;,y,&#39;to&#39;,z)
          continue
        if z in seen:
          print(&#39;back arc from&#39;,y,&#39;to&#39;,z)
          continue
        previsit(z)
        stack.append((z, g[z].__iter__()))
      except StopIteration:
        postvisit(y)
&lt;/pre&gt;

&lt;p&gt;
I must admit: This looks a bit scary.
One reason why it does is that it keeps explicit all these distinction that &lt;i&gt;could&lt;/i&gt; be of use.
For example, the post-visiting is useful for computing SCCs, but sometimes is not.
So, it&#39;s now time to strip all these, and go back to the first piece of code.
The only modification I&#39;ll keep is the change from recursion to a loop.

&lt;pre class=&quot;prettyprint&quot;&gt;
def dfs_d(g, root):
  seen = set([root])
  stack = [(root, g[root].__iter__())]
  while stack:
    try:
      x, i = stack.pop()
      y = next(i)
      stack.append((x, i))
      if y not in seen:
        seen.add(y)
        stack.append((y, g[y].__iter__()))
    except StopIteration:
      pass
&lt;/pre&gt;

&lt;p&gt;
This is almost simple.
But, hey, if I google for &amp;lsquo;depth-first search python&amp;rsquo;, then I get
&lt;a href=&quot;http://eddmann.com/posts/depth-first-search-and-breadth-first-search-in-python/&quot;&gt;this code by Edward Mann&lt;/a&gt;.

&lt;pre class=&quot;prettyprint&quot;&gt;
def dfs(graph, start):
    visited, stack = set(), [start]
    while stack:
        vertex = stack.pop()
        if vertex not in visited:
            visited.add(vertex)
            stack.extend(graph[vertex] - visited)
    return visited
&lt;/pre&gt;

&lt;p&gt;
This code is even simpler!
Yes, it is, and you should use it: compared to the other top-results from google that I saw, this one is clearly the best.
It has only one problem: The memory use is $\Theta(m)$ rather than $\Theta(n)$.
This means that for dense graphs you might want to write a bit of extra code to deal with iterators.

&lt;p&gt;
What&#39;s the point of the other variants?
The point is that they are more general.
By studying them, you should get a better feeling of what DFS does.
For example, you might be able to decode this:

&lt;p&gt;Algorithm for finding strongly connected components:
&lt;ol&gt;
&lt;li&gt;using DFS on the original graph, sort vertices in reverse post-order
&lt;li&gt;using DFS on the reversed graph, find components; for the outer loop of this DFS use the order built at step 1
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rgrig.blogspot.com/feeds/6599395327929278708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rgrig.blogspot.com/2014/07/depth-first-search-in-python.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6599395327929278708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5829875/posts/default/6599395327929278708'/><link rel='alternate' type='text/html' href='http://rgrig.blogspot.com/2014/07/depth-first-search-in-python.html' title='Depth First Search in Python'/><author><name>rgrig</name><uri>http://www.blogger.com/profile/02991214367108471744</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>