Jekyll2022-08-28T04:25:37+00:00/feed.xmlBen KushigianPL&SENash Equilibrium Quiz2022-08-27T17:28:50+00:002022-08-27T17:28:50+00:00/2022/08/27/nash-equilibrium-quiz<h1 id="nash-equilibrium-quiz">Nash Equilibrium Quiz</h1>
<p>I’m going to ask you a few questions to test your understanding of a Nash
equilibrium. The answers to the first two questions come from the definition of
Nash Equilibrium; the answer to the third involves some thinking.</p>
<ul>
<li>
<p><em>Definition of Nash Equilibrium</em>:</p>
<blockquote>
<p>A Nash equilibrium (for a 2-player game) between players <em>X</em> and <em>Y</em> is a pair
of strategies <em>S = (Sx, Sy)</em> for <em>X</em> and <em>Y</em> respectively such that when both
players use these strategies, neither can unilaterally alter their strategy to
increase their payout.</p>
</blockquote>
</li>
</ul>
<p>I’ll start off listing questions and then I’ll give the solutions below.</p>
<h2 id="questions">Questions</h2>
<h3 id="question-1-comparing-different-equilibrium-strategies">Question 1: Comparing Different Equilibrium Strategies</h3>
<blockquote>
<p>Suppose you are playing rake free HUNL (heads up no limit) and you’ve
discovered two different equilibrium strategies <em>S</em> and <em>T</em>. Is it possible
for <em>EV(S) > EV(T)</em>? If so, provide an example. Otherwise, prove that this is
impossible.</p>
</blockquote>
<h3 id="question-2-unused-lines-in-a-gametree">Question 2: Unused Lines in a Gametree</h3>
<blockquote>
<p>Suppose that we have an equilibrium strategy <em>S = (Sx, Sy)</em> for players <em>X</em>
and <em>Y</em> such that player <em>X</em> never uses a particular action <em>A</em> at a given
node in the game-tree. Now, suppose we modify the game-tree to remove <em>X</em>’s
option to take action <em>A</em> at that node. Can <em>Y</em> modify their strategy <em>Sy</em> to
exploit this altered game-tree (that is, can <em>Y</em> increase their payout in any
way?)</p>
</blockquote>
<h3 id="question-3-nash-equilibria-as-fixed-points-of-maximally-exploitative-strategy-sequences">Question 3: Nash Equilibria as Fixed-points of Maximally Exploitative Strategy Sequences</h3>
<blockquote>
<p>Suppose you are playing HUNL rake free. You and your opponent start off with
strategies S0 and T0. You adjust your strategy to maximally exploit T0,
resulting in S1. Villain then adjusts to maximally exploit your new strategy,
resulting in T1. You continue iteratively exploiting each other until you reach
a fixed point (neither one of you can do any better).</p>
<ol>
<li>Is this fixed point always an equilibrium pair?</li>
<li>Do you always reach such a fixed point?</li>
</ol>
</blockquote>
<h2 id="solutions">Solutions</h2>
<h3 id="question-1">Question 1</h3>
<p>It is impossible that <em>EV(S) > EV(T)</em> for equilibrium strategies <em>S = (Sh, Sv)</em>
and <em>T = (Th, Tv)</em>; here <em>Sh</em> and <em>Th</em> are Hero’s (that is to say, your),
equilibrium strategies, and <em>Sv</em> and <em>Tv</em> are villain’s equilibrium strategies.</p>
<p>Let’s prove by contradiction. Suppose that hero’s payout is higher for <em>S</em> than
it is for <em>T</em>; that is, <em>P(S)> P(T)</em>. Let’s look at what happens when Hero plays
<em>Sh</em> against villain’s <em>Tv</em>. Since <em>Sh</em> is part of an equilibrium strategy it
must win Hero at least <em>P(S) > P(T)</em>. This means that Hero could have used <em>Sh</em>
against villains <em>Tv</em> and gotten a payout higher than if they’d used strategy
<em>Th</em>. Since <em>(Th, Tv)</em> is an equilibrium pair this is impossible, and we’ve
derived a contradiction. Since we’ve derived a contradiction we conclude that it
is impossible for two equilibria to have different expected payouts.</p>
<h3 id="question-2">Question 2</h3>
<p>Deleting an action unused by player <em>X</em> from the game-tree does not open a
<em>X</em> up to being exploited. This again follows from the definition of Nash
equilibrium: any strategy that would exploit this lack of a line would be
gaining EV against X’s equilibrium strategy.</p>
<p>In more detail, fix X’s equilibrium strategy <em>Sx</em> and move it to the new
game-tree with action <em>A</em> removed from the game-tree. If player <em>Y</em> exploits
this strategy in the new game tree then they have increased their payout against
<em>Sx</em>. But <em>Sx</em> has not changed at all, and this new exploitative strategy from
<em>Y</em> would also be exploiting <em>Sx</em> in the original game tree, contradicting that
<em>Sx</em> was an equilibrium strategy to begin with.</p>
<h3 id="question-3">Question 3</h3>
<ol>
<li>
<p>When a fixed point is reached it is always an equilibrium. This follows
directly from the definition of a Nash equilibrium: a fixed point is simply a
pair of strategies such that neither player can unilaterally increase their
payout by altering their strategy.</p>
</li>
<li>
<p>Such a fixed point is not always reached. In particular, finding maximally
exploitative strategies does not handle mixing. A classic example is the AKQ
game. If the polar player is under bluffing then the condensed player always
folds, which makes the polar player always bluff, which makes the condensed
player always call, which makes the polar player never bluff, which makes the
condensed player always fold, etc.</p>
</li>
</ol>Nash Equilibrium Quiz I’m going to ask you a few questions to test your understanding of a Nash equilibrium. The answers to the first two questions come from the definition of Nash Equilibrium; the answer to the third involves some thinking.On Confidence Intervals and Probabilities2022-02-03T03:28:50+00:002022-02-03T03:28:50+00:00/2022/02/03/on-cis-and-probabilities<h1 id="the-problem">The problem</h1>
<p>My professor made a statement today which I really hated. We were chatting about
confidence intervals. Suppose we have some normally distributed population
<code class="language-plaintext highlighter-rouge">p ~ N(10, 1)</code> with a mean of 10 and a standard deviation of 1. Let <code class="language-plaintext highlighter-rouge">X</code> be a
size-100 random sample from <code class="language-plaintext highlighter-rouge">p</code>. Suppose we compute the 95% confidence interval
<code class="language-plaintext highlighter-rouge">I = (u, v)</code> for the mean of <code class="language-plaintext highlighter-rouge">p</code>. The question is: what is the probability that
<code class="language-plaintext highlighter-rouge">mean(p)</code> is inside <code class="language-plaintext highlighter-rouge">I</code>?</p>
<p>Let’s look at an example:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">BSDA</span><span class="p">)</span><span class="w"> </span><span class="c1"># For Z test</span><span class="w">
</span><span class="n">set.seed</span><span class="p">(</span><span class="m">8</span><span class="p">)</span><span class="w">
</span><span class="n">p</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="n">val</span><span class="o">=</span><span class="n">rnorm</span><span class="p">(</span><span class="m">1000000</span><span class="p">,</span><span class="w"> </span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">mean</span><span class="p">(</span><span class="n">p</span><span class="o">$</span><span class="n">val</span><span class="p">)</span><span class="w">
</span><span class="n">sd</span><span class="p">(</span><span class="n">p</span><span class="o">$</span><span class="n">val</span><span class="p">)</span><span class="w">
</span><span class="n">N</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">100</span><span class="w"> </span><span class="c1"># Sample size</span><span class="w">
</span><span class="n">X</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="n">p</span><span class="o">$</span><span class="n">val</span><span class="p">,</span><span class="w"> </span><span class="n">N</span><span class="p">,</span><span class="w"> </span><span class="n">replace</span><span class="o">=</span><span class="nb">F</span><span class="p">)</span><span class="w">
</span><span class="n">z.test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">sigma.x</span><span class="o">=</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">mu</span><span class="o">=</span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="n">conf.level</span><span class="o">=</span><span class="m">0.90</span><span class="p">)</span><span class="w"> </span><span class="c1"># 90% CI, I1</span><span class="w">
</span><span class="n">z.test</span><span class="p">(</span><span class="n">X</span><span class="p">,</span><span class="w"> </span><span class="n">sigma.x</span><span class="o">=</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">mu</span><span class="o">=</span><span class="m">10</span><span class="p">,</span><span class="w"> </span><span class="n">conf.level</span><span class="o">=</span><span class="m">0.95</span><span class="p">)</span><span class="w"> </span><span class="c1"># 95% CI, I2</span><span class="w">
</span></code></pre></div></div>
<p>This outputs the following (truncated) text describing two z-Tests, one with a 90% confidence interval and one with a 95% confidence interval.</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] Population mean: 9.99916568117066
[1] Population std: 9.99916568117066
One-sample z-Test
data: X
z = 1.8306, p-value = 0.06716
alternative hypothesis: true mean is not equal to 10
90 percent confidence interval:
10.01857 10.34754
sample estimates:
mean of x
10.18306
One-sample z-Test
data: X
z = 1.8306, p-value = 0.06716
alternative hypothesis: true mean is not equal to 10
95 percent confidence interval:
9.987062 10.379055
sample estimates:
mean of x
10.18306
</code></pre></div></div>
<p>For simplicity, here is the population mean and the confidence intervals:</p>
<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] Population mean: 9.99916568117066
90 percent confidence interval:
10.01857 10.34754
95 percent confidence interval:
9.987062 10.379055
</code></pre></div></div>
<p>So Prof asks “What’s the probability that the population mean is in the 90%
confidence interval?” and everyone says “90%”. Prof is all “lulz nah it’s 0”,
and we’re like “well yeah, obviously, but you know what we mean..” and that’s
when he drops one on us: he says that a 90% confidence interval doesn’t have a
90% chance of containing the population mean. It has either a 0% chance or 100%
chance.</p>The problemDonking and CBetting | Lojack versus Big Blind | Flop: 887 Rainbow2021-02-09T17:28:50+00:002021-02-09T17:28:50+00:00/2021/02/09/lj-cbetting-887r<p>I came across an interesting scenario while working with PokerSnowie today.</p>
<h2 id="scenario">Scenario</h2>
<p>6max, 100bb effective</p>
<ul>
<li><strong>Preflop:</strong>
<ul>
<li>LJ opens for 2.5bb</li>
<li>Action folds to BB who calls</li>
</ul>
</li>
<li><strong>Flop:</strong>
<ul>
<li>Flop comes 8d8c7s (rainbow)</li>
</ul>
</li>
</ul>
<p><img src="/poker/resources/img/887r-board.png" alt="Board on the flop" /></p>
<p>I’m interested the following questions:</p>
<ol>
<li>does BB ever donk here?</li>
<li>what does LJ continue with?</li>
</ol>
<h2 id="preflop-charts">Preflop Charts</h2>
<p>Here are the preflop charts from PS (these are approximate, and doesn’t
differentiate between some mixed 3betting in the BB):</p>
<ul>
<li>
<p><strong>LJ: raise 15% of hands:</strong> 66+, A2s+, K9s+, QTs+, JTs, ATo+, KJo+</p>
<p><img src="/poker/resources/img/6max-lj-open.png" alt="LJ Open" /></p>
</li>
<li>
<p><strong>BB: call with 18% of hands:</strong> 22-TT, A2s-A9s, K4s, K6s+, Q8s+, J8s+, T8s+,
97s+, 86s+, 75s+, 64s+, 53s+, ATo-AQo, KJo+, QJo</p>
<p><img src="/poker/resources/img/6max-bb-call-v-lj-open.png" alt="BB Call" /></p>
</li>
</ul>
<p>PokerCruncher gives LJ about 55.52 equity advantage.</p>
<h2 id="question-1-does-bb-donk">Question 1: Does BB Donk?</h2>
<p>BB and LJ have about the same number of combos of the nuts in their range
(actually, BB 3bets 88 every once and a while), and since BB’s range is larger
than LJ’s range, 88 and 77 make up a larger proportion of LJ’s range than BB’s range.</p>
<p>However, BB also has a 98s-A8s, for an extra 12x trips, and 87s,97s,K7s,and A7s,
for an extra 12x second pair. While this doesn’t give BB the equity advantage,
it <em>does</em> mean that BB is connecting with this flop in relatively nutty ways
that LJ can’t, and that means it might make sense to develop a donking range:</p>
<p><strong>Hypothesis:</strong> Given that BB has a nuts advantage, BB will donk bet on this
flop with 88, 77, some 8x, as well as some bluffs.</p>
<h3 id="what-hands-will-bb-donk-with">What hands will BB donk with?</h3>
<h4 id="my-guess">My guess</h4>
<p>I think that BB will donk with 88, 87, 77, and maybe a couple other 8x and 7x
hands. I also think that T9 and 65 might bet here. I’m not sure what bluffs BB
would add.</p>
<h4 id="pokersnowie">PokerSnowie</h4>
<p>PokerSnowie advocates that BB donk 1/2 pot about 7% of the time:</p>
<p><img src="/poker/resources/img/887r-donk.png" alt="BB Donk" /></p>
<p>There are some surprising things here:</p>
<ol>
<li>
<p><strong>88 is only bet 25% of the time</strong></p>
<p>Since we will mainly be checking this keeps our checking range strong,
allowing us to x/r.</p>
</li>
<li>
<p><strong>77 is almost never bet (about 7% of the time)</strong></p>
<p>Again, allows us to x/r effectively. I’m surprised we aren’t betting out here
more though.</p>
</li>
<li>
<p><strong>No 8x are bet.</strong></p>
<p>This is surprising because flopping trips here is pretty nutty. However,
given the ability to x/r, this actually makes sense.</p>
<p>For instance, given Q8h, what turn cards are we afraid of? JTs gets there on
a 9, and even then we have around 14% equity. Obviously overpairs might make
a boat, but this also shouldn’t be too likely. With no flush draws on the
board, we are pretty secure against any turn cards, and giving LJ a chance to
cbet is probably higher EV.</p>
</li>
<li>
<p><strong>A bunch of suited queens are bet: QJs, QTs, and Q9s w/ a BDFD are all bet
here 100%.</strong></p>
<p>This surprised me, and is actually why I’m writing this. I want to figure out
what these QXs are doing in the donking range.</p>
<p>I also noticed that these hands are being cbet by LJ, so there is <em>something</em>
going on with these hands.</p>
</li>
<li>
<p><strong>BB’s donk range has more bluffs than value bets.</strong></p>
</li>
</ol>
<p>There are about 8.5 combos of the Qx bluffs and only 3-4 combos of ‘made hands’
(including a 7 or an 8). PS is betting 1/2 pot here, so I guess by combining
fold equity along with potential to improve and getting paid when we have the
nuts, this might make sense? But it’s really weird that we have more bluffs here
than value bets.</p>
<h3 id="why-donk-with-qx">Why donk with Qx?</h3>
<p>Here are the possible reasons I can think of:</p>
<h4 id="blockers"><strong>Blockers</strong></h4>
<p>The Qx hands are all blocking over-pairs 99-QQ</p>
<h4 id="fold-equity"><strong>Fold Equity</strong></h4>
<p>These hands benefit from folds from hands like Ax and Qx, and maybe hands
like 66. Hands like KTs-KQs don’t benefit from fold equity as much because there
are fewer overcards that beat us. QT getting KJ to fold is much better than vice
versa.</p>
<h4 id="potential-to-improve"><strong>Potential To Improve</strong></h4>
<p>First, all of these hands are BDFDs and can possibly make nut straights.</p>
<h3 id="revising-hypothesis">Revising Hypothesis</h3>
<p>I’m revising my hypothesis:</p>
<p><em><strong>Hypothesis 2.0:</strong> On MMM paired flop (i.e., three medium cards from 6-9 with
a pair) the BB has the nuts advantage and will donk bet on this flop with a small
percentage of nutty made hands like 88, 77, and some weaker made hands, as well
as around 1.5x-2x as many bluffs that (a) have good blocking potential, (b)
benefit from folds, and (c) have a potential to improve.</em></p>
<p>I can test this on other flops to see if the pattern continues.</p>
<h2 id="question-2-what-does-lj-continue-with-here">Question 2: What does LJ continue with here?</h2>
<h3 id="my-guess-1">My guess</h3>
<p>LJ has an equity advantage but not the nuts advantage. This is a relatively
dynamic board: any 8x is clearly nutted and probably can bet to the river for
value. However, a paired 7 is vulnerable. BB has some OESDs (65s, T9s) that
probably won’t fold, but we still have good equity against those.</p>
<p>Because of the nuts advantage we don’t want to bet too wide because of the risk
of x/r. Therefore I think we will want to bet about half of our range about 1/2
pot, including:</p>
<ul>
<li>A8, 88</li>
<li>A7</li>
<li>99+</li>
<li>Some bluffs:
<ul>
<li><strong>Question:</strong> what hands make the best bluffs?</li>
<li><strong>Answer:</strong> we kinda already answered this above (and I also already saw
this from PokerSnowie, so I cheated): the QTs+ hands w/ a BDFD make very
good bluffing candidates because they (a) benefit from folding out Kx and Ax
hands, (b) have potential to improve on later streets (straights, flushes,
pairing the turn/river), and (c) block some overpairs that BB might have.</li>
</ul>
</li>
</ul>
<h3 id="pokersnowies-answer">PokerSnowie’s answer</h3>
<p>PokerSnowie suggests cbetting 1/2 pot with only 23% of hands:</p>
<p><img src="/poker/resources/img/887r-lj-cbet.png" alt="LJ Cbet" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's CBetting range">
<b>Lojack's CBetting range:</b>
<i>The lojack continues with any 7 or 8, as well as most Qx and Kx
holdings. Ax doesn't cbet, presumably because they aren't as
vulnerable to an A on the turn/river</i>
</p>
<p>This is a polarized range. Overpairs and A-high don’t bet, but nutted hands like
88, 77, A8 and A7 continue.</p>
<h2 id="experiment-design">Experiment design</h2>
<p>Unfortunately I don’t have access to a solver, so all experiments will be by
hand using PokerSnowie (i.e., I can’t script PioSOLVER).</p>
<p>To test my hypothesis I want to</p>
<ol>
<li>Try a number of paired MMM flops
<ul>
<li>Does rainbow matter?</li>
<li>Does adding a gap matter?</li>
<li>Does making the unpaired higher than the paired cards matter?</li>
</ul>
</li>
<li>Try some MML paired flops
<ul>
<li>Does changing the unpaired card to a low card matter?</li>
</ul>
</li>
</ol>
<p>To test this, I am going to investigate two of each of the following flop
textures:</p>
<ol>
<li>MMM paired/rainbow/no gaps (e.g., 887r)</li>
<li>MMM paired/rainbow/1 gap (e.g., 886r)</li>
<li>MMM paired/rainbow/unpaired>paired (e.g., 877r)</li>
<li>MMM paired/two-tone (e.g., 8s8d7s)</li>
<li>MML paired/rainbow (e.g., 883r)</li>
</ol>
<p>I will randomly generate the ranks (when there are more than two possible
flops). The suits will be chosen by hand since they don’t matter.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">random</span>
<span class="n">l</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
<span class="n">m</span> <span class="o">=</span> <span class="p">[</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">9</span><span class="p">]</span>
<span class="n">h</span> <span class="o">=</span> <span class="p">[</span><span class="mi">10</span><span class="p">,</span><span class="mi">11</span><span class="p">,</span><span class="mi">12</span><span class="p">,</span><span class="mi">13</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">make_paired_flop</span><span class="p">(</span><span class="n">ranks</span><span class="o">=</span><span class="s">'mm'</span><span class="p">,</span> <span class="n">paired_is_higher</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">gap</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">paired_card</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="n">ranks</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
<span class="n">unpaired_card</span> <span class="o">=</span> <span class="n">random</span><span class="p">.</span><span class="n">choice</span><span class="p">(</span><span class="nb">eval</span><span class="p">(</span><span class="n">ranks</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
<span class="k">if</span> <span class="n">paired_card</span> <span class="o">==</span> <span class="n">unpaired_card</span><span class="p">:</span> <span class="k">continue</span>
<span class="k">if</span> <span class="n">paired_is_higher</span> <span class="ow">and</span> <span class="n">paired_card</span> <span class="o"><</span> <span class="n">unpaired_card</span><span class="p">:</span> <span class="k">continue</span>
<span class="k">if</span> <span class="n">gap</span> <span class="o">^</span> <span class="p">((</span><span class="n">paired_card</span> <span class="o">-</span> <span class="n">unpaired_card</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">):</span>
<span class="k">return</span> <span class="s">"{}{}{}"</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">paired_card</span><span class="p">,</span> <span class="n">paired_card</span><span class="p">,</span> <span class="n">unpaired_card</span><span class="p">)</span>
</code></pre></div></div>
<p>I explore these:</p>
<ul>
<li><a href="/2021/02/09/mmm-paired-rainbow-nogap.html">MMM Rainbow/Paired/No Gap</a>.</li>
</ul>I came across an interesting scenario while working with PokerSnowie today.Donking and CBetting | Lojack versus Big Blind | MMM Rainbow/Paired/No Gap2021-02-09T17:28:50+00:002021-02-09T17:28:50+00:00/2021/02/09/mmm-paired-rainbow-nogap<p>In my <a href="/2021/02/09/lj-cbetting-887r.html">previous post</a> I looked at
the scenario where LJ opens for 2.5bb, BB calls, and flop comes 887 rainbow. I
looked at PokerSnowie output, tried to interpret it, and formed a hypothesis
based on this interpretation:</p>
<p><em><strong>Hypothesis 2.0:</strong> On MMM paired flop (i.e., three medium cards from 6-9 with
a pair) the BB has the nuts advantage and will donk bet on this flop with a small
percentage of nutty made hands like 88, 77, and some weaker made hands, as well
as around 1.5x-2x as many bluffs that (a) have good blocking potential, (b)
benefit from folds, and (c) have a potential to improve.</em></p>
<p>In this post I intend to test this hypothesis for , and to investigate the followup
questions I asked in my last post.</p>
<h1 id="preflop-ranges">Preflop Ranges</h1>
<p>Here are the preflop charts from PS (these are approximate, and doesn’t
differentiate between some mixed 3betting in the BB):</p>
<ul>
<li>
<p><strong>LJ: raise 15% of hands:</strong> 66+, A2s+, K9s+, QTs+, JTs, ATo+, KJo+</p>
<p><img src="/poker/resources/img/6max-lj-open.png" alt="LJ Open" /></p>
</li>
<li>
<p><strong>BB: call with 18% of hands:</strong> 22-TT, A2s-A9s, K4s, K6s+, Q8s+, J8s+, T8s+,
97s+, 86s+, 75s+, 64s+, 53s+, ATo-AQo, KJo+, QJo</p>
<p><img src="/poker/resources/img/6max-bb-call-v-lj-open.png" alt="BB Call" /></p>
</li>
</ul>
<h1 id="mmm--paired--rainbow--no-gaps">MMM / Paired / Rainbow / No Gaps</h1>
<p>There are only two flops in this category that we haven’t checked yet:</p>
<ol>
<li>998r</li>
<li>776r</li>
</ol>
<p>I think that BB will donk slightly more in 776 and slightly less on 998, and
that LJ will cbet slightly more on 998 and slightly less on 776.</p>
<h2 id="998r">998r</h2>
<p>PokerCruncher gives LJ a 55.76% equity over 44.24. This is almost identical to the 887 flop.</p>
<h3 id="prediction-for-big-blind-donking-range-on-998r">Prediction for Big Blind Donking Range on 998r</h3>
<p>I think that BB will donk with about 5% of hands, including:</p>
<ul>
<li>99 (mixed, maybe about 20%)</li>
<li>T8s-Q8s (infrequently)</li>
<li>QJs, QTs, KTs w/ BDFD (trying to get fold equity, possibility to improve,
block some pocket pairs)</li>
</ul>
<h3 id="prediction-for-lojack-cbetting-range-on-998r">Prediction for Lojack CBetting range on 998r</h3>
<p>This flop connects a bit more with the LJ, but not much more. BB has the nuts
advantage, and this flop only has about .25% more equity than the last for LJ.</p>
<p>I predict that LJ will cbet 1/2 pot for around 23% of hands:</p>
<ul>
<li>88</li>
<li>99</li>
<li>A8s</li>
<li>A9s, K9s</li>
<li>JTs</li>
<li>QTs+</li>
<li>Some Kxs</li>
</ul>
<h3 id="pokersnowie-bb-donking-range-on-998r">PokerSnowie: BB Donking Range on 998r</h3>
<p>PS only donks 2.8% of the time, less than 1/2 the time as on 887. The only
explanation I can think of is that this connects better with LJ’s range. But it
doesn’t, really. There are two more possibilities at trips (K9s + A9s versus
A8s), and there is now four OESDs (JTs).</p>
<p><img src="/poker/resources/img/998r-bb-donk.png" alt="BB Donk" /></p>
<p>The QJs and QTs combos are still represented as the bluffs, but Q9 is checked to
keep the value range strong. Instead, JTs is added in as a semibluff (it’s an
OESD). 99 and various 8x are amost never bet. 9x is always checked.</p>
<h3 id="pokersnowie-lj-cbetting-range-on-998r">PokerSnowie: LJ CBetting Range on 998r</h3>
<p>PS actually prefers betting 1/4 pot with around 26.5% of hands:</p>
<p><img src="/poker/resources/img/998r-lj-cbet-quarter-pot.png" alt="LJ Continue with 1/4 pot" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's CBetting range at 1/4 pot on 998r">
<b>Lojack's CBetting range at 1/4 pot on 998r:</b>
<i>The lojack continues with about 26.5% of hands. Hands like QTs+ have
the same qualities as on 887r now connect a bit better: since 89TJQ makes a
straight, these are now gutshots, as well as having blocking potential and
benefiting from folds.</i>
</p>
<p><img src="/poker/resources/img/998r-lj-breakdown.png" alt="PokerCruncher Range Breakdown" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's hand equity breakdown on the flop">
<b>Lojack's hand equity breakdown on the flop:</b>
<i>The lojack continues with about 26.5% of hands. Hands like QTs+ have
the same qualities as on 887r now connect a bit better: since 89TJQ makes a
straight, these are now gutshots, as well as having blocking potential and
benefiting from folds.</i>
</p>
<p>The betting range is more polar than linear: there are hands in the 40%-43%
range, and hands in the 53%+ range. This isn’t quite polar because there are a
lot of 50% equity hands that aren’t “the nuts”, but it’s not quite linear either
because there are some low-equity hands (granted, these have some good implied
odds and might be able to play for stacks), a hole, and then some
decent-to-premium hands. I think it’s best to think of this as a semi-polarized
range…</p>
<p>The checking range is relatively condensed. It does have some high-equity hands
like AA, KK with 80-80% equity, but these aren’t really nutted: you don’t wanna
play for stacks with these hands.</p>
<h4 id="using-12-pot-bet">Using 1/2 pot bet</h4>
<p>This is awfully close to the previous scenario (887r), and I think that the PS
strategy for a 1/2 pot bet should be similar to what it was in my previous post.</p>
<p>Here are the ranges, both from 887 and from 998:</p>
<p><img src="/poker/resources/img/998r-lj-cbet-half-pot.png" alt="PokerSnowie Range LJ Cbet for 998r" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's 1/2-pot cbetting range on 998r">
<b>Lojack's 1/2-pot cbetting range on 998r:</b>
<i></i>
</p>
<p><img src="/poker/resources/img/887r-lj-cbet.png" alt="PokerSnowie Range LJ Cbet for 887r" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's 1/2-pot cbetting range on 887r">
<b>Lojack's 1/2-pot cbetting range on 887r:</b>
<i></i>
</p>
<p>These ranges look very similar, with the following changes:</p>
<ol>
<li>77 and 88 have become 88 and 99</li>
<li>KQs and KQo are now bet at about 100% frequency…these have the possibility
of runner-runnering to the nut straight, so maybe that explains it?</li>
<li>A7s and A8s have become A8s (~ around 30% frequency) and A9s</li>
</ol>
<h4 id="analysis">Analysis</h4>
<p>Using a 1/2 pot bet sizing, a similar betting strategy is used.</p>
<p>What’s more, these ranges are a lot more polarized than the 1/4 pot bet. For the
998r flop, 88 and 99 each have about 100% equity, and A9s/K9s both have 90%+
equity. A8s is bet about 30% of the time and has 73% equity; all other hands
that are bet have between 37% equity and 42% equity.</p>
<p>That leaves about 7 value combos and 44 weak hand combos (< 50%). However, many
of these weaker combos can improve in different ways to various over cards and
all have the potential to make straights…these won’t be nutted, but will have
serious equity on later streets if they connect.</p>
<h2 id="776r">776r</h2>
<p>PokerCruncher gives LJ a 56.64% equity over 43.36 for the BB. This is higher
than for 887 or 998, which surprised me.</p>
<h3 id="prediction-for-big-blind-donking-range-on-776r">Prediction for Big Blind Donking Range on 776r</h3>
<p>I think that BB will donk w/ 1/2 pot for about 6% of hands, including:</p>
<ul>
<li>77 (mixed, about 20%)</li>
<li>66 (mixed, about 20%)</li>
<li>J8s+ (mixed, about 75%) w/ BDFDs</li>
<li>87s (mixed, around 15-20%)</li>
<li>A6s (around 10%)</li>
<li>64s+ (around 25%)</li>
</ul>
<p>I am deriving this by shifting the range from 887 diagonally down one square</p>
<h3 id="prediction-for-lojack-cbetting-range-on-776r">Prediction for Lojack CBetting Range on 776r</h3>
<p>I predict that LJ should cbet a polarized range about 1/2 pot with about 23% of
hands, including:</p>
<ul>
<li>66</li>
<li>77</li>
<li>A6s</li>
<li>A7s</li>
<li>JTs</li>
<li>K9s</li>
<li>QTs</li>
</ul>
<p>The problem is, the flop really doesn’t connect with LJ’s range at all, so
trying to find good bluffs that can improve (like QTs on 887) is hard. For this
reason, it might make more sense to expect to see a higher frequency, lower
size, less polarized betting strategy.</p>
<h3 id="pokersnowie-big-blind-donking-range-on-776r">PokerSnowie: Big Blind Donking Range on 776r</h3>
<p>PokerSnowie recommends donking 1/2 pot with the following range, comprising
11.12% of hands:
<img src="/poker/resources/img/776r-bb-donk.png" alt="BB Donk" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="BB's flop strategy">
<b>BB's flop strategy:</b>
<i></i>
</p>
<p><img src="/poker/resources/img/776r-bb-breakdown.png" alt="PokerCruncher BB Range Breakdown" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="BB's hand equity breakdown on the 776r flop">
<b>BB's hand equity breakdown on the 776r flop:</b>
<i></i>
</p>
<p>This is surprising…LJ’s donking range is almost entirely made up of trash,
including Jxs and Qxs.</p>
<p>BB donks with a very polarized range.</p>
<h3 id="pokersnowie-lojack-continuing-range-on-776r">PokerSnowie: Lojack Continuing Range on 776r</h3>
<p>PS prefers betting 1/4 pot with linear range with about 31.1% of hands:</p>
<p><img src="/poker/resources/img/776r-lj-cbet-quarter-pot.png" alt="LJ Continue with 1/4 pot" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's CBetting range at 1/4 pot on 776r">
<b>Lojack's CBetting range at 1/4 pot on 776r:</b>
<i></i>
</p>
<p><img src="/poker/resources/img/776r-lj-breakdown.png" alt="PokerCruncher Range Breakdown" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's hand equity breakdown on the flop">
<b>Lojack's hand equity breakdown on the flop:</b>
<i></i>
</p>
<p>Using the 1/2 pot sizing PS likes to bet a polarized range about 14% of the time:
<img src="/poker/resources/img/776r-lj-cbet-half-pot.png" alt="LJ Continue with 1/4 pot" /></p>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Lojack's CBetting range at 1/2 pot on 776r">
<b>Lojack's CBetting range at 1/2 pot on 776r:</b>
<i></i>
</p>
<p>These are by and large the hands I was expecting, but a lower frequency. I think
this is well explained by the fact that it’s hard to find hands that improve on
later streets. This board, while not static, doesn’t let the LJ to improve to
the nuts on later streets.</p>In my previous post I looked at the scenario where LJ opens for 2.5bb, BB calls, and flop comes 887 rainbow. I looked at PokerSnowie output, tried to interpret it, and formed a hypothesis based on this interpretation:Short Circuiting with Side Effects2021-01-20T20:00:00+00:002021-01-20T20:00:00+00:00/2021/01/20/short-circuiting-with-side-effects<p>In this post I look at how basic rewrite rules fail when dealing with side
effects, as well as exploring possible solutions.</p>
<h2 id="short-circuiting-operators">Short-Circuiting Operators</h2>
<p>Consider the following method <code class="language-plaintext highlighter-rouge">shortCircuit()</code>.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">boolean</span> <span class="nf">shortCircuit</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">cond</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">cond</span> <span class="o">||</span> <span class="n">getBoolWithSideEffects</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 1">
<b>Listing 1:</b>
<i>A short circuiting operator that may or may not trigger side effects</i>
</p>
<p>Currently Cornelius serializes this as if the right hand side is always
executed. Instead I need to handle the short circuiting.</p>
<p>For instance, this would serialize to something like</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">return-node</span>
<span class="p">(</span><span class="nf">||</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">cond</span><span class="p">)</span> <span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">invoke</span> <span class="nv">getBoolWithSideEffects</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">this</span><span class="p">)</span> <span class="nv">actuals</span> <span class="nv">heap</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">invoke->heap</span>
<span class="p">(</span><span class="nf">invoke</span> <span class="nv">getBoolWithSideEffects</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">this</span><span class="p">)</span> <span class="nv">actuals</span> <span class="nv">heap</span><span class="p">)))</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 2">
<b>Listing 2:</b>
<i>Buggy serialized output</i>
</p>
<p>Instead this should serialize to something like this:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">return-node</span>
<span class="p">(</span><span class="nf">||</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">cond</span><span class="p">)</span> <span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">invoke</span> <span class="nv">getBoolWithSideEffects</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">this</span><span class="p">)</span> <span class="nv">actuals</span> <span class="nv">heap</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">cond</span><span class="p">)</span>
<span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)</span>
<span class="p">(</span><span class="nf">invoke->heap</span>
<span class="p">(</span><span class="nf">invoke</span> <span class="nv">getBoolWithSideEffects</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">this</span><span class="p">)</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))))</span>
</code></pre></div></div>
<h2 id="commutativity">Commutativity</h2>
<p>How does commutativity work here? It should actually just play out the same as
in <a href="/2021/01/14/commutativity-with-side-effects.html">my previous post</a>.</p>In this post I look at how basic rewrite rules fail when dealing with side effects, as well as exploring possible solutions.Commutativity with Side Effects2021-01-14T20:00:00+00:002021-01-14T20:00:00+00:00/2021/01/14/commutativity-with-side-effects<p>This post is just to clarify why I don’t have to worry about side effects and
commutative rewrites. In my next post, <a href="/2021/01/20/short-circuiting-with-side-effects.html">Short Circuiting with Side Effects</a>, I look into why this
fails and how to fix it.</p>
<h2 id="commutativity">Commutativity</h2>
<p>Addition is commutative, obviously, so when I started working Cornelius a rule
like</p>
<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">rw!</span><span class="p">(</span><span class="s">"commute-add"</span><span class="p">;</span> <span class="s">"(+ ?a ?b)"</span> <span class="k">=></span> <span class="s">"(+ ?b ?a)"</span><span class="p">),</span>
</code></pre></div></div>
<p>was obvious and natural to write. But consider the following program:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">Counter</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kt">int</span> <span class="nf">next</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">++</span><span class="n">count</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="nf">get</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">count</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="nf">add</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">Counter</span> <span class="n">c</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Counter</span><span class="o">();</span>
<span class="k">return</span> <span class="n">c</span><span class="o">.</span><span class="na">get</span><span class="o">()</span> <span class="o">+</span> <span class="n">c</span><span class="o">.</span><span class="na">next</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">+</code> operator cannot commute here. If <code class="language-plaintext highlighter-rouge">c.count</code> is <code class="language-plaintext highlighter-rouge">0</code>, <code class="language-plaintext highlighter-rouge">c.get() + c.next()</code>
evaluates to <code class="language-plaintext highlighter-rouge">1</code>, while <code class="language-plaintext highlighter-rouge">c.next() + c.get()</code> evaluates to <code class="language-plaintext highlighter-rouge">2</code>.</p>
<p>My first question is</p>
<blockquote>
<p>Does the commutative rewrite potentially change the semantics of a program?</p>
</blockquote>
<h3 id="no">No</h3>
<p>This turns out <em>not</em> to be a problem. Why is that? To see this, let’s serialize
the above <code class="language-plaintext highlighter-rouge">add</code> method. Don’t look too closely at the output (it’s
huge!)…instead, look at the comments. Look at how big the invocation for the
RHS is versus the LHS:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="p">(</span><span class="nf">return-node</span>
<span class="p">(</span><span class="nb">+</span>
<span class="c1">;; START LHS</span>
<span class="p">(</span><span class="nf">invoke->peg</span>
<span class="p">(</span><span class="nf">invoke</span>
<span class="p">(</span><span class="nf">heap</span>
<span class="p">(</span><span class="nf">invoke->heap-state</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">invoke->exception-status</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">))))</span>
<span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span> <span class="nv">get</span> <span class="nv">actuals</span><span class="p">))</span>
<span class="c1">;; END LHS</span>
<span class="c1">;; RHS</span>
<span class="p">(</span><span class="nf">invoke->peg</span>
<span class="p">(</span><span class="nf">invoke</span>
<span class="c1">;; HEAP WE ARE INVOKING IN</span>
<span class="p">(</span><span class="nf">heap</span>
<span class="p">(</span><span class="nf">invoke->heap-state</span>
<span class="p">(</span><span class="nf">invoke</span>
<span class="p">(</span><span class="nf">heap</span>
<span class="p">(</span><span class="nf">invoke->heap-state</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">invoke->exception-status</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">))))</span>
<span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="nv">get</span>
<span class="nv">actuals</span><span class="p">))</span>
<span class="p">(</span><span class="nf">invoke->exception-status</span>
<span class="p">(</span><span class="nf">invoke</span>
<span class="p">(</span><span class="nf">heap</span>
<span class="p">(</span><span class="nf">invoke->heap-state</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">invoke->exception-status</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">))))</span>
<span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="nv">get</span>
<span class="nv">actuals</span><span class="p">)))</span>
<span class="c1">;; RECEIVER OBJECT FOR INVOCATION</span>
<span class="p">(</span><span class="nf">invoke->peg</span> <span class="p">(</span><span class="nf">new</span> <span class="s">"Counter"</span> <span class="nv">actuals</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span> <span class="nv">unit</span><span class="p">)))</span>
<span class="c1">;; METHOD NAME</span>
<span class="nv">next</span>
<span class="c1">;; ACTUAL PARAMS (empty)</span>
<span class="nv">actuals</span><span class="p">))</span>
<span class="c1">;; END RHS</span>
<span class="p">)</span> <span class="c1">;;; CLOSE (+ ... ...) NODE</span>
<span class="c1">;; RETURNED HEAP</span>
<span class="p">(</span><span class="nf">heap</span> <span class="o">...</span> <span class="o">...</span><span class="p">)</span>
</code></pre></div></div>
<p>If the LHS and RHS were commuted we actually wouldn’t be commuting the order in
which things happen.</p>This post is just to clarify why I don’t have to worry about side effects and commutative rewrites. In my next post, Short Circuiting with Side Effects, I look into why this fails and how to fix it.Serializing Cast Expressions in Cornelius2021-01-02T20:00:00+00:002021-01-02T20:00:00+00:00/2021/01/02/serializing-cast-expressions-in-cornelius<pre>
_______ __ __ __ __
| __|.-----.----.|__|.---.-.| |__|.-----.|__|.-----.-----.
|__ || -__| _|| || _ || | ||-- __|| || | _ |
|_______||_____|__| |__||___._||__|__||_____||__||__|__|___ |
|_____|
______ __
| |.---.-.-----.| |_
| ---|| _ |__ --|| _|
|______||___._|_____||____|
_______ __
| ___|.--.--.-----.----.-----.-----.-----.|__|.-----.-----.-----.
| ___||_ _| _ | _| -__|__ --|__ --|| || _ | |__ --|
|_______||__.__| __|__| |_____|_____|_____||__||_____|__|__|_____|
|__|
__ ______ __ __
|__|.-----. | |.-----.----.-----.-----.| |__|.--.--.-----.
| || | | ---|| _ | _| | -__|| | || | |__ --|
|__||__|__| |______||_____|__| |__|__|_____||__|__||_____|_____|
</pre>
<p>In this article I’m going to reason through transforming cast expressions into
PEGs.</p>
<h1 id="the-problem">The Problem</h1>
<p>The problem is simple: given a cast expression <code class="language-plaintext highlighter-rouge">(T)o</code>, I want to create a PEG
that represents the semantics of this expression. I need to track the following:</p>
<ol>
<li>
<p><strong>The change to the type:</strong> this is important for method dispatch, assignment
validity, etc. For instance,</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cm">/**
* Suppose that T extends S, and that overriddenMethod is defined
* in S and overridden in T.
*/</span>
<span class="kt">void</span> <span class="nf">m</span><span class="o">(</span><span class="no">S</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="n">o</span><span class="o">.</span><span class="na">overriddenMethod</span><span class="o">();</span>
<span class="no">T</span> <span class="n">o2</span> <span class="o">=</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span><span class="n">o</span><span class="o">;</span>
<span class="n">o2</span><span class="o">.</span><span class="na">overriddenMethod</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div> </div>
<p>should properly capture that both method invocations are not necessarily the same.</p>
</li>
<li>
<p><strong>Class Cast Exceptions:</strong> The following code should represent the
possibility that something went wrong:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">m</span><span class="o">(</span><span class="nc">Object</span> <span class="n">o</span><span class="o">)</span> <span class="o">{</span>
<span class="no">T</span> <span class="o">=</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span> <span class="n">o</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div> </div>
<p>This will be tracked as an exception status stored in a heap node <code class="language-plaintext highlighter-rouge">(heap
state status)</code>.</p>
<p>To do this, I’ll need at least two new nodes:</p>
<ul>
<li>
<p>A <code class="language-plaintext highlighter-rouge">(can-cast? OBJ TYPE)</code> node representing the relation that <code class="language-plaintext highlighter-rouge">OBJ</code> os if
type <code class="language-plaintext highlighter-rouge">TYPE</code>, and</p>
</li>
<li>
<p>A <code class="language-plaintext highlighter-rouge">(cast OBJ TYPE)</code> node that represents the result of <code class="language-plaintext highlighter-rouge">OBJ</code> being cast to
<code class="language-plaintext highlighter-rouge">TYPE</code></p>
</li>
</ul>
</li>
</ol>
<p><strong>Question:</strong> can the <code class="language-plaintext highlighter-rouge">can-cast?</code> relation be replaced with Java’s <code class="language-plaintext highlighter-rouge">instanceof</code>
keyword? That is, is cast expression <code class="language-plaintext highlighter-rouge">(T)o</code> successful precisely when <code class="language-plaintext highlighter-rouge">o
instanceof T</code>?</p>
<p><strong>Answer:</strong> Not quite…these are almost identical, but <code class="language-plaintext highlighter-rouge">null instanceof T</code>
always returns <code class="language-plaintext highlighter-rouge">false</code>, while casts to reference types always succeed (e.g.,
<code class="language-plaintext highlighter-rouge">(Object)null</code> is successful). That’s okay, we can introduce a <code class="language-plaintext highlighter-rouge">can-cast?</code> node
and then rewrite <code class="language-plaintext highlighter-rouge">(can-cast? o t)</code> to <code class="language-plaintext highlighter-rouge">(and (not is-null? o) (instance-of? o
t))</code>.</p>
<h1 id="pegifying-a-cast-expression">PEGifying a cast expression</h1>
<p>I <em>think</em> it should be as easy as:</p>
<ol>
<li>Add exit condition <code class="language-plaintext highlighter-rouge">(not (can-cast? o T))</code> to the Context so that subsequent
changes to local state are predicated on this condition not being satisfied.</li>
<li>Modify the heap by replacing it’s <code class="language-plaintext highlighter-rouge">STATUS</code> field with <code class="language-plaintext highlighter-rouge">(phi (is-unit? STATUS)
(phi (not (can-cast? o T)) java.lang.ClassCastException unit))</code></li>
<li>Represent the expression as a <code class="language-plaintext highlighter-rouge">(cast o T)</code> PEG node.</li>
</ol>_______ __ __ __ __ | __|.-----.----.|__|.---.-.| |__|.-----.|__|.-----.-----. |__ || -__| _|| || _ || | ||-- __|| || | _ | |_______||_____|__| |__||___._||__|__||_____||__||__|__|___ | |_____| ______ __ | |.---.-.-----.| |_ | ---|| _ |__ --|| _| |______||___._|_____||____|Adding Exceptions to Cornelius, Part 12021-01-01T18:00:00+00:002021-01-01T18:00:00+00:00/2021/01/01/adding-exceptions-to-cornelius-pt1<h2 id="the-problem">The Problem</h2>
<p>Cornelius needs to handle arbitrary exceptions and try/catch blocks. To do this
in its entirety will be hard, so I’ve decide to start with something simpler:
null pointer dereferencing.</p>
<h2 id="null-pointer-dereferencing">Null Pointer Dereferencing</h2>
<p>Cornelius handles field writing and reading of objects, for instance:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">foo</span><span class="o">()</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="na">b</span><span class="o">;</span>
<span class="k">return</span> <span class="n">x</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 1">
<b>Listing 1:</b>
<i>A Java program that dereferences a class variable
<code>this.a</code></i>
</p>
<p>If we knew that <code class="language-plaintext highlighter-rouge">a</code> was never null then we could output something like:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">method-root</span>
<span class="c1">;; The returned value is the result of two reads.</span>
<span class="c1">;; 1. `(rd (path (var this) (derefs a)) (heap 0))` reads `this.a` from</span>
<span class="c1">;; `(heap 0)`</span>
<span class="c1">;; 2. The result of the above read is used as the base of the outer `rd` node,</span>
<span class="c1">;; which dereferences variable name `b` in `(heap 0)`</span>
<span class="p">(</span><span class="nf">rd</span> <span class="p">(</span><span class="nf">path</span>
<span class="p">(</span><span class="nf">rd</span> <span class="p">(</span><span class="nf">path</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">this</span><span class="p">)</span> <span class="p">(</span><span class="nf">derefs</span> <span class="nv">a</span><span class="p">))</span> <span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span><span class="p">))</span>
<span class="p">(</span><span class="nf">derefs</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span><span class="p">))</span>
<span class="c1">;; The returned heap</span>
<span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span><span class="p">))</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 2">
<b>Listing 2:</b>
<i>The (incorrect) PEG produced by Cornelius currently...note that this
doesn't handle <code>null</code> dereferences</i>
</p>
<p>I need to check the dereference of <code class="language-plaintext highlighter-rouge">(this.a).b)</code> for nullity; I can skip the
<code class="language-plaintext highlighter-rouge">null</code> check for <code class="language-plaintext highlighter-rouge">this</code> since <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.8.3"><code class="language-plaintext highlighter-rouge">this</code> is never
null.</a></p>
<h2 id="why-is-this-tricky">Why is this tricky?</h2>
<p>I’ll need to capture control flow somewhere. Consider the following method:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">derefAndAssign</span><span class="o">(</span><span class="nc">Foo</span> <span class="n">a</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="n">a</span><span class="o">.</span><span class="na">value</span><span class="o">;</span> <span class="c1">// Might throw NPE</span>
<span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="o">;</span> <span class="c1">// Doesn't execute if NPE is thrown.</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NullPointerException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{}</span>
<span class="k">return</span> <span class="n">x</span><span class="o">;</span> <span class="c1">// This x shouldn't track assignment x = x + 1 when a is null</span>
<span class="o">}</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 3">
<b>Listing 3:</b>
<i>This method illustates the intersection of concerns between
handling possible exceptional status and control flow.</i>
</p>
<p>If <code class="language-plaintext highlighter-rouge">a</code> is <code class="language-plaintext highlighter-rouge">null</code>, then the print statement and executed. The semantics for the
print statement are implicitly handled because <code class="language-plaintext highlighter-rouge">a.value</code> is serialized to <code class="language-plaintext highlighter-rouge">(rd
(path (var a) (derefs value)) (heap 0))</code>, which implicitly tracks the
possibility that <code class="language-plaintext highlighter-rouge">a</code> might be <code class="language-plaintext highlighter-rouge">null</code>.</p>
<p>But in the case of <code class="language-plaintext highlighter-rouge">x = 1</code>, this is a simple assignment to a local variable and
doesn’t involve the heap at all. Thus if we just update our context naively, <code class="language-plaintext highlighter-rouge">x</code>
will always be <code class="language-plaintext highlighter-rouge">1</code> at there return statement.</p>
<h2 id="the-solution">The solution</h2>
<h3 id="the-heap">The Heap</h3>
<p>Heaps now track two things: <strong>heap state</strong> and <strong>exception status</strong>: <code class="language-plaintext highlighter-rouge">(heap
STATE STATUS)</code>. <code class="language-plaintext highlighter-rouge">STATE</code> is a chain of <code class="language-plaintext highlighter-rouge">wr</code> nodes, while <code class="language-plaintext highlighter-rouge">STATUS</code> is a chain of
conditionals testing for conditions and resulting in <code class="language-plaintext highlighter-rouge">unit</code> if none of the
conditions are met, or specific exception types if the corresponding condition
is met.</p>
<p>For instance, <code class="language-plaintext highlighter-rouge">(heap unit (phi (isnull? (var a) (exception
java.lang.NullPointerException) unit)))</code> represents a heap with a single
possible NPE triggered by <code class="language-plaintext highlighter-rouge">(var a)</code> being <code class="language-plaintext highlighter-rouge">null</code>.</p>
<h3 id="exit-conditions">Exit Conditions</h3>
<p>Cornelius tracks <strong>exit conditions</strong> in its contexts:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">final</span> <span class="kd">public</span> <span class="nc">ImmutableSet</span><span class="o"><</span><span class="nc">PegNode</span><span class="o">></span> <span class="n">exitConditions</span><span class="o">;</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 4">
<b>Listing 4:</b>
<i>PegContext.exitConditions</i>
</p>
<p>During serialization, which is basically just a big AST visit, every time we
encounter code that might throw an exception (for now, just
<code class="language-plaintext highlighter-rouge">NullPointerException</code>s), we register it in the context:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="nc">ExpressionResult</span> <span class="nf">visit</span><span class="o">(</span><span class="nc">FieldAccessExpr</span> <span class="n">n</span><span class="o">,</span> <span class="nc">PegContext</span> <span class="n">arg</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">ExpressionResult</span> <span class="n">scope</span> <span class="o">=</span> <span class="n">n</span><span class="o">.</span><span class="na">getScope</span><span class="o">().</span><span class="na">accept</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">arg</span><span class="o">);</span>
<span class="kd">final</span> <span class="nc">PegNode</span> <span class="n">path</span> <span class="o">=</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">path</span><span class="o">(</span><span class="n">scope</span><span class="o">.</span><span class="na">peg</span><span class="o">.</span><span class="na">id</span><span class="o">,</span> <span class="n">n</span><span class="o">.</span><span class="na">getNameAsString</span><span class="o">());</span>
<span class="c1">// isnull: the exit condition for this dereference</span>
<span class="kd">final</span> <span class="nc">PegNode</span> <span class="n">isnull</span> <span class="o">=</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">isnull</span><span class="o">(</span><span class="n">scope</span><span class="o">.</span><span class="na">peg</span><span class="o">.</span><span class="na">id</span><span class="o">);</span>
<span class="c1">// the null pointer exception that is thrown when the 'scope' of the</span>
<span class="c1">// FieldAccessExpr is null (e.g., in a.x, 'a' is the scope)</span>
<span class="kd">final</span> <span class="nc">PegNode</span> <span class="n">npe</span> <span class="o">=</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">exception</span><span class="o">(</span><span class="s">"java.lang.NullPointerException"</span><span class="o">);</span>
<span class="c1">// nullCheck: the resulting context after a null check, with the</span>
<span class="c1">// corresponding exception condition</span>
<span class="kd">final</span> <span class="nc">PegContext</span> <span class="n">nullCheck</span> <span class="o">=</span> <span class="n">scope</span><span class="o">.</span><span class="na">context</span><span class="o">.</span><span class="na">withExceptionCondition</span><span class="o">(</span><span class="n">isnull</span><span class="o">,</span> <span class="n">npe</span><span class="o">);</span>
<span class="k">return</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">rd</span><span class="o">(</span><span class="n">path</span><span class="o">.</span><span class="na">id</span><span class="o">,</span> <span class="n">scope</span><span class="o">.</span><span class="na">context</span><span class="o">.</span><span class="na">heap</span><span class="o">.</span><span class="na">id</span><span class="o">).</span><span class="na">exprResult</span><span class="o">(</span><span class="n">nullCheck</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 5">
<b>Listing 5:</b>
<i>PegExprVisitor.visit(FieldAccessExpr, PegContext)</i>
</p>
<p>An <code class="language-plaintext highlighter-rouge">ExpressionResult</code> is just a wrapper around a <code class="language-plaintext highlighter-rouge">PegContext</code> and a <code class="language-plaintext highlighter-rouge">PegNode</code>,
as well as some convenience methods.</p>
<p>Under the hood, <code class="language-plaintext highlighter-rouge">PegContext.withExceptionCondition(PegNode cond, PegNode
exception)</code> copies the current <code class="language-plaintext highlighter-rouge">PegContext</code> with the following modifications</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">cond</code> is added to the new <code class="language-plaintext highlighter-rouge">PegContext</code>’s <code class="language-plaintext highlighter-rouge">exitConditions</code></li>
<li>the new context’s heap now tracks the possibility of this exceptional status.
This is stored in <code class="language-plaintext highlighter-rouge">context.heap.status</code>. If there have been no exceptions
thrown, then <code class="language-plaintext highlighter-rouge">context.heap.status</code> is <code class="language-plaintext highlighter-rouge">unit</code> (or something that is, in
theory, rewritable to <code class="language-plaintext highlighter-rouge">unit</code>). If it is <em>not</em> <code class="language-plaintext highlighter-rouge">unit</code>, that means that an
exception has been thrown already, which in turn means that the current
exception is not thrown. Thus the new status is:
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">unit?</span> <span class="nv">OLD-STATUS</span><span class="p">)</span>
<span class="c1">;; Old status is unit, so whenever the new exit condition is true,</span>
<span class="c1">;; the status should be the new exception. Otherwise, it's the old</span>
<span class="c1">;; exception status</span>
<span class="p">(</span><span class="nf">phi</span> <span class="nv">NEW-EXIT-CONDITION</span> <span class="nv">EXCEPTION</span> <span class="nv">OLD-STATUS</span><span class="p">)</span>
<span class="c1">;; The old statis is NOT unit, which means that an exception was</span>
<span class="c1">;; thrown that hasn't been caught. The old status should be used.</span>
<span class="nv">OLD-STATUS</span><span class="p">)</span>
</code></pre></div> </div>
</li>
</ol>
<p>On subsequent assignment operations, instead of directly updating the context we
now predicate that update on exit conditions:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cm">/**
* A helper method wrapping {@code setLocalVar} to predicate assignments on appropriate checks against
* exitConditions.
* @param key variable name we are assigning to
* @param val value we are assigning
* @return context resulting from assignment
*/</span>
<span class="kd">public</span> <span class="nc">PegContext</span> <span class="nf">performAssignLocalVar</span><span class="o">(</span><span class="kd">final</span> <span class="nc">String</span> <span class="n">key</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">PegNode</span> <span class="n">val</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">exitConditions</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">setLocalVar</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="n">val</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="nf">setLocalVar</span><span class="o">(</span><span class="n">key</span><span class="o">,</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">phi</span><span class="o">(</span><span class="nc">PegNode</span><span class="o">.</span><span class="na">exitConditions</span><span class="o">(</span><span class="n">exitConditions</span><span class="o">).</span><span class="na">id</span><span class="o">,</span> <span class="n">getLocalVar</span><span class="o">(</span><span class="n">key</span><span class="o">).</span><span class="na">id</span><span class="o">,</span> <span class="n">val</span><span class="o">.</span><span class="na">id</span><span class="o">));</span>
<span class="o">}</span>
</code></pre></div></div>
<p style="color:DarkSlateGray;font-size:1.0em;text-align:left;padding-left:30px;padding-right:30px;padding-top:5px;" id="Listing 6">
<b>Listing 6:</b>
<i>PegContext.performLocalAssign(String, PegNode): this helper method performs
a local assignment predicated on any possible exit conditions that occurred
before this</i>
</p>
<p>This also needs to be tracked by context joins, but this is pretty straight
forward…I just union the <code class="language-plaintext highlighter-rouge">exitConditions</code> and update heap state and status based on control flow:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cm">/**
* Combine two contexts, merging control flow.
* @param c1 the context resulting from the then branch that executes if {@code guardId} is true
* @param c2 the context resulting from the else branch that executes if {@code guardId} is false
* @param guardId the id of the branching condition
* @return combined contexts
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">PegContext</span> <span class="nf">combine</span><span class="o">(</span><span class="nc">PegContext</span> <span class="n">c1</span><span class="o">,</span> <span class="nc">PegContext</span> <span class="n">c2</span><span class="o">,</span> <span class="nc">Integer</span> <span class="n">guardId</span><span class="o">)</span> <span class="o">{</span>
<span class="k">assert</span> <span class="n">c1</span><span class="o">.</span><span class="na">fieldNames</span> <span class="o">==</span> <span class="n">c2</span><span class="o">.</span><span class="na">fieldNames</span><span class="o">;</span> <span class="c1">// TODO: is this true? This should be true</span>
<span class="kd">final</span> <span class="nc">ImmutableSet</span><span class="o"><</span><span class="nc">String</span><span class="o">></span> <span class="n">domain</span> <span class="o">=</span> <span class="n">c1</span><span class="o">.</span><span class="na">localVariableLookup</span><span class="o">.</span><span class="na">keySet</span><span class="o">().</span><span class="na">stream</span><span class="o">().</span><span class="na">filter</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">localVariableLookup</span><span class="o">::</span><span class="n">containsKey</span><span class="o">)</span>
<span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">collectingAndThen</span><span class="o">(</span><span class="nc">Collectors</span><span class="o">.</span><span class="na">toSet</span><span class="o">(),</span> <span class="nl">ImmutableSet:</span><span class="o">:</span><span class="n">copyOf</span><span class="o">));</span>
<span class="kd">final</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">Heap</span> <span class="n">combinedHeap</span> <span class="o">=</span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">heap</span><span class="o">(</span>
<span class="nc">PegNode</span><span class="o">.</span><span class="na">phi</span><span class="o">(</span><span class="n">guardId</span><span class="o">,</span> <span class="n">c1</span><span class="o">.</span><span class="na">heap</span><span class="o">.</span><span class="na">state</span><span class="o">,</span> <span class="n">c2</span><span class="o">.</span><span class="na">heap</span><span class="o">.</span><span class="na">state</span><span class="o">).</span><span class="na">id</span><span class="o">,</span>
<span class="nc">PegNode</span><span class="o">.</span><span class="na">phi</span><span class="o">(</span><span class="n">guardId</span><span class="o">,</span> <span class="n">c1</span><span class="o">.</span><span class="na">heap</span><span class="o">.</span><span class="na">status</span><span class="o">,</span> <span class="n">c2</span><span class="o">.</span><span class="na">heap</span><span class="o">.</span><span class="na">status</span><span class="o">).</span><span class="na">id</span>
<span class="o">);</span>
<span class="kd">final</span> <span class="nc">ImmutableSet</span><span class="o"><</span><span class="nc">PegNode</span><span class="o">></span> <span class="n">combinedExitConditions</span> <span class="o">=</span> <span class="o">(</span><span class="k">new</span> <span class="nc">ImmutableSet</span><span class="o">.</span><span class="na">Builder</span><span class="o"><</span><span class="nc">PegNode</span><span class="o">>())</span>
<span class="o">.</span><span class="na">addAll</span><span class="o">(</span><span class="n">c1</span><span class="o">.</span><span class="na">exitConditions</span><span class="o">)</span>
<span class="o">.</span><span class="na">addAll</span><span class="o">(</span><span class="n">c2</span><span class="o">.</span><span class="na">exitConditions</span><span class="o">).</span><span class="na">build</span><span class="o">();</span>
<span class="k">return</span> <span class="nf">initMap</span><span class="o">(</span>
<span class="n">domain</span><span class="o">,</span>
<span class="n">p</span> <span class="o">-></span> <span class="nc">PegNode</span><span class="o">.</span><span class="na">phi</span><span class="o">(</span><span class="n">guardId</span><span class="o">,</span> <span class="n">c1</span><span class="o">.</span><span class="na">getLocalVar</span><span class="o">(</span><span class="n">p</span><span class="o">).</span><span class="na">id</span><span class="o">,</span> <span class="n">c2</span><span class="o">.</span><span class="na">getLocalVar</span><span class="o">(</span><span class="n">p</span><span class="o">).</span><span class="na">id</span><span class="o">),</span>
<span class="n">c1</span><span class="o">.</span><span class="na">fieldNames</span><span class="o">,</span>
<span class="n">combinedHeap</span><span class="o">,</span>
<span class="n">combinedExitConditions</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>The Problem Cornelius needs to handle arbitrary exceptions and try/catch blocks. To do this in its entirety will be hard, so I’ve decide to start with something simpler: null pointer dereferencing.Testing Cornelius Serialization with Clojure2020-11-06T20:00:00+00:002020-11-06T20:00:00+00:00/2020/11/06/testing-serialization-with-clojure<pre>
_______ __ __
|_ _|.-----.-----.| |_|__|.-----.-----.
| | | -__|__ --|| _| || | _ |
|___| |_____|_____||____|__||__|__|___ |
|_____|
______ __ __
| |.-----.----.-----.-----.| |__|.--.--.-----.
| ---|| _ | _| | -__|| | || | |__ --|
|______||_____|__| |__|__|_____||__|__||_____|_____|
_______ __ __ __ __ __
| __|.-----.----.|__|.---.-.| |__|.-----.---.-.| |_|__|.-----.-----.
|__ || -__| _|| || _ || | ||-- __| _ || _| || _ | |
|_______||_____|__| |__||___._||__|__||_____|___._||____|__||_____|__|__|
__ __ __ ______ __ __
.--.--.--.|__| |_| |--. | | |.-----.|__|.--.--.----.-----.
| | | || | _| | | ---| || _ || || | | _| -__|
|________||__|____|__|__| |______|__||_____|| ||_____|__| |_____|
|___|
</pre>
<ul id="markdown-toc">
<li><a href="#testing-peg-serialization" id="markdown-toc-testing-peg-serialization">Testing Peg Serialization</a></li>
<li><a href="#original-testing-infrastructure" id="markdown-toc-original-testing-infrastructure">Original Testing Infrastructure</a></li>
<li><a href="#updated-testing-infrastructure" id="markdown-toc-updated-testing-infrastructure">Updated Testing Infrastructure</a> <ul>
<li><a href="#testing-intermediate-state" id="markdown-toc-testing-intermediate-state">Testing intermediate state</a></li>
</ul>
</li>
<li><a href="#problems-with-new-implementation" id="markdown-toc-problems-with-new-implementation">Problems with new implementation</a></li>
</ul>
<h2 id="testing-peg-serialization">Testing Peg Serialization</h2>
<p><strong>Question:</strong> how can I effectively test PEG serialization? Ultimately, each
test is a set of input/expected output pairs. The input should be some Java code
to be serialized, and the expected output should be some form that can easily be
compared with the generated PEG.</p>
<p>I could compare PEGs directly, and this might be the right way to do it in the
long run. However, I wanted something easy to implement and easy to write tests
for.</p>
<h2 id="original-testing-infrastructure">Original Testing Infrastructure</h2>
<p>I wrote a simple comment parser that can inspect method comments for forms like</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">/**
* <expected>
* (method-root (+ (var a) (var b)) (heap 0 unit))
* </expected>
*/</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">add</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The test would read the comment, serialize the method, and compare the parsed
string literals with the dereferenced string of the serialized PEG for string
equality, reporting the index of the first difference if one was found.</p>
<p>This was easy to implement, and for easy test cases was easy to write tests.
However, this setup has several shortcomings:</p>
<ol>
<li>
<p><strong>Cannot test intermediate state:</strong> The serializer only returns a
<code class="language-plaintext highlighter-rouge">(method-root peg heap)</code> node, and this doesn’t include intermediate state.
This means that I can only test against the expected output.</p>
</li>
<li>
<p><strong>String comparison isn’t great:</strong> I don’t have a good way of comparing PEGs
directly: instead, I’ve been comparing dereferenced strings
<code class="language-plaintext highlighter-rouge">peg.toDerefString()</code></p>
</li>
<li>
<p><strong>HUGE test cases:</strong> The expected outputs are BIG: a one line method can
result in a PEG whose dereferenced string is over 2000 characters long (this
is, after all, why I deduplicate my PEGs when I serialize). Constructing
these by hand is tedious and error prone</p>
</li>
</ol>
<p>I started off hacking on a small elisp helper script to build up PEG strings
quickly in Emacs. At the advice of Rene switched over to Clojure so that my
testing code could better interact with the serializer, which is in Java.</p>
<h2 id="updated-testing-infrastructure">Updated Testing Infrastructure</h2>
<h3 id="testing-intermediate-state">Testing intermediate state</h3>
<p>I solve shortcoming 1 by instrumenting the serializer to scrape statement-level
comments for expected state, and to capture the actual resulting state in an
<code class="language-plaintext highlighter-rouge">ExpressionResult</code>, which is just a wrapper around a PEG, a context, and a heap.</p>
<p>A quick reminder, in addition to PEGs resulting from expressions there are two
types of state that I need to track during serialization: context and heap
state. A context, represented by <code class="language-plaintext highlighter-rouge">serializer.peg.PegContext</code>, maps variable
names to PEGs. Thus, after the serializing the statement <code class="language-plaintext highlighter-rouge">x = 1;</code>, the context
should map <code class="language-plaintext highlighter-rouge">x</code> to PEG node <code class="language-plaintext highlighter-rouge">(int-lit 1)</code>.</p>
<p>Heap stores global state that <em>isn’t</em> stored in the context. This includes
global state and exception status, and is updated by field reads, method
invocations, and anything that might trigger an exception.</p>
<p>Statements don’t have values, which means I’m not going to be reasoning about
individual PEGs; instead, I’m going to be concerned with contexts and heaps (but
if I ever expand to testing expressions I’ll want to have access to PEGs, thus
the <code class="language-plaintext highlighter-rouge">ExpressionResult</code>).</p>
<p>Rather than reconstructing the entire PEG at each comment, I’m marking each
statement with the state update, and optionally including a <code class="language-plaintext highlighter-rouge">snapshot</code> node,
which tells the testing infrastructure to check the expected state versus the
serialized state.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">foo</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="cm">/**
* <expected>
* [a (lookup-in-ctx "a")
* peg (opnode "+" a (int-lit 1))
* ctx (update-key-in-ctx ctx "x" peg)
* (snapshot {:ctx ctx :heap heap})]
* </expected>
*/</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span>
<span class="cm">/**
* <expected>
* [b (lookup-in-ctx "b")
* peg (opnode "+" b (int-lit 1))
* ctx (update-key-in-ctx ctx "y" peg)
* (snapshot {:ctx ctx})]
* </expected>
*/</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="mi">1</span><span class="o">;</span>
<span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Note that I’m currently not testing the returned value from return statements
explicitly (I made some early design decisions based on only having a single
return statement in a method, and I’m going to update that soon—updating the
testing infra doesn’t make sense here, since it will only be around for a short
amount of time). Further, the way returns are handled is simply to record the
resulting PEG (if any) in the returned expression, and copy heap info in a
<code class="language-plaintext highlighter-rouge">(method-root PEG HEAP)</code> node. This is very simple and doesn’t exercise any new
machinery that isn’t already exercised elsewhere in the method, so any bugs that
show up should be immediately obvious. Anyway, this will be fixed at some point
soon, but it isn’t pressing.</p>
<p>The above <code class="language-plaintext highlighter-rouge">expected</code> decorations should be transformed into a program that runs tests, something like:</p>
<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">t/testing</span><span class="w"> </span><span class="s">"foo(int,int)"</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">ctx</span><span class="w"> </span><span class="p">(</span><span class="nf">new-ctx-from-params</span><span class="w"> </span><span class="s">"this"</span><span class="w"> </span><span class="s">"a"</span><span class="w"> </span><span class="s">"b"</span><span class="p">)</span><span class="w">
</span><span class="n">heap</span><span class="w"> </span><span class="p">(</span><span class="nf">init-heap</span><span class="p">)]</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-in-ctx</span><span class="w"> </span><span class="s">"a"</span><span class="p">)</span><span class="w">
</span><span class="n">peg</span><span class="w"> </span><span class="p">(</span><span class="nf">opnode</span><span class="w"> </span><span class="s">"+"</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="p">(</span><span class="nf">int-lit</span><span class="w"> </span><span class="mi">1</span><span class="p">))</span><span class="w">
</span><span class="n">ctx</span><span class="w"> </span><span class="p">(</span><span class="nf">update-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"x"</span><span class="w"> </span><span class="n">peg</span><span class="p">)]</span><span class="w">
</span><span class="c1">;; TEST HEAP</span><span class="w">
</span><span class="c1">;;</span><span class="w">
</span><span class="c1">;; This performs an actual test via `(t/is (= str1 str2))`, and</span><span class="w">
</span><span class="c1">;; prints helpful info on failure</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="s">"(heap 0 unit)"</span><span class="w"> </span><span class="s">"(heap 0 unit)"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; TEST CONTEXT</span><span class="w">
</span><span class="c1">;;</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"this"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"this\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"a"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"a\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"b"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"b\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"x"</span><span class="p">))</span><span class="w"> </span><span class="s">"(opnode \"+\" (var \"a\") (int-lit 1))"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; RECURSIVELY VISIT REST OF FUNCTION</span><span class="w">
</span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">b</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-in-ctx</span><span class="w"> </span><span class="s">"b"</span><span class="p">)</span><span class="w">
</span><span class="n">peg</span><span class="w"> </span><span class="p">(</span><span class="nf">opnode</span><span class="w"> </span><span class="s">"+"</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="p">(</span><span class="nf">int-lit</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w">
</span><span class="n">ctx</span><span class="w"> </span><span class="p">(</span><span class="nf">update-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"y"</span><span class="w"> </span><span class="n">peg</span><span class="p">))]</span><span class="w">
</span><span class="c1">;; TEST CONTEXT</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"this"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"this\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"a"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"a\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"b"</span><span class="p">))</span><span class="w"> </span><span class="s">"(var \"b\")"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"x"</span><span class="p">))</span><span class="w"> </span><span class="s">"(opnode \"+\" (var \"a\") (int-lit 1))"</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">ensure-strings-are-same</span><span class="w"> </span><span class="p">(</span><span class="nf">to-deref-string</span><span class="w"> </span><span class="p">(</span><span class="nf">lookup-key-in-ctx</span><span class="w"> </span><span class="n">ctx</span><span class="w"> </span><span class="s">"y"</span><span class="p">))</span><span class="w"> </span><span class="s">"(opnode \"+\" (var \"b\") (int-lit 1))"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; NO HEAP TEST (wasn't specified in statement's snapshot)</span><span class="w">
</span><span class="c1">;; ... continue</span><span class="w">
</span><span class="p">))))</span><span class="w">
</span></code></pre></div></div>
<h2 id="problems-with-new-implementation">Problems with new implementation</h2>
<ol>
<li>
<p><strong>Inlining <code class="language-plaintext highlighter-rouge">String</code> literals is space inefficient:</strong>
I’m inlining the actual <code class="language-plaintext highlighter-rouge">String</code> literals returned from <code class="language-plaintext highlighter-rouge">to-deref-string</code> for
each of the serialized PEGs in the context and heap. These will get really
big. These are generated from <code class="language-plaintext highlighter-rouge">PegNode</code>s, and I can’t use object references
inside of an <code class="language-plaintext highlighter-rouge">eval</code>. One way around this is to us a <code class="language-plaintext highlighter-rouge">bindings</code> wrapper, and
auto-gen names for each object reference, which is something I can do in the
future if it becomes an issue.</p>
</li>
<li>
<p><strong>Testing via String Comparisons:</strong>
If two PEGs differ, they will have different dereferenced strings.
These are hard to read as they can be HUGE. A better way to handle this would
be to write a PEG comparison method that recursively checks for PEG
equivalence. This also requires that I solve the binding problem that I
mention above (I can’t reference PEGs directly in an <code class="language-plaintext highlighter-rouge">eval</code>).</p>
</li>
<li>
<p><strong>Testing contexts is asymmetric:</strong>
At test generation I have access to the actual contexts (they’ve already been
serialized) but I don’t have access to the expected contexts…the testing
program I’m building is defining the expected contexts in a series of nested
let bindings, and these haven’t been executed yet (they’re still being
constructed). This means that when I check that contexts agree on a set of
keys, I’m only checking that they agree on the keys of the <em>serialized</em>
context. In particular, if the expected context has a bunch of garbage keys
that aren’t part of the serialized context (or if the serialized context
doesn’t include enough keys), these keys won’t be tested.</p>
<p>A fix is to write a function that takes a context and a list of keys and
asserts that the context has the same set of keys.</p>
</li>
</ol>_______ __ __ |_ _|.-----.-----.| |_|__|.-----.-----. | | | -__|__ --|| _| || | _ | |___| |_____|_____||____|__||__|__|___ | |_____| ______ __ __ | |.-----.----.-----.-----.| |__|.--.--.-----. | ---|| _ | _| | -__|| | || | |__ --| |______||_____|__| |__|__|_____||__|__||_____|_____|Time Co-op Writeup2020-09-09T20:00:00+00:002020-09-09T20:00:00+00:00/2020/09/09/time-coop<ul id="markdown-toc">
<li><a href="#overview" id="markdown-toc-overview">Overview</a></li>
<li><a href="#mutation-testing" id="markdown-toc-mutation-testing">Mutation Testing</a> <ul>
<li><a href="#example" id="markdown-toc-example">Example</a> <ul>
<li><a href="#pop-quiz-1" id="markdown-toc-pop-quiz-1">POP QUIZ 1</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#mutant-kill-ratio" id="markdown-toc-mutant-kill-ratio">Mutant Kill Ratio</a></li>
<li><a href="#equivalent-and-redundant-mutants" id="markdown-toc-equivalent-and-redundant-mutants">Equivalent and Redundant Mutants</a> <ul>
<li><a href="#problems-with-equivalent-and-redundant-mutants" id="markdown-toc-problems-with-equivalent-and-redundant-mutants">Problems with Equivalent And Redundant Mutants</a></li>
<li><a href="#how-we-handle-the-equivalent-and-redundant-mutant-problem" id="markdown-toc-how-we-handle-the-equivalent-and-redundant-mutant-problem">How We Handle the Equivalent And Redundant Mutant Problem</a></li>
<li><a href="#how-we-actually-handle-the-equivalent-and-redundant-mutant-problem" id="markdown-toc-how-we-actually-handle-the-equivalent-and-redundant-mutant-problem">How we <em>Actually</em> Handle The Equivalent And Redundant Mutant Problem</a></li>
</ul>
</li>
<li><a href="#detecting-equivalent-mutants-with-egraphs" id="markdown-toc-detecting-equivalent-mutants-with-egraphs">Detecting Equivalent Mutants with Egraphs</a> <ul>
<li><a href="#pop-quiz" id="markdown-toc-pop-quiz">POP QUIZ</a></li>
<li><a href="#handling-local-equalities" id="markdown-toc-handling-local-equalities">Handling Local Equalities</a></li>
</ul>
</li>
<li><a href="#solutions-to-pop-quizes" id="markdown-toc-solutions-to-pop-quizes">Solutions to Pop Quizes</a> <ul>
<li><a href="#pop-quiz-1-1" id="markdown-toc-pop-quiz-1-1">Pop Quiz 1</a></li>
<li><a href="#pop-quiz-2" id="markdown-toc-pop-quiz-2">Pop Quiz 2</a></li>
</ul>
</li>
</ul>
<h2 id="overview">Overview</h2>
<p>This week I want to introduce you to <em>Cornelius</em>, a static analysis tool to
detect equivalent and redundant mutants in Java programs. Cornelius takes in the
Java source files of a program and some mutants of that program, translates them
into Program Expression Graphs (PEGs), stuffs them into an Egraph, and runs a
rewrite system until equality saturation is reached. Finally, Cornelius checks
if any of the programs (the original program or the mutants) have become
equivalent under the rewrites. Cornelius is heavily inspired by Tate et al’s
<a href="http://www.cs.cornell.edu/~ross/publications/eqsat/">Peggy</a> tool. Under the
hood, Cornelius uses <a href="https://github.com/mwillsey/egg">egg</a>.</p>
<p>For this Time Co-op I want to</p>
<ol>
<li>Introduce <em>you</em> to mutation analysis</li>
<li>Introduce <em>you</em> to Cornelius</li>
<li>Get <em>your</em> input on how Cornelius can find some equivalent and redundant mutants</li>
</ol>
<p>If you’re interested in tinkering, check out the <a href="https://github.com/bkushigian/cornelius">Cornelius
Repository</a>. It will require Java 8 to
use the shell script wrapper. I haven’t gotten around to writing a full tutorial
but I’ll try to get that together for next time.</p>
<h2 id="mutation-testing">Mutation Testing</h2>
<p>Imagine you’ve just finished writing a test suite for one of your projects. How
good is your test suite? If you’re anything like me, then not very good. Still,
it would be nice to quantify just how not-good our test suites are.</p>
<p>What should tests do? Catch bugs, of course! Finding real live bugs in code is
hard, so we can’t measure this property directly. However, we can seed a bunch
of syntactic faults in our program, producing new broken programs called
<em>mutants</em>. Each of these mutants is a proxy for a real world bug.</p>
<p>After mutating the original program, we try to <em>kill</em> mutants by running the
test suite on each mutant. If a mutant causes one of the tests in the suite to
fail, that mutant is <em>killed</em>. We killed it. It ded.</p>
<h3 id="example">Example</h3>
<p>Consider the following program which computes the max of two <code class="language-plaintext highlighter-rouge">int</code>s:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">){</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">></span> <span class="n">b</span><span class="o">)</span> <span class="k">return</span> <span class="n">a</span><span class="o">;</span>
<span class="k">return</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Let’s look at four of this program’s mutants:</p>
<p><strong>Mutant 1:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">){</span>
<span class="c1">// `>` -> `!=`</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">!=</span> <span class="n">b</span><span class="o">)</span> <span class="k">return</span> <span class="n">a</span><span class="o">;</span>
<span class="k">return</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Mutant 2:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">){</span>
<span class="c1">// `>` -> `>=`</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">>=</span> <span class="n">b</span><span class="o">)</span> <span class="k">return</span> <span class="n">a</span><span class="o">;</span>
<span class="k">return</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Mutant 3:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">){</span>
<span class="c1">// `>` -> `false`</span>
<span class="k">if</span> <span class="o">(</span><span class="kc">false</span><span class="o">)</span> <span class="k">return</span> <span class="n">a</span><span class="o">;</span>
<span class="k">return</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Mutant 4:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">){</span>
<span class="c1">// `return a;` -> `;`</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">></span> <span class="n">b</span><span class="o">)</span> <span class="o">;</span>
<span class="k">return</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Let Clarence be a test suite with only a single test.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ClarenceTheTestSuite</span> <span class="o">{</span>
<span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">theOnlyTestClarenceHas</span><span class="o">()</span> <span class="o">{</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="n">max</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span><span class="mi">2</span><span class="o">),</span> <span class="mi">2</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h4 id="pop-quiz-1">POP QUIZ 1</h4>
<ol>
<li>Which of the above mutants does Clarence kill?</li>
<li>What proportion (written as a decimal) of mutants does Clarence kill? This
number is called the <strong>mutant kill ratio.</strong></li>
<li>Can <em>you</em> write tests to kill the other mutants? If not, why not? If so, what’s
your favorite color?</li>
<li><strong>(mandatory bonus question)</strong> Can <em>you</em> write tests to differentiate <em>all</em>
mutants? That is, can you write a test suite such that for every pair of
mutants <code class="language-plaintext highlighter-rouge">m1</code> and <code class="language-plaintext highlighter-rouge">m2</code>, there is a test <code class="language-plaintext highlighter-rouge">t</code> that behaves differently on <code class="language-plaintext highlighter-rouge">m1</code>
and <code class="language-plaintext highlighter-rouge">m2</code>?
If not, why not? If so, what is your favorite smell?</li>
</ol>
<h2 id="mutant-kill-ratio">Mutant Kill Ratio</h2>
<p>Problem 2 asks you to compute the mutant kill ratio. You should have gotten
0.25: <code class="language-plaintext highlighter-rouge">ClarenceTheTestSuite</code> kills mutant 1 but not mutants 2-4. Thus it kills
1/4 = 0.25 mutants. In general we want the mutant kill ratio to be close to 1;
let’s say that for the rest of the day, any mutation kill ratio of above 0.85 is
“good”.</p>
<h2 id="equivalent-and-redundant-mutants">Equivalent and Redundant Mutants</h2>
<p>Unless you broke reality you should have found it impossible to kill mutant 2.
This is because it is <em>semantically equivalent</em> to the original program, even
though it differs syntactically. Such a mutant is called an <strong>equivalent
mutant</strong>.</p>
<p>Likewise, you should have found it impossible to write a test that behaves
differently on mutants 3 and 4. These two mutants are semantically equivalent to
one another. Such mutants are called <strong>redundant mutants</strong>.</p>
<h3 id="problems-with-equivalent-and-redundant-mutants">Problems with Equivalent And Redundant Mutants</h3>
<p>Equivalent and redundant mutants cause two problems in mutation testing.</p>
<ol>
<li>
<p><em>They skew metrics:</em> The best a test suite can possibly do is to kill mutants
1, 3, and 4. This means that at best, the mutant kill ratio will be 0.75,
which is not ‘good’ according to our above definition.</p>
<p>Similarly, a killing a redundant mutant kills all the mutants in its
redundancy class. This means that as long as a redundancy class is left
unkilled, it as has an overly negative effect on the mutant kill ratio, and
once it has been killed it has an overly positive effect on the mutant kill
ratio.</p>
</li>
<li>
<p><em>They waste resources:</em> We have to run testing infrastructure on each mutant.
At scale this is expensive, and especially so with equivalent mutants. This
is because they can <em>never</em> be detected, so we have to run the entire testing
infrastructure, wasting CPU cycles. What’s worse, a human developer might
have to come in and waste human cycles trying to kill it by hand.</p>
</li>
</ol>
<p>The equivalent mutant problem is one of the reasons why mutation testing isn’t
more widely adopted in practice.</p>
<h3 id="how-we-handle-the-equivalent-and-redundant-mutant-problem">How We Handle the Equivalent And Redundant Mutant Problem</h3>
<p>The only way to handle equivalent and redundant mutants is to detect them
before running the test suite. This is undecidable in general, but there are a
lot of mutants that are ‘obviously’ equivalent or redundant.</p>
<p>There have been a number of attempts to detect equivalent and redundant mutants.
These attempts fall into two categories:</p>
<ol>
<li><strong>Use of constraints:</strong> by modeling the semantics of two programs with
constraints, we can a query a constraint solver to determine if there are
inputs that force the programs to behave differently.
<ul>
<li><a href="https://ieeexplore.ieee.org/document/92910/">Constraint-based automatic test data generation (DeMilli and Offutt, 1991)</a></li>
<li><a href="https://www.semanticscholar.org/paper/Using-Constraints-to-Detect-Equivalent-Mutants-Pan-Mason/329d2f8107679740395bac2cc0525f83adf33a20?p2df">Using Constraints to Detect Equivalent Mutants (Offutt and Pan, 1994)</a></li>
<li><a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/(SICI)1099-1689(199709)7:3%3C165::AID-STVR143%3E3.0.CO;2-U">Automatically Detecting Equivalent Mutants and Infeasible Paths (Offutt and Pan, 1997)</a></li>
<li><a href="https://arxiv.org/abs/1207.2234">Using Constraints for Equivalent Mutant Detection (Nica and Wotawa, 2012)</a></li>
<li><a href="https://ieeexplore.ieee.org/document/8728921/">Medusa: Mutation Equivalence Detection Using SAT Analysis (Kushigian, Rawat, Just, 2019)</a></li>
</ul>
</li>
<li>
<p><strong>Using compiler techniques:</strong> compiler optimizations rewrite programs to
more efficient forms. These rewrites preserve program semantics. Therefore,
if two different programs are rewritten to the same optimized version they
must have begun as equivalent.</p>
<ul>
<li><a href="https://ieeexplore.ieee.org/ielx7/32/8338178/07882714.pdf?tp=&arnumber=7882714&isnumber=8338178&ref=aHR0cHM6Ly9pZWVleHBsb3JlLmllZWUub3JnL3N0YW1wL3N0YW1wLmpzcD9hcm51bWJlcj03ODgyNzE0">Detecting Trivial Mutant Equivalences via Compiler Optimisations (Kintis et al., 2018)</a></li>
<li><a href="https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=7194639&casa_token=SEBDFdKI7FkAAAAA:sdJSiNcUmwvStDWH1wS2UL1g1TnEtRhZBF6yXXmKOUjJ52iYEys-tl-C-mma9l8S7mzp4_Gjz9s&tag=1">Trivial Compiler Equivalence: A Large Scale Empirical Study of a Simple, Fast and Effective Equivalent Mutant Detection Technique (Papadakis et al., 2015)</a></li>
<li><a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/stvr.4370040303">Using compiler optimization techniques to detect equivalent mutants (Offutt and Jefferson, 1994)</a></li>
</ul>
</li>
</ol>
<p>Cornelius uses a new approach: store all mutants in an Egraph and compute
equality saturation.</p>
<h3 id="how-we-actually-handle-the-equivalent-and-redundant-mutant-problem">How we <em>Actually</em> Handle The Equivalent And Redundant Mutant Problem</h3>
<p>Use test coverage metrics.</p>
<h2 id="detecting-equivalent-mutants-with-egraphs">Detecting Equivalent Mutants with Egraphs</h2>
<p>Java is complicated, and I won’t be doing anything with heaps or referency type
things. Instead we will focus on loop free programs with primitive types.</p>
<p>Cornelius starts by translating a program into a PEG. This currently involves
<em>regularizing</em> the AST so that there is a single return location. For instance,
after regularization the original program becomes:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">max</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Default value to satisfy Javac's flow checking. Definitely NOT a hack</span>
<span class="kt">int</span> <span class="n">__RETURN_RESULT__</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2147483648</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">__method_has_returned__</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">></span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="n">__method_has_returned__</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">__RETURN_RESULT__</span> <span class="o">=</span> <span class="n">a</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/* --- Auto-generated guard statement --- */</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">__method_has_returned__</span><span class="o">)</span> <span class="o">{</span>
<span class="n">__method_has_returned__</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">__RETURN_RESULT__</span> <span class="o">=</span> <span class="n">b</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">__RETURN_RESULT__</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>And let’s be honest, this is really an improvement, and is probably how the
developer <em>should</em> have written the code in the first place.</p>
<p>It is future work to make this transformation <em>implicit</em>, both saving time and
getting rid of pesky artifacts like the default initialization value in
<code class="language-plaintext highlighter-rouge">__RETURN_RESULT__</code>. This shouldn’t be too hard, but it will be subtle so I
haven’t gotten around to it yet.</p>
<p>Cornelius then translates the reguralized AST into a PEG. I’ll represent PEGs as
S-expressions, but this is inaccurate: PEGs use <em>deduplication</em> or <em>node
sharing</em> to cut down on size and allow for very fast application of rewrite
rules. I can’t actually represent this as an S-expression so I’ll just
undeduplicate the PEG.</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">method-root</span>
<span class="c1">;; Return value</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb">></span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span> <span class="nv">true</span> <span class="nv">false</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb">></span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="mi">-2147483648</span><span class="p">))</span>
<span class="c1">;; Resulting heap (pay no mind!)</span>
<span class="p">(</span><span class="nf">heap</span> <span class="mi">0</span><span class="p">))</span>
</code></pre></div></div>
<p>Since I like you I’m gonna rewrite this to a nicer form; I’ll extract the
return value, omitting the heapy bit, and I’ll apply the rewrite rule <code class="language-plaintext highlighter-rouge">(phi ?c
true false) => ?c</code> to make this more legible:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">></span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb">></span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span>
<span class="mi">-2147483648</span><span class="p">))</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">phi</code> nodes are if-then-else expressions, and the <code class="language-plaintext highlighter-rouge">var</code> nodes represent
free variables (in this case, parameters passed in to the method).</p>
<p>The (simplified) pegs for the four mutants are:</p>
<p><strong>Mutant 1:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">!=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span>
<span class="mi">-2147483648</span><span class="p">))</span>
</code></pre></div></div>
<p><strong>Mutant 2:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">>=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb">>=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span>
<span class="mi">-2147483648</span><span class="p">))</span>
</code></pre></div></div>
<p><strong>Mutant 3:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="nv">false</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="nv">false</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span>
<span class="mi">-2147483648</span><span class="p">))</span>
</code></pre></div></div>
<p><strong>Mutant 4:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="pop-quiz">POP QUIZ</h3>
<ol>
<li>
<p>Can <em>you</em> find a set of rewrite rules that will discover the equivalence
between mutants 3 and 4? Generalize your results.</p>
</li>
<li>
<p>Can <em>you</em> find a set of rewrite rules that will discover the equivalence
between the original program and mutant 2? (<strong>Warning!</strong> This is tricky!)</p>
</li>
</ol>
<p>Solving the first problem is easier than solving the second. The following two
rewrite rules will get us there:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">!</span> <span class="nv">false</span><span class="p">)</span> <span class="nv">=></span> <span class="nv">true</span>
<span class="p">(</span><span class="nf">phi</span> <span class="nv">true</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span> <span class="nv">=></span> <span class="nv">?a</span>
</code></pre></div></div>
<p>Handling the second problem, though, involves reasoning about <em>local
equalities</em>.</p>
<h3 id="handling-local-equalities">Handling Local Equalities</h3>
<p>First, if you got this far, you’re awesome! You get a <em>free mutant!!!!!</em> If
you’ve reached your hour (which you probably have), GET OUT OF HERE! YOU’RE
DONE! GO WALK YOUR MUTANT!</p>
<p>Alright, let’s take a look at a contrived program and some of its mutants.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="nf">areEqual</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>There are 8 mutants generated for this subject, and when Cornelius runs on them
it outputs the following discovered equivalence classes (each line contains a
single equivalence class, and mutant id <code class="language-plaintext highlighter-rouge">0</code> corresponds to the original
program):</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0
1
2
3 6 7
4
5
</code></pre></div></div>
<p>That means that Cornelius detected that mutants 3, 6, and 7 are redundant to one
another, and no other equivalences were detected.</p>
<p>This is ground truth:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>3 6 7
0 1 2 4 5 8
</code></pre></div></div>
<p>The good news is Cornelius hasn’t reported any incorrect equivalences! SWEET!</p>
<p>The bad news is that Cornelius missed a bunch of easy equivalences. Here are a
couple of the equivalent mutants Cornelius missed:</p>
<p><strong>Mutant 1:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="nf">areEqual</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o"><=</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// `==` -> `<=`</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Mutant 5:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="nf">areEqual</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">>=</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span> <span class="c1">// `==` -> `>=`</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p><strong>Mutant 8:</strong></p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kt">boolean</span> <span class="nf">areEqual</span><span class="o">(</span><span class="kt">int</span> <span class="n">a</span><span class="o">,</span> <span class="kt">int</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">;</span> <span class="c1">// `return false;` -> `;`</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Let’s take a closer look at mutant 8 as it compares to the original program. The
original program has the following PEG (for readability I’ve applied a couple
rewrite rules):</p>
<p><strong>Original Program:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="nv">true</span>
<span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="nv">false</span><span class="p">))</span>
<span class="nv">false</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="nv">false</span>
<span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="nv">false</span><span class="p">))</span>
</code></pre></div></div>
<p><strong>Mutant 8:</strong></p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="nv">false</span><span class="p">))</span>
<span class="nv">false</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="nv">false</span><span class="p">))</span>
</code></pre></div></div>
<p>These should be rewritable to one another. We can break these into sub problems:</p>
<ol>
<li>Can we find a way to rewrite
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(phi (== (var a) (var b))
(phi (! (== (var a) (var b)))
true
(== (var a) (var b)))
false)
</code></pre></div> </div>
<p>to</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(phi (== (var a) (var b))
(== (var a) (var b))
false)
</code></pre></div> </div>
<p>?</p>
</li>
<li>Can we find a way to rewrite
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(phi (== (var a) (var b))
(phi (! (== (var a) (var b)))
false
(== (var a) (var b)))
false)
</code></pre></div> </div>
<p>to</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(phi (== (var a) (var b))
(== (var a) (var b))
false)
</code></pre></div> </div>
<p>?</p>
</li>
</ol>
<p>In the above questions, is there a way to do this purely with rewrite rules?
Remember that we don’t want any term to rewrite to multiple ‘value’ terms. So,
for instance, rewriting <code class="language-plaintext highlighter-rouge">(== (var a) (var b))</code> to <code class="language-plaintext highlighter-rouge">true</code> will rewrite it
<em>globally</em>.</p>
<h2 id="solutions-to-pop-quizes">Solutions to Pop Quizes</h2>
<h3 id="pop-quiz-1-1">Pop Quiz 1</h3>
<ol>
<li>Clarence kills mutant 1.</li>
<li>Clarence has a mutant kill ratio of 0.25</li>
<li>The following test kills mutants 3 and 4
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nd">@Test</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">aNewTestForClarence</span><span class="o">()</span> <span class="o">{</span>
<span class="n">assertEquals</span><span class="o">(</span><span class="n">max</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">1</span><span class="o">),</span> <span class="mi">2</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div> </div>
<p>There are no tests can kill mutant 2 because it is equivalent.</p>
</li>
<li>No, mutants 3 and 4 are in the same redundancy class.</li>
</ol>
<h3 id="pop-quiz-2">Pop Quiz 2</h3>
<ol>
<li>The rewrite rules
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">!</span> <span class="nv">false</span><span class="p">)</span> <span class="nv">=></span> <span class="nv">true</span>
<span class="p">(</span><span class="nf">phi</span> <span class="nv">true</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span> <span class="nv">=></span> <span class="nv">?a</span>
</code></pre></div> </div>
</li>
<li>
<p>Let’s try to solve problem 2 from above. First, I’m gonna use a rule to
rewrite the above programs to get rid of that stupid default value:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">rule1:</span> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="nv">?c</span><span class="p">)</span> <span class="p">(</span><span class="nf">phi</span> <span class="nv">?c</span> <span class="nv">?x</span> <span class="nv">?y</span><span class="p">)</span> <span class="nv">?z</span><span class="p">)</span> <span class="nv">=></span> <span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="nv">?c</span><span class="p">)</span> <span class="nv">?y</span> <span class="nv">?z</span><span class="p">)</span>
</code></pre></div> </div>
<p>This makes sense because if we’re in the <em>then</em> branch of a <code class="language-plaintext highlighter-rouge">phi</code> node we know
the condition is true.</p>
<p>This gives us</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Original</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">></span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
<span class="c1">;; Mutant 2</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">>=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
</code></pre></div> </div>
<p>Next, let’s distribute the negation over the comparison operators:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">rule2:</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">></span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">))</span> <span class="nv">=></span> <span class="p">(</span><span class="nb"><=</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span>
<span class="nv">rule3:</span> <span class="p">(</span><span class="nf">!</span> <span class="p">(</span><span class="nb">>=</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">))</span> <span class="nv">=></span> <span class="p">(</span><span class="nb"><</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span>
</code></pre></div> </div>
<p>This gives us</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Original</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb"><=</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
<span class="c1">;; Mutant 2</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb"><</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
</code></pre></div> </div>
<p>Now I want to split the <code class="language-plaintext highlighter-rouge"><=</code> into two cases: <code class="language-plaintext highlighter-rouge"><</code> and <code class="language-plaintext highlighter-rouge">==</code>:</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">rule4:</span> <span class="p">(</span><span class="nb"><=</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span> <span class="nv">=></span> <span class="p">(</span><span class="nf">||</span> <span class="p">(</span><span class="nb"><</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">)</span> <span class="p">(</span><span class="nf">==</span> <span class="nv">?a</span> <span class="nv">?b</span><span class="p">))</span>
</code></pre></div> </div>
<p>This produces</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Original</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">||</span> <span class="p">(</span><span class="nb"><</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
<span class="c1">;; Mutant 2</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb"><</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
</code></pre></div> </div>
<p>Okay, let’s turn our <code class="language-plaintext highlighter-rouge">||</code> into nested <code class="language-plaintext highlighter-rouge">phi</code> nodes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rule5: (phi (|| ?c1 ?c2) ?a ?b) => (phi ?c1 ?a (phi ?c2 ?a ?b))
</code></pre></div> </div>
<p>This produces</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Original</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb"><</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nf">==</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)))</span>
<span class="c1">;; Mutant 2</span>
<span class="p">(</span><span class="nf">phi</span> <span class="p">(</span><span class="nb"><</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">)</span> <span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">))</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">b</span><span class="p">)</span>
<span class="p">(</span><span class="nf">var</span> <span class="nv">a</span><span class="p">))</span>
</code></pre></div> </div>
<p>Finally, if we can rewrite <code class="language-plaintext highlighter-rouge">(phi (== (var a) (var b)) (var b) (var a))</code> to <code class="language-plaintext highlighter-rouge">(var
a)</code>, we win. One way to do this would be to rewrite the <code class="language-plaintext highlighter-rouge">(var b)</code> in the then
branch of the <code class="language-plaintext highlighter-rouge">phi</code> node to <code class="language-plaintext highlighter-rouge">(var a)</code>, and use the rule</p>
<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">rule6:</span> <span class="p">(</span><span class="nf">phi</span> <span class="nv">?c</span> <span class="nv">?a</span> <span class="nv">?a</span><span class="p">)</span> <span class="nv">=></span> <span class="nv">?a</span>
</code></pre></div> </div>
<p><strong>This is where I’m stuck.</strong> I want to do <em>local rewrites</em> , but all rewrites
are <em>global</em> in an Egraph.</p>
<p>I’ve tried to use a technique called <a href="/2020/07/28/local-reasoning-with-equality-refinement.html">equality
refinement</a> to make local rewrites, but this still
introduces soundness errors. Another idea is to use a second Egraph to do
local reasoning, and this seems like it could be promising, but would also
have a few downsides as well.</p>
</li>
</ol>