<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Course Notes on Xiang Huang | 黄湘</title>
    <link>https://xianghuang.me/course/</link>
    <description>Recent content in Course Notes on Xiang Huang | 黄湘</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <atom:link href="https://xianghuang.me/course/" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>The Karatsubas</title>
      <link>https://xianghuang.me/course/csc482/kara/</link>
      <pubDate>Thu, 01 Feb 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc482/kara/</guid>
      <description>
        <![CDATA[
        <h2 id="the-father">The Father</h2>
<p>Every semester I teach Karatsuba algorithm by <a href="https://en.wikipedia.org/wiki/Anatoly_Karatsuba">Anatoly Karatsuba</a> in the first or second lecture. Well, to impress my students how a normal task like integer multiplication can be improved by clever algorithms. I still remember the &ldquo;Aha&rdquo; moment of reading the algorithm. By using a small trick to save one multiplication in each stage, we can achieve a faster algorithm!</p>
<h2 id="the-daughter">The Daughter</h2>
<p>But that is not the only Karatsuba having impact on me. When I was a PhD student, one thing I worked on is to use a computational model called Chemical Reaction Network (CRN), to compute real number. The Number that I extremely interested in computing was Euler&rsquo;s $\gamma$, which can be defined as
$$
\gamma = \lim_{n\to \infty} \bigg(-\log n + \sum_{k=1}^{n}\frac{1}{k}\bigg).
$$
The first few digits of the number are 0.5772156649 &hellip;</p>
<p>The above formula can not be used to actually compute $\gamma$. Firstly, it is very slow! Secondly, the CRN model I used is a continuous model. I need something continuous, such as an integral. I tried many many formula but failed.</p>
<p>Then one day I ran into <a href="https://math.stackexchange.com/questions/129777/what-is-the-fastest-most-efficient-algorithm-for-estimating-eulers-constant-g">this thread</a> on StackOverflow and people talked about a method that can compute $\gamma$ fast. The author? <a href="http://www.ccas.ru/karatsuba/index_e.htm">Ekatherina Karatsuba</a>, the daughter of Anatoly Karatsuba. Her research interest are around fast algorithms.</p>
<blockquote>
    The field of computational mathematics, which is called Fast Algorithms, was born in 1960. By an algorithm, not formalizing this concept, we mean a rule or a way of computation. 
</blockquote>
<p>I found the formula I need in her paper to do the work for me. Of course, it is not that straightforward. The formula looks like.</p>
<p>\[
\gamma =\Gamma^{\prime}(2) -1,
\]
where $\Gamma$ is the <em>Gamma function</em> and $\Gamma^{\prime}(2)=\int_0^{\infty} e^{-t}t\log(t)d t$.</p>
<p>The list of her publications contains many other work on computing mathematical constants and special function. One thing I found specifically very interested is <a href="https://sci-hubtw.hkvisa.net/10.1023/a:1021948002934">this one</a>. Titled: <em>Fast Computation Of ζ(3) and of Some Special Integrals Using The Ramanujan Formula and Polylogarithms.</em></p>
<p>$$\zeta(3) = -\frac{1}{2}\bigg(\Gamma^{(3)}(1) -3\Gamma^{(2)}(1)\Gamma^{(1)}(1) + 2\Big(\Gamma^{(1)}(1)\Big)^{3}\bigg),$$</p>
<p>which is something I identified that can be computed by CRN using the tricks I developed previous to compute $\gamma$. This time we can compute <a href="https://en.wikipedia.org/wiki/Ap%C3%A9ry%27s_constant">Apéry&rsquo;s constant</a>.</p>
<p>Coincidentally, I just figured out a way to do it by another formula in the Wiki page <a href="https://en.wikipedia.org/wiki/Ap%C3%A9ry%27s_constant">Apéry&rsquo;s constant</a>.</p>
<p>\[
\zeta(3) = -\frac{1}{2}\bigg( \Gamma^{(3)}(1) + \gamma^{3} + \frac{1}{2}\pi^{2}\gamma\bigg) = -\frac{1}{2}\varphi^{(2)}(1).
\]
But I only use the first half of the formula. I have no idea how to deal with the <a href="https://en.wikipedia.org/wiki/Polygamma_function">polygamma function</a> in the second equation, where
$$
\varphi^{(m)}(z)= (-1)^{m+1}\int_0^{\infty}\frac{t^m e^{-zt}}{1-e^{-t}} dt,
$$
although it looks manageable.</p>
<hr>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>The Tao of Solving Problems</title>
      <link>https://xianghuang.me/course/csc482/juyifansan/</link>
      <pubDate>Sun, 28 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc482/juyifansan/</guid>
      <description>
        <![CDATA[
        <p>I am from China, and I grew up in an environment where you need to solve sometimes tedious problems repeatedly to proficiency. This ensures that one will excel in the important exam that determines many aspects of a Chinese&rsquo;s life: <a href="https://www.theguardian.com/world/2016/oct/12/gaokao-china-toughest-school-exam-in-world">the Gaokao</a>. Two important philosophies helped me survive those days: &ldquo;举一反三&rdquo; (jǔ yī fǎn sān) and “融会贯通” (róng huì guàn tōng).</p>
<p>&ldquo;举一反三&rdquo; (jǔ yī fǎn sān) means &ldquo;from one example, deduce solutions for many other problems.&rdquo; This emphasizes the concept of applying a solution or understanding from one specific problem to a variety of other, related problems, which is a fundamental skill in algorithmic thinking and problem-solving.</p>
<p>“融会贯通” (róng huì guàn tōng) means &ldquo;integrate knowledge and achieve a thorough understanding.&rdquo; This suggests not only learning various algorithms and concepts but also synthesizing them into a comprehensive, interconnected understanding, crucial in algorithm design and application.</p>
<p>You can see these ideas reflected in my lab and homework assignments:</p>
<ul>
<li>Understanding an algorithm means you can generalize it.</li>
<li>Understanding an algorithm means you can adapt it to different, perhaps non-classical, scenarios.</li>
<li>Understanding an algorithm means you can integrate it with other methods to solve bigger problems.</li>
<li>Understanding an algorithm means you can reinvent it.</li>
</ul>
<hr>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Successive Squaring Algorithm</title>
      <link>https://xianghuang.me/course/squaring/</link>
      <pubDate>Sat, 27 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/squaring/</guid>
      <description>
        <![CDATA[
        <p>The successive squaring algorithm is a method to compute large power modulo m. We are going to implement it in this post.</p>
<h1 id="basic-ideas">Basic Ideas</h1>
<p>The following simple properties can guide us on developing the algorithm.</p>
<p><strong>Property 1</strong>:
$(p \cdot q)\% m = [(p \% m) \cdot(q \% m)] \% m. $</p>
<p>That is , if we need to do the product of $p\cdot q$ modulo $m$, we can instead do the $p$ modulo $m$ and $q$ modulo $m$ separately, and multiply the results together. But then the result might exceed $m$, so we need to modulo $m$ for another time.</p>
<p>Now let&rsquo;s consider computing $a^b \,\%m$, we need the following property.</p>
<p><strong>Property 2</strong>:</p>
<ul>
<li>if b is even:</li>
</ul>
<p>$$
a^b \ \% m = (a ^ {\frac{b}{2}} \cdot a ^ {\frac{b}{2}}) \% m, \quad \text{by rewriting } a ^ b
$$
$$
= ((a ^ {\frac{b}{2}} \% m) \cdot(a ^ {\frac{b}{2}} \% m)) \% m, \quad \text{by property 1.}
$$</p>
<p>This suggests a recursive algorithm.</p>
<p>By now, we should be able to handle even exponents. What if $b$ is odd? Well, we just need to take one out of the $b$. That is , if $b-1$ is an even number, we can just rely on the recursive call on computing that.</p>
<ul>
<li>if b is odd:</li>
</ul>
<p>$$ a ^ b \% m = (a \cdot(a ^ {b - 1})) \% m = (a \% m) \cdot(a ^ {b - 1}) \% m $$</p>
<p><strong>Special Case</strong>:</p>
<p>We will eventually reduce $b$ to 0, in which case $a^0 \equiv 1 \pmod{m}$.</p>
<h1 id="pseudocode">Pseudocode</h1>
<p>By the above analysis, we can implement the function as what follows.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># Computing a^b modulo m, where b is large. </span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">largePower</span>(a, b, m):
    <span style="color:#75715e"># Base Cases</span>
    <span style="color:#66d9ef">if</span> (b <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>):
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>
    <span style="color:#75715e"># If b is Even</span>
    <span style="color:#66d9ef">if</span> (b <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>):
        y <span style="color:#f92672">=</span> largePower(a, b <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>, m)
        <span style="color:#66d9ef">return</span> (y <span style="color:#f92672">*</span> y) <span style="color:#f92672">%</span> m
    <span style="color:#75715e"># If b is Odd</span>
    <span style="color:#66d9ef">else</span>:
        y <span style="color:#f92672">=</span> a <span style="color:#f92672">%</span> m
        <span style="color:#66d9ef">return</span> (y <span style="color:#f92672">*</span> largePower(a, b <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>, m)) <span style="color:#f92672">%</span> m

</code></pre></td></tr></table>
</div>
</div><h1 id="iterative-version">Iterative Version</h1>
<p>We can also implement the method by loops. The iterative process has a lot to do with the <strong>binary representation of $b$</strong>. Consider $b=20=2^4+2^2$ or $b=10100_2$ in binary. Note that we have two $1$&rsquo;s in &ldquo;10100&rdquo;. Or we can view &ldquo;$10100_2 = 10000_2 +100_2$&rdquo;. From right to left, we will run into the first &ldquo;1&rdquo; after two digits; and the second &ldquo;1&rdquo; after four digits. The program keeps squaring until it runs into a &ldquo;1&rdquo;. So by the time it runs into the first &ldquo;1&rdquo;, we have $(a^2)^2 = a^{2\times 2}= a^{2^2}$ already. By the time it runs into the second &ldquo;1&rdquo;, we have see four digits and have been squaring four times, so we have $((((a^2))^2)^2)^2 = a^{2\times 2\times 2 \times 2}= a^{2^4}$.</p>
<p>Another observation is that, each time when we see a &ldquo;1&rdquo;, we multiply the squaring result to the output <code>result</code>. We did that twice for $b=10100$ for the two 1&rsquo;s. So we have <code>result</code>= $a^{2^4 + 2^2}=a^{20} = a^{10100_2}$.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">largePowerIterative</span>(a, b, m):
    result <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>
    a <span style="color:#f92672">=</span> a <span style="color:#f92672">%</span> m

    <span style="color:#66d9ef">while</span> b <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#75715e"># If b is odd, multiply a with result</span>
        <span style="color:#66d9ef">if</span> b <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span>:
            result <span style="color:#f92672">=</span> (result <span style="color:#f92672">*</span> a) <span style="color:#f92672">%</span> m

        <span style="color:#75715e"># b must be even now</span>
        b <span style="color:#f92672">=</span> b <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>  <span style="color:#75715e"># Use floor division to avoid float</span>
        a <span style="color:#f92672">=</span> (a <span style="color:#f92672">*</span> a) <span style="color:#f92672">%</span> m

    <span style="color:#66d9ef">return</span> result

</code></pre></td></tr></table>
</div>
</div><h1 id="generalization">Generalization</h1>
<p>We know binary number are not so special. Now if your treat $b$ as a <strong>ternary</strong> number. How will you implement the algorithm?</p>
<h1 id="test">Test</h1>
<p>Try a = 7, b = 327, m = 853 to see what you get. (I made up these numbers just now. You can surely make up more tests. Use <a href="https://www.wolframalpha.com/">Wolfram Alpha</a> to get quick results.)</p>
<hr>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Computing the n-th Fibonacci Number in O(log(n)) Time</title>
      <link>https://xianghuang.me/course/csc482/fibo/</link>
      <pubDate>Thu, 25 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc482/fibo/</guid>
      <description>
        <![CDATA[
        <div class="toc">
<nav id="TableOfContents">
  <ul>
    <li><a href="#the-o-n-time-complexity-is-not-good-for-a-number-theoretical-algorithm">The $O(n)$ Time Complexity Is Not Good For A Number Theoretical Algorithm</a></li>
    <li><a href="#matrix-method">Matrix Method</a></li>
    <li><a href="#no-matrix-please">No Matrix, Please.</a></li>
    <li><a href="#performance">Performance</a></li>
    <li><a href="#generalization">Generalization</a></li>
    <li><a href="#other-methods-i-tried-but-failed">Other Methods I Tried but Failed</a></li>
    <li><a href="#final-remarks">Final Remarks</a></li>
  </ul>
</nav>
</div>



<p>The other day, I sent an announcement to my students about the concept of an open-ended lab, stating they could pick any problem as long as <strong>&ldquo;it wasn&rsquo;t as trivial as computing the $n$-th Fibonacci number&rdquo;</strong>. But is it really trivial? In the world of algorithms, even straightforward tasks like integer multiplication have spawned a range of fast algorithms, such as Karatsuba, Toom-Cook, and Schönhage-Strassen (See Wiki: <a href="https://en.wikipedia.org/wiki/Multiplication_algorithm">Multiplication algorithm</a>), not to mention the <a href="https://www.quantamagazine.org/mathematicians-discover-the-perfect-way-to-multiply-20190411/">recent</a> $O(n\log n)$ method for $n$- bit two numbers. As as the numbers grow, what seems fast can become slow—just think about the grade school multiplication algorithm.</p>
<h1 id="the-o-n-time-complexity-is-not-good-for-a-number-theoretical-algorithm">The $O(n)$ Time Complexity Is Not Good For A Number Theoretical Algorithm</h1>
<p>Every semester, in my algorithm course I review the Big-O notations, as many people do. One thing that I always emphasize is that the <a href="https://stackoverflow.com/questions/53042838/why-naive-primality-test-algorithm-is-not-polynomial">naive primary test</a> is not a <strong>polynomial algorithm</strong>, and it is not deemed fast. The reason is that we measure complexity of an algorithms by its input length. A number $n$ is presented in $\log(n)$ bits. A polynomial algorithms needs to be in polynomial of $\log(n)$. So, a $O(n)$ algorithm is an exponential algorithm in this sense.</p>
<p>One can read more on this in <a href="https://en.wikipedia.org/wiki/Introduction_to_Algorithms">CLRS</a> Chapter 31: Number - theoretic Algorithms.</p>
<blockquote>
    In this chapter, a “large input” typically means an input containing “large integers” rather than an input containing “many integers” (as for sorting). Thus,
    we shall measure the size of an input in terms of the number of bits required to
represent that input, not just the number of integers in the input. An algorithm
with integer inputs $a_1, a_2, \cdots, a_k$ is a $\textbf{polynomial - time algorithm}$ if it runs in time
polynomial in $\log a_1, \log a_2, \cdots, \log a_k$, that is, polynomial in the lengths of its binary-encoded inputs.
</blockquote >
<p>Now let&rsquo;s come back to Fibonacci number. Every semester, I use it to introduce recursion and some basic dynamic programming (memoization trick) to my students. Everyone is glad that we can avoid the naive recursive function implementation to achieve $O(n)$ time and $O(1)$ space!</p>
<p>But wait! From the naive primary test we know the $O(n)$ algorithm for Fibonacci number is <strong>not</strong> a polynomial algorithm <strong>with respect to the input length</strong>.</p>
<div class="highlight myclass"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fib_linear</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>
    <span style="color:#66d9ef">elif</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>
    a, b <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>
    <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>, n <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>):
        a, b <span style="color:#f92672">=</span> b, (a <span style="color:#f92672">+</span> b)
    <span style="color:#66d9ef">return</span> b


</code></pre></td></tr></table>
</div>
</div><p>Can we find a polynomial algorithm for computing the $n$-th Fibonacci number? Ideally in $O(\log n)$? Before we continued, we need to solve a problem: $n$-th Fibonacci number is about $O(n)$ long (Why? See this <a href="https://www.quora.com/Why-is-the-nth-Fibonacci-number-about-0-694-n-bits-long">Quora thread</a> for more info. But it is not our focus here.)  It is exponentially long with respect to the input length! How can our algorithm output so long a thing in $O(\log n)$ time? Well, we can avoid this by taking a modulo just as in <a href="https://leetcode.com/problems/domino-and-tromino-tiling/description/">Leetcode 790</a>. In that way, every number we compute in with in fixed length, and the arithmetic operations between two numbers will not grow as $n$ grows.</p>
<h1 id="matrix-method">Matrix Method</h1>
<p>To calculate the n-th Fibonacci number efficiently, we can use a technique known as matrix exponentiation, which allows us to achieve a time complexity of O(log n). The Fibonacci sequence can be represented by a matrix. Although the matrix representation looks very scary, it is not. It is just a fancy way to pack
the following two formula altogether.
$$
\begin{align}
&amp;F_{n+1}= F_n + F_{n-1} \\
&amp;F_n    = F_n
\end{align}
$$</p>
<p>We can rewrite it into the following.
\[
\begin{bmatrix}
F(n+1) \\
F(n)
\end{bmatrix}
=\begin{bmatrix}
1 &amp; 1 \\
1 &amp; 0
\end{bmatrix}\begin{bmatrix}
F(n) \\
F(n-1)
\end{bmatrix}
\]</p>
<p>If we denote the matrix</p>
<p>\[
\begin{bmatrix}
1 &amp; 1 \\
1 &amp; 0
\end{bmatrix}
\]</p>
<p>as $M$, we can express $F(n)$ as:</p>
<p>\[
\begin{bmatrix}
F(n) \\
F(n-1)
\end{bmatrix}
=M^{(n-1)}
\begin{bmatrix}
F(1) \\
F(0)
\end{bmatrix}
\]</p>
<p>where F(1) = 1 and F(0) = 0.</p>
<p>The key here is to compute $M^{(n-1)}$ efficiently. We can do this using the concept of exponentiation by squaring, which is a method where we divide the power in half at each step, squaring the result as we go along. This method reduces the number of multiplications needed to calculate $M^n$, resulting in a logarithmic time complexity. The method is not all that mysterious. I talked about the <a href="https://en.wikipedia.org/wiki/Exponentiation_by_squaring">Exponential by Squaring</a> algorithm in my last post. That one is for computing modulo of large number&rsquo;s large exponent, which makes it a very useful algorithm in Cryptography! Here the matrix exponent computation is more of less the same.</p>
<p>Since the Fibonacci numbers can grow quite large, we will use modulo $10^9 + 7$ to keep the numbers within an integer range.</p>
<p>Here&rsquo;s the Python code implementing this approach:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">MOD <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span><span style="color:#f92672">**</span><span style="color:#ae81ff">9</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">7</span>

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">matrix_multiply</span>(A, B):
    result <span style="color:#f92672">=</span> [[<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>], [<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>]]
    <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>):
        <span style="color:#66d9ef">for</span> j <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>):
            <span style="color:#66d9ef">for</span> k <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>):
                result[i][j] <span style="color:#f92672">=</span> (result[i][j] <span style="color:#f92672">+</span> A[i][k] <span style="color:#f92672">*</span> B[k][j]) <span style="color:#f92672">%</span> MOD
    <span style="color:#66d9ef">return</span> result

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">matrix_power</span>(matrix, n):
    result <span style="color:#f92672">=</span> [[<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">0</span>], [<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">1</span>]]  <span style="color:#75715e"># Identity matrix</span>
    <span style="color:#66d9ef">while</span> n <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">if</span> n <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
            result <span style="color:#f92672">=</span> matrix_multiply(result, matrix)
        matrix <span style="color:#f92672">=</span> matrix_multiply(matrix, matrix)
        n <span style="color:#f92672">//=</span> <span style="color:#ae81ff">2</span>
    <span style="color:#66d9ef">return</span> result

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fib</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>
    M <span style="color:#f92672">=</span> [[<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">1</span>], [<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">0</span>]]
    M_power <span style="color:#f92672">=</span> matrix_power(M, n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>)
    <span style="color:#66d9ef">return</span> M_power[<span style="color:#ae81ff">0</span>][<span style="color:#ae81ff">0</span>]  <span style="color:#75715e"># F(n) is located at the top left of the matrix</span>

<span style="color:#75715e"># Test the function with a sample value</span>
print(fib(<span style="color:#ae81ff">10</span>))
</code></pre></td></tr></table>
</div>
</div><p>Explanation of the code:</p>
<ol>
<li><strong>matrix_multiply(A, B)</strong>: Multiplies two 2x2 matrices.</li>
<li><strong>matrix_power(matrix, n)</strong>: Efficiently calculates the power of a matrix to the nth power using exponentiation by squaring.</li>
<li><strong>fib(n)</strong>: Calculates the n-th Fibonacci number using matrix exponentiation by calling <code>matrix_power</code> and then returning the appropriate element of the resulting matrix.</li>
</ol>
<p>Since the exponent $n$ shrinks by half every time. This algorithm has a time complexity of O(log n), making it very efficient for large values of n, and it also handles large Fibonacci numbers by using modulo (10^9 + 7) to keep the numbers within the range of a 32-bit integer.</p>
<p>If you like recursive function better, here is the recursive version of the <code>matrix_power()</code> function.</p>
<div class="highlight myclass"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">9
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">matrix_power_recursive</span>(matrix, n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
        <span style="color:#66d9ef">return</span> matrix
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        half_power <span style="color:#f92672">=</span> matrix_power_recursive(matrix, n <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>)
        <span style="color:#66d9ef">return</span> matrix_multiply(half_power, half_power)
    <span style="color:#66d9ef">else</span>:
        half_power <span style="color:#f92672">=</span> matrix_power_recursive(matrix, n <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>)
        <span style="color:#66d9ef">return</span> matrix_multiply(matrix_multiply(half_power, half_power), matrix)
</code></pre></td></tr></table>
</div>
</div><h1 id="no-matrix-please">No Matrix, Please.</h1>
<p>If you hate matrix and don&rsquo;t want to see it for like at all. You can unpack the calculation in the following way.</p>
<p>The key relationship we&rsquo;ll use is based on the identities:</p>
<ol>
<li>$F_{2k} = F_k \cdot (2F_{k+1} − F_k)$</li>
<li>$F_{2k+1} = F_{k+1}^2 + F_k^2$</li>
</ol>
<p>where $F_k$ is the $k$-th Fibonacci number. One can prove this by induction. But you must not be satisfied with that. Check out <a href="https://math.stackexchange.com/questions/2248821/prove-f-n12f-n2-f-2n1">this thread</a> to see how to <strong>derive</strong> this relation. You will understand why I called this an unpack of the the matrix. (It uses the formula $M^{2n}=M^n\cdot M^n$.) The Wiki page for <a href="https://en.wikipedia.org/wiki/Fibonacci_sequence#Matrix_form">Fibonacci number</a> a discussion on the matrix forms. Donald Knuth also includes a section in of the chapter of his famous book series, <a href="https://www-cs-faculty.stanford.edu/~knuth/taocp.html">TAOCP</a>, in volume 1: Fundamental Algorithms.</p>
<p>These identities allow us to compute Fibonacci numbers at even and odd indices efficiently, enabling a divide-and-conquer approach similar to the matrix exponentiation method but without explicitly using matrices. <strong>But I think the matrix method is more elegant, and easier to generalize.</strong> You will see why I say so.</p>
<p>Here&rsquo;s the Python code implementing this approach:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">MOD <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span><span style="color:#f92672">**</span><span style="color:#ae81ff">9</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">7</span>

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fib_logn</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>
    <span style="color:#66d9ef">elif</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">1</span>
    
    <span style="color:#75715e"># Compute F(n/2) and F(n/2 + 1)</span>
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        a <span style="color:#f92672">=</span> fib_logn(n <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>)
        b <span style="color:#f92672">=</span> fib_logn(n <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>)
        <span style="color:#66d9ef">return</span> (a <span style="color:#f92672">*</span> ((<span style="color:#ae81ff">2</span> <span style="color:#f92672">*</span> b) <span style="color:#f92672">-</span> a)) <span style="color:#f92672">%</span> MOD  <span style="color:#75715e"># F(2k) = F(k) * (2F(k+1) − F(k))</span>
    <span style="color:#66d9ef">else</span>:
        a <span style="color:#f92672">=</span> fib_logn((n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>)
        b <span style="color:#f92672">=</span> fib_logn((n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>)
        <span style="color:#66d9ef">return</span> (a <span style="color:#f92672">*</span> a <span style="color:#f92672">+</span> b <span style="color:#f92672">*</span> b) <span style="color:#f92672">%</span> MOD  <span style="color:#75715e"># F(2k+1) = F(k+1)^2 + F(k)^2</span>

<span style="color:#75715e"># Test the function with a sample value</span>
print(fib_logn(<span style="color:#ae81ff">10</span>))
</code></pre></td></tr></table>
</div>
</div><p>Explanation:</p>
<ul>
<li>The function <code>fib_logn(n)</code> computes the n-th Fibonacci number using the properties of Fibonacci numbers.</li>
<li>If <code>n</code> is even, we compute $F_{\frac{n}{2}}$ and $F_{\frac{n}{2} + 1}$, then use the formula for $F_{2k}$.</li>
<li>If <code>n</code> is odd, we compute $F_{\frac{n-1}{2}}$ and $F_{\frac{n-1}{2} + 1}$, then use the formula for $F_{2k+1}$.</li>
</ul>
<p>The time complexity remains O(log n) due to the divide-and-conquer nature of the algorithm.</p>
<h1 id="performance">Performance</h1>
<p>We want to compare the three version of the implementation: recursive, iterative, and O(n)/linear version. One can find the full test code <a href="/CSC482/files/fibo/fibo_test.py">here</a>.
When the test case is n=1000 and we sample every hundred. We get the following result. Several observation:</p>
<ol>
<li>The linear algorithm leads until about $n=400$. Then its time consumption exceeds the other two algorithms.</li>
<li>There are some fluctuation between $n=800$ to $n=1000$ in the recursive algorithm. You won&rsquo;t believe it takes less time to do $n=900$ than $n=800$, right? What happen in the test is that, the jobs of calculating $n=800$ or $n=900$ do not take too much of time, and it might be comparable to the background operating system scheduling. It could be the time we have for $n=800$ is the actually calculation time plus the scheduling time. Actually, the testing result differs time to time. I attached another testing result showing the fluctuation happening somewhere else. The way to mitigate the phenomenon? Well, just use bigger number so that the actual jobs take more time to finish, so the scheduling time become negligible.</li>
</ol>
<img src="/CSC482/files/fibo/1000.png" alt="Upto 1000th Fibonacci Number" style="border: 2px solid  gray;">
<p>Picture below: Random fluctuations causes by scheduling.</p>
<img src="/CSC482/files/fibo/fluct.png" alt="Fluctuation" style="border: 2px solid  gray;">
<p>Use bigger number: n=10,000,000. The data show that for $n$ equals to ten million, the recursive version takes 0.107 ms, while the iterative version takes 0.0997 ms, but the $O(n)$ version takes 822 ms. So the $\log(n)$ algorithms are now <strong>8000 times more efficient</strong> than the $O(n)$ version!</p>
<img src="/CSC482/files/fibo/10m.png" alt="n=10,000,000" style="border: 2px solid  gray;">
<h1 id="generalization">Generalization</h1>
<p>Now we have some new fancy ways to computer Fibonacci numbers. We want to ask further questions.</p>
<ol>
<li>Can we compute the $n$-th Domino-Tromino Tiling number in $O(\log(n))$ time? As we remember the <a href="https://xianghuang.me/course/csc482/domino-tromino/">recurrence</a> is $f(n)= 2*f(n-1) + f(n-3)$. What is the matrix you need to use for this recurrence?</li>
<li>For a general <a href="https://brilliant.org/wiki/linear-recurrence-relations/">Linear Recurrence Relations</a>, how do we compute the $n$-th number in $\log(n)$? What is the form of the matrix?</li>
</ol>
<p>The answer is not so terrible to figure out. To help you see that. I attached the solution for the Domino-Tromino Tiling problem <a href="/CSC482/files/fibo/tiling.py">here</a>. I was so exciting after I asked ChatGPT wrote this up for me. (No, I did not write the code I attached.) I thought I was going to beat everyone on Leetcode. The result? Well, it only ranks me at 93.06% in time complexity! Surely I know my program will take more memory, but time?</p>
<img src="/CSC482/files/fibo/Leetcode.png" alt="Leetcode" style="border: 2px solid  gray;">
<p>And what is the fastest algorithm on Leetcode then? Well, it is only the $O(n)$ algorithm. I attached in the above source code and ran a local test. Here is the result.</p>
<img src="/CSC482/files/fibo/tiling.png" alt="Leetcode" style="border: 2px solid  gray;">
<p>The result shows that when $n=1,000,000$, the $O(\log(n))$ algorithm takes 0.36 ms, while the $O(n)$ algorithm takes 193.8 ms. A more than 500 times different. While the Leetcode tests only tests the maximum number of $n=1000$. The number is not big enough to show the advantage of the $O(\log n)$ algorithm yet.</p>
<h1 id="other-methods-i-tried-but-failed">Other Methods I Tried but Failed</h1>
<p>I know there are closed-form formula to compute Fibonacci number directly.</p>
<p>\[ F(n) = \frac{\phi^n - (1 - \phi)^n}{\sqrt{5}} \]</p>
<p>where:</p>
<ul>
<li>$F(n)$is the nth Fibonacci number.</li>
<li>$\phi$ is the golden ratio, approximately equal to $1.61803398875$.</li>
<li>$n$is the position in the Fibonacci sequence.</li>
</ul>
<p>The generating function methodology that lead to this kind of formula is a topic that I like to talk about.</p>
<p>However, though attempting, we cannot use the above method to get a fast computation of Fibonacci number. The reasons:</p>
<ol>
<li>Floating number has errors. When $n$ becomes very large, the result you get is not correct any more.</li>
<li>How to compute a floating number to a large exponent fast? Well, I believe one can still use the successive squaring method. But the precision of of the floating number itself determines how far you can go.</li>
</ol>
<p>I guess if we restrict to a finite modular, like $10^9+7$, we can pick a precision for $\phi$. So that our calculation always return correct result when we round it to the nearby integer.</p>
<p>One thing I try for the domino-tromino tiling number is I found its solutions to the characterization function of the recurrence through <a href="https://www.wolframalpha.com/input?i=f%28n%29%3D%3D2+*+f%28n%E2%88%921%29%2Bf%28n%E2%88%923%29%2C+f%281%29%3D%3D1%2C+f%282%29%3D%3D2%2C+f%283%29%3D%3D5">Wolfram Alpha</a>. And the $n$-th tiling number $f(n)$ can be written as</p>
<p>\[
f(n) = \left(\frac{1}{3} - \frac{1}{354} (1 + i \sqrt{3}) \left(\frac{3481}{2} - \frac{177 \sqrt{177}}{2}\right)^{\frac{1}{3}} - \frac{(1 - i \sqrt{3}) \left(\frac{1}{2} (59 + 3 \sqrt{177})\right)^{\frac{1}{3}}}{6 \cdot 59^{\frac{2}{3}}}\right) \left(\frac{2}{3} - \frac{1}{6} (1 - i \sqrt{3}) \left(\frac{43}{2} - \frac{3 \sqrt{177}}{2}\right)^{\frac{1}{3}} - \frac{1}{6} (1 + i \sqrt{3}) \left(\frac{1}{2} (43 + 3 \sqrt{177})\right)^{\frac{1}{3}}\right)^n
\]</p>
<p>\[+ \left(\frac{1}{3} - \frac{1}{354} (1 - i \sqrt{3}) \left(\frac{3481}{2} - \frac{177 \sqrt{177}}{2}\right)^{\frac{1}{3}} - \frac{(1 + i \sqrt{3}) \left(\frac{1}{2} (59 + 3 \sqrt{177})\right)^{\frac{1}{3}}}{6 \cdot 59^{\frac{2}{3}}}\right) \left(\frac{2}{3} - \frac{1}{6} (1 + i \sqrt{3}) \left(\frac{43}{2} - \frac{3 \sqrt{177}}{2}\right)^{\frac{1}{3}} - \frac{1}{6} (1 - i \sqrt{3}) \left(\frac{1}{2} (43 + 3 \sqrt{177})\right)^{\frac{1}{3}}\right)^n
\]</p>
<p>\[+ \frac{1}{59} \left(59 + \left(\frac{3481}{2} - \frac{177 \sqrt{177}}{2}\right)^{\frac{1}{3}} + \left(\frac{59}{2} (59 + 3 \sqrt{177})\right)^{\frac{1}{3}}\right) 3^{-n - 1} \left(2 + \left(\frac{43}{2} - \frac{3 \sqrt{177}}{2}\right)^{\frac{1}{3}} + \left(\frac{1}{2} (43 + 3 \sqrt{177})\right)^{\frac{1}{3}}\right)^n
\]</p>
<p>Quite a monster with a mixture of algebraic numbers and complex numbers. I asked ChatGPT to generate the formula for me, too. But ChatGPT got it wrong. It is not so good at Math!</p>
<p>I asked ChatGPT to code the above formula into Python (Yes, it takes LaTex input pretty well). Here is the <a href="/CSC482/files/fibo/tiling_direct_complex.py">source code</a>. The program fails at $n=50$: it outputs 451995436 while the expected is 451995198.</p>
<h1 id="final-remarks">Final Remarks</h1>
<ol>
<li>It is quite a learning experience for me to putting this up.</li>
<li>Teaching forces me to reflect. After so many semesters talking about the naive primary test not being polynomial, I finally realized that I did not treat the calculation of Fibonacci number in the same caliber.</li>
<li>ChatGPT does a fantastic job. Not a single line of the above code is written by me; The codes are all by ChatGPT. But it takes some extra effort to make sure it does things correctly. See the <a href="https://chat.openai.com/share/7661c246-3825-474f-98a5-5e269380e996">conversation</a> I had with ChatGPT. (Please ignore that part where I asked it to help my English writing.) Of course, I read quite some other things before I talked to ChatGPT: I knew all the algorithms already from other materials and I knew all the math I need. The more you know, the more helpful ChatGPT is.</li>
<li>The future best programming language are Math and English.</li>
</ol>
<hr>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>List of Recursive Functions/Problems</title>
      <link>https://xianghuang.me/course/recursive_prob_list/</link>
      <pubDate>Wed, 24 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/recursive_prob_list/</guid>
      <description>
        <![CDATA[
        <p>One of students asked me to give him more problems to work on to learn recursion. I don&rsquo;t know why I could not think of any off top of my head. Maybe because I was tired after a long lecture! Here are some problems as requested. Ranked increasingly by their difficulty.</p>
<ol>
<li><a href="https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm">Euclidean algorithm and Extended Euclidean algorithm</a>. One might say its faster to just do loops. But it is indeed a good problem on recursion anyway.</li>
<li><a href="https://en.wikipedia.org/wiki/Exponentiation_by_squaring">Exponentiation by squaring</a> (The Successive Squaring Algorithm) for modular arithmetic.</li>
<li>Catalan number Recurrence. $C_0=0$ and $C_{n+1}=\displaystyle\sum_{i=0}^{n}C_i C_{n-i}$ for $n\geq 0$. And many other recurrence about Catalan number.</li>
<li><a href="https://en.wikipedia.org/wiki/Derangement">Derangement</a>. My personal favorite recursion and counting problem. $D(n)=(n-1)\cdot(D(n-1)+ D(n-2))$.</li>
<li><a href="http://www.cut-the-knot.org/recurrence/BiColorHanoi.shtml">Variation of Hanoi Tower Problems</a>. Bi-color[<a href="https://rmm.ludus-opuscula.org/PDF_Files/Chaugule_BicolorHanoi_37_48(4_2015)_low.pdf">pdf</a>], 3-color, and more.</li>
<li><a href="https://en.wikipedia.org/wiki/Golomb_sequence">Colin Mallows&rsquo;s Recurrence on Golomb sequence</a>. $a(1) = 1$; $a(n+1) = 1 + a(n + 1 - a(a(n)))$. I had had a lot of fun deriving this recurrence. It lied somewhere in my old notes. I should share it some day. I don&rsquo;t have the trick to do the asymptotic analysis as Colin Mallows did. He associated that with golden ratio. This will be a very interesting topic to read more about.</li>
</ol>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Leetcode 790: Mutual Recursion in A Tiling Problem</title>
      <link>https://xianghuang.me/course/csc482/domino-tromino/</link>
      <pubDate>Sat, 20 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc482/domino-tromino/</guid>
      <description>
        <![CDATA[
        <div class="toc">
<nav id="TableOfContents">
  <ul>
    <li><a href="#tiling-a-2-times-n-board-with-dominoes-and-trominoes">Tiling a $2\times n$ Board with Dominoes and Trominoes</a></li>
    <li><a href="#mutual-recursion">Mutual Recursion</a></li>
    <li><a href="#recurrence-relations">Recurrence Relations</a></li>
    <li><a href="#for-f-n">For $f(n)$:</a></li>
    <li><a href="#for-g-n-1">For $g(n-1)$:</a></li>
    <li><a href="#eliminate-the-g-function">Eliminate the $g()$ function:</a></li>
    <li><a href="#python-implementation">Python Implementation</a></li>
    <li><a href="#conclusion-remarks">Conclusion Remarks</a></li>
  </ul>
</nav>
</div>



<h1 id="tiling-a-2-times-n-board-with-dominoes-and-trominoes">Tiling a $2\times n$ Board with Dominoes and Trominoes</h1>
<p>I assigned <a href="https://leetcode.com/problems/domino-and-tromino-tiling/description/">Leetcode 790</a> as a Lab to my students. In this problem, we are tasked with finding the number of ways to tile a $2\times n$ board using dominoes and trominoes. Many online resources do not explain the deduction of the recurrence very well. So I decide to write one here.</p>
<h1 id="mutual-recursion">Mutual Recursion</h1>
<p>It will be convenient to introduce another problem $g(x)$ defined as below to help us attack the problem.</p>
<p>We define two functions to represent the number of tiling configurations:</p>
<ul>
<li>$f(n)$: Number of ways to tile a $2\times n$ board.</li>
<li>$g(n)$: Number of ways to tile a $2\times n$ board with one of the grids in the first column missing.</li>
</ul>
<p>The phenomenon of two functions recursively call each other is called mutual recursion. In a way, the two functions help implementing each other. We will see that in a minute.</p>
<h1 id="recurrence-relations">Recurrence Relations</h1>
<p>The recurrence relations for $f(n)$ and $g(n)$ are derived based on the ways to cover the first column of the board:</p>
<h1 id="for-f-n">For $f(n)$:</h1>
<ol>
<li>Cover the first column with a vertically placed domino. This leaves a $2 \times(n - 1)$ board.</li>
<li>Cover the first column with two horizontally placed dominoes. This leaves a $2\times(n - 2)$ board.</li>
<li>Cover the first column with a tromino in two possible orientations, each leaving a configuration that fits $g(n - 1)$.</li>
</ol>
<p>This gives us the relation:</p>
<p>$$
f(n) = f(n - 1) + f(n - 2) + 2g(n - 1).
$$</p>
<p>Or one can see the following picture for a better visualization.</p>
<img src = "/CSC482/pic/domino-tromino/f(n).png" alt = "your-image-description" style = "border: 2px solid  gray;" >
<h1 id="for-g-n-1">For $g(n-1)$:</h1>
<ol>
<li>Place a domino to cover the remaining grid in the first column of a $2 \times(n - 1)$ board with one grid missing. This leaves a configuration that fits $g(n - 2)$.</li>
<li>Place a tromino to cover the remaining grid in the first column. This leaves a standard $2 \times(n - 3)$ board.</li>
</ol>
<p>This gives us the relation:</p>
<p>$$
g(n - 1) = g(n - 2) + f(n - 3).
$$</p>
<p>One can consult the following picture for better understanding.</p>
<img src = "/CSC482/pic/domino-tromino/g(n).png" alt = "your-image-description" style = "border: 2px solid  gray;" >
<h1 id="eliminate-the-g-function">Eliminate the $g()$ function:</h1>
<p>From the expression for $f(n)$, we can express $g(n - 1)$ in terms of $f(n).$
$$ g(n - 1) = \frac{f(n) - f(n - 1) - f(n - 2)}{2} $$
and similarly for $g(n - 2)$.</p>
<p>Substituting these into the recurrence for $g(n - 1)$, we get:
$$ \frac{f(n) - f(n - 1) - f(n - 2)}{2} =\frac{f(n - 1) - f(n - 2) - f(n - 3)}{2} + f(n - 3). $$</p>
<p>Rearranging and solving for $f(n)$, we finally get:
\[f(n) = 2f(n - 1) + f(n - 3). \]</p>
<h1 id="python-implementation">Python Implementation</h1>
<p><strong>Dynamic Programming with Memoization:</strong></p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">MOD <span style="color:#f92672">=</span> <span style="color:#ae81ff">10</span><span style="color:#f92672">**</span><span style="color:#ae81ff">9</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">7</span>

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">f_dp</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">or</span> n<span style="color:#f92672">==</span> <span style="color:#ae81ff">2</span>:
        <span style="color:#66d9ef">return</span> n
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">3</span>:
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">5</span>
    f <span style="color:#f92672">=</span> [<span style="color:#ae81ff">0</span>] <span style="color:#f92672">*</span> (n <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>)
    f[<span style="color:#ae81ff">0</span>], f[<span style="color:#ae81ff">1</span>], f[<span style="color:#ae81ff">2</span>], f[<span style="color:#ae81ff">3</span>] <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">5</span>
    <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">4</span>, n <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>):
        f[i] <span style="color:#f92672">=</span> (<span style="color:#ae81ff">2</span> <span style="color:#f92672">*</span> f[i <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>] <span style="color:#f92672">+</span> f[i <span style="color:#f92672">-</span> <span style="color:#ae81ff">3</span>]) <span style="color:#f92672">%</span> MOD
    <span style="color:#66d9ef">return</span> f[n]

<span style="color:#75715e"># Example usage:</span>
n <span style="color:#f92672">=</span> <span style="color:#ae81ff">5</span>
print(f_dp(n))
</code></pre></td></tr></table>
</div>
</div><h1 id="conclusion-remarks">Conclusion Remarks</h1>
<p>Don&rsquo;t overthink the notion of mutual recursion. It is just you find a helper to help you implement your recursive function. Or it is just a name you give to some special intermediate calculation.</p>
<p>I generate some of the math in markdown by ChatGPT. I would hope it can help me draw the pictures but it did not do so good a job in writing Tikz. I ended up using <a href="https://www.mathcha.io/">Mathcha</a> to draw the picture I need. It is a very good online what-you-see-is-what-you-get solution for LaTex/Tikz. I highly recommend it when it comes to draw math pictures.</p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Understanding Bayes&#39;s Rule Through a Concrete Example</title>
      <link>https://xianghuang.me/course/csc302/prob/bayes/</link>
      <pubDate>Wed, 17 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc302/prob/bayes/</guid>
      <description>
        <![CDATA[
        <div class="toc">
<nav id="TableOfContents">
  <ul>
    <li><a href="#understanding-bayes-s-rule-through-a-concrete-example">Understanding Bayes&rsquo;s Rule Through a Concrete Example</a></li>
    <li><a href="#formal-statement-of-bayes-s-rule">Formal Statement of Bayes&rsquo;s Rule</a></li>
    <li><a href="#illustrative-example-the-dice-urn">Illustrative Example: The Dice Urn</a></li>
    <li><a href="#prior-distribution">Prior Distribution</a></li>
    <li><a href="#likelihood-function">Likelihood Function</a></li>
    <li><a href="#posterior-distribution">Posterior Distribution</a>
      <ul>
        <li><a href="#experiments-and-visualization">Experiments and Visualization</a>
          <ul>
            <li><a href="#experiment-1-uniform-prior">Experiment 1: Uniform Prior</a></li>
            <li><a href="#experiment-2-weighted-prior">Experiment 2: Weighted Prior</a></li>
          </ul>
        </li>
      </ul>
    </li>
    <li><a href="#conclusion">Conclusion</a></li>
  </ul>
</nav>
</div>



<h1 id="understanding-bayes-s-rule-through-a-concrete-example">Understanding Bayes&rsquo;s Rule Through a Concrete Example</h1>
<p>Bayes&rsquo;s rule is a fundamental concept in probability theory, offering a robust framework for understanding conditional probabilities. This article delves into Bayes&rsquo;s rule, illustrating its principles through a practical example and visualizations. The example is taken from Example 1.10.1 (Page 59 - 62) of the book  <em>An Introduction to Kolmogorov Complexity and Its Application</em>, Fourth Edition, authored by Ming Li and Paul Vitányi.</p>
<h1 id="formal-statement-of-bayes-s-rule">Formal Statement of Bayes&rsquo;s Rule</h1>
<p>Bayes&rsquo;s rule can be formally stated as follows:</p>
<p>$$ P(A | B) = \frac{P(B | A)P(A)}{P(B)} $$</p>
<p>where:</p>
<ul>
<li>$P(A | B)$ is the posterior probability of event $A$ given event $B$.</li>
<li>$P(B | A)$ is the likelihood of event $B$ given event $A$.</li>
<li>$P(A)$ is the prior probability of event $A$.</li>
<li>$P(B)$ is the marginal probability of event $B$.</li>
</ul>
<h1 id="illustrative-example-the-dice-urn">Illustrative Example: The Dice Urn</h1>
<p>Consider an urn filled with dice, each having a unique probability $p$ of showing the number 6. The probability $p$ may differ from the 1 / 6 expected from a fair die. If we draw a die from the urn and roll it $n$ times, observing the number 6 $m$ times, we can use Bayes&rsquo;s rule to understand the probabilities involved.</p>
<h1 id="prior-distribution">Prior Distribution</h1>
<p>Let $P(X=p)$ represent the prior probability of drawing a die with probability $p$ of showing a 6. According to von Mises&rsquo;s interpretation, the relative frequency of drawing a die with a specific $p$ converges to $P(X=p)$ over many draws.</p>
<h1 id="likelihood-function">Likelihood Function</h1>
<p>The likelihood of observing $m$ outcomes of 6 in $n$ throws for a die with probability $p$ is given by the binomial distribution:</p>
<p>$$ P(Y=m | n, p) = \binom{n}{m} p ^ m(1 - p) ^ {n - m} $$</p>
<p>This represents the number of ways to choose $m$ successful outcomes from $n$ trials, multiplied by the likelihood of those successes and failures.</p>
<h1 id="posterior-distribution">Posterior Distribution</h1>
<p>Therefore, the probability of drawing a die with probability $p$ and subsequently observing $m$ outcomes of 6 in $n$ throws is the product $P(X=p)P(Y=m | n, p)$.</p>
<p>In this context, Bayes&rsquo;s problem involves determining the probability of observing $m$ outcomes of 6 in $n$ throws due to a die with a specific probability $p$. The solution is given by the posterior or inferred probability distribution:</p>
<p>$$ P(X=p | n, m) = \frac{P(X=p)P(Y=m | n, p)}{\sum_{p} P(X=p)P(Y=m | n, p)} $$</p>
<p>Here, the denominator is the sum over all possible values of $p$, ensuring the probabilities sum to 1.</p>
<h2 id="experiments-and-visualization">Experiments and Visualization</h2>
<p>To understand these concepts better, let&rsquo;s conduct a series of experiments and visualize the results.</p>
<h3 id="experiment-1-uniform-prior">Experiment 1: Uniform Prior</h3>
<p>Let $p$ take values 0.1, 0.2, &hellip;, 0.9, each with equal probability $P(X=p) = 1 / 9$. We consider two cases: $n = 5, m = 3$ and $n = 500, m = 300$.</p>
<h4 id="case-1-n-5-m-3">Case 1: $n=5, m=3$</h4>
<h4 id="case-2-n-500-m-300">Case 2: $n=500, m=300$</h4>
<h3 id="experiment-2-weighted-prior">Experiment 2: Weighted Prior</h3>
<p>Let the new prior distribution be $P(X=p) = i / 45, i = 1, &hellip;, 9$. We analyze the inferred probabilities for the same two cases.</p>
<h4 id="case-1-n-5-m-3-1">Case 1: $n=5, m=3$</h4>
<h4 id="case-2-n-500-m-300-1">Case 2: $n=500, m=300$</h4>
<p><img src="/csc302/pic/bayes_experiments_accurate_labeled.png" alt="Experiment 1: Uniform Prior (n=5, m=3)"></p>
<p>These experiments demonstrate that as the number of trials increases, the limiting value of the observed relative frequency of success approaches the true probability of success, regardless of the initial prior distribution. Bayes&rsquo;s rule proves to be a powerful tool for making inferences based on a large number of observations. However, for small sequences of observations, knowledge of the initial probability is crucial for making justified inferences.</p>
<p>The codes for the experiments are generated by ChatGPT.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">50
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">51
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">52
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">53
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">54
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">55
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">56
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">57
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">58
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">59
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">60
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">61
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">62
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">63
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">64
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">65
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">66
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">67
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">68
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">69
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">70
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-Python" data-lang="Python">
<span style="color:#f92672">import</span> numpy <span style="color:#66d9ef">as</span> np
<span style="color:#f92672">import</span> matplotlib.pyplot <span style="color:#66d9ef">as</span> plt
<span style="color:#f92672">from</span> scipy.special <span style="color:#f92672">import</span> comb

<span style="color:#75715e"># Define the binomial likelihood function</span>


<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">binomial_likelihood</span>(p, n, m):
    <span style="color:#66d9ef">return</span> comb(n, m) <span style="color:#f92672">*</span> (p<span style="color:#f92672">**</span>m) <span style="color:#f92672">*</span> ((<span style="color:#ae81ff">1</span> <span style="color:#f92672">-</span> p)<span style="color:#f92672">**</span>(n <span style="color:#f92672">-</span> m))

<span style="color:#75715e"># Calculate the posterior distribution</span>


<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">posterior</span>(p_values, prior, n, m):
    likelihoods <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>array([binomial_likelihood(p, n, m) <span style="color:#66d9ef">for</span> p <span style="color:#f92672">in</span> p_values])
    unnormalized_posterior <span style="color:#f92672">=</span> prior <span style="color:#f92672">*</span> likelihoods
    posterior <span style="color:#f92672">=</span> unnormalized_posterior <span style="color:#f92672">/</span> np<span style="color:#f92672">.</span>sum(unnormalized_posterior)
    <span style="color:#66d9ef">return</span> posterior


<span style="color:#75715e"># Define p values and prior distributions</span>
p_values <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>arange(<span style="color:#ae81ff">0.1</span>, <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">0.1</span>)
uniform_prior <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>array([<span style="color:#ae81ff">1</span> <span style="color:#f92672">/</span> <span style="color:#ae81ff">9</span>] <span style="color:#f92672">*</span> <span style="color:#ae81ff">9</span>)
weighted_prior <span style="color:#f92672">=</span> np<span style="color:#f92672">.</span>array([i <span style="color:#f92672">/</span> <span style="color:#ae81ff">45</span> <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">10</span>)])

<span style="color:#75715e"># Experiment 1: Uniform prior</span>
posterior_uniform_5_3 <span style="color:#f92672">=</span> posterior(p_values, uniform_prior, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">3</span>)
posterior_uniform_500_300 <span style="color:#f92672">=</span> posterior(p_values, uniform_prior, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">300</span>)

<span style="color:#75715e"># Experiment 2: Weighted prior</span>
posterior_weighted_5_3 <span style="color:#f92672">=</span> posterior(p_values, weighted_prior, <span style="color:#ae81ff">5</span>, <span style="color:#ae81ff">3</span>)
posterior_weighted_500_300 <span style="color:#f92672">=</span> posterior(p_values, weighted_prior, <span style="color:#ae81ff">500</span>, <span style="color:#ae81ff">300</span>)


<span style="color:#75715e"># Function to plot with more accurate numbers on top of the bars and save the image</span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">plot_with_accurate_labels_and_save</span>(p_values, posteriors, titles, xlabel, ylabel, filename, figsize<span style="color:#f92672">=</span>(<span style="color:#ae81ff">18</span>, <span style="color:#ae81ff">14</span>)):
    plt<span style="color:#f92672">.</span>figure(figsize<span style="color:#f92672">=</span>figsize)

    <span style="color:#66d9ef">for</span> i, (posterior, title) <span style="color:#f92672">in</span> enumerate(zip(posteriors, titles), <span style="color:#ae81ff">1</span>):
        plt<span style="color:#f92672">.</span>subplot(<span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">2</span>, i)
        bars <span style="color:#f92672">=</span> plt<span style="color:#f92672">.</span>bar(p_values, posterior, width<span style="color:#f92672">=</span><span style="color:#ae81ff">0.08</span>)
        plt<span style="color:#f92672">.</span>title(title)
        plt<span style="color:#f92672">.</span>xlabel(xlabel)
        plt<span style="color:#f92672">.</span>ylabel(ylabel)
        <span style="color:#75715e"># Adjust y-limit to max value + 0.1 for better visualization</span>
        plt<span style="color:#f92672">.</span>ylim(<span style="color:#ae81ff">0</span>, max(posterior) <span style="color:#f92672">+</span> <span style="color:#ae81ff">0.1</span>)
        <span style="color:#66d9ef">for</span> bar, value <span style="color:#f92672">in</span> zip(bars, posterior):
            <span style="color:#75715e"># More accurate label with 6 decimal places</span>
            label <span style="color:#f92672">=</span> <span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{</span>value<span style="color:#e6db74">:</span><span style="color:#e6db74">.6f</span><span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#66d9ef">if</span> value <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0.0001</span> <span style="color:#66d9ef">else</span> <span style="color:#e6db74">&#34;&lt; 0.0001&#34;</span>
            plt<span style="color:#f92672">.</span>text(bar<span style="color:#f92672">.</span>get_x() <span style="color:#f92672">+</span> bar<span style="color:#f92672">.</span>get_width() <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>, bar<span style="color:#f92672">.</span>get_height(), label,
                     ha<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;center&#39;</span>, va<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;bottom&#39;</span>, fontsize<span style="color:#f92672">=</span><span style="color:#ae81ff">8</span>)

    plt<span style="color:#f92672">.</span>tight_layout()
    plt<span style="color:#f92672">.</span>savefig(<span style="color:#e6db74">f</span><span style="color:#e6db74">&#34;/mnt/data/</span><span style="color:#e6db74">{</span>filename<span style="color:#e6db74">}</span><span style="color:#e6db74">.png&#34;</span>)
    plt<span style="color:#f92672">.</span>show()


<span style="color:#75715e"># Call the function with all four experiments</span>
plot_with_accurate_labels_and_save(
    p_values,
    [posterior_uniform_5_3, posterior_uniform_500_300,
        posterior_weighted_5_3, posterior_weighted_500_300],
    titles,
    <span style="color:#e6db74">&#39;p&#39;</span>,
    <span style="color:#e6db74">&#39;P(X=p | n, m)&#39;</span>,
    <span style="color:#e6db74">&#39;bayes_experiments_accurate_labeled&#39;</span>,
    figsize<span style="color:#f92672">=</span>(<span style="color:#ae81ff">18</span>, <span style="color:#ae81ff">14</span>)
)

</code></pre></td></tr></table>
</div>
</div><h1 id="conclusion">Conclusion</h1>
<p>This approach quantifies the intuition that when the number of trials $n$ is small, the inferred distribution $P(X=p | n, m)$ heavily depends on the prior distribution $P(X=p)$. However, as $n$ increases, the inferred probability $P(X=p | n, m)$ increasingly concentrates around the empirical frequency $m / n = p$, regardless of the prior.</p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>CSC 302: Midterm Oral Presentation</title>
      <link>https://xianghuang.me/course/csc302/presentation/</link>
      <pubDate>Tue, 16 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc302/presentation/</guid>
      <description>
        <![CDATA[
        <h1 id="purpose">Purpose</h1>
<ul>
<li>Show your understanding of a topic related to the course.</li>
<li>Presentation skills.</li>
</ul>
<h1 id="format">Format</h1>
<ul>
<li>A talk of length 10-15 minutes.</li>
<li>Slides. (Required for everyone. You need to submit those slides. )</li>
<li>You can use the whiteboard during your talk.</li>
</ul>
<h1 id="structure">Structure</h1>
<ol>
<li>Introduce the topic. Given the basic definition. Or state the problem you try to solve. (Be friendly to you audience.) You can lightly use some Youtube video to help. But please note that it is your talk, you don&rsquo;t want to use the video for too long.</li>
<li>Solve the problem, typically you present a proof or some calculation (typically for counting and probablity problems). Or if you are introducing some mathematical software, demo what kind of problem it can solve and how to solve it.</li>
<li>Summerize the skills that you used form this course.</li>
<li>Q and A.</li>
</ol>
<h1 id="topics">Topics.</h1>
<p>I don&rsquo;t sugguest topics. You need to pick you own topics. However, the following topics are examples to help you understand what is expected. Once you have selected a topic, you need to send me an email to seek my approval on the topic.</p>
<p><em>Topics needs to be related to contents in Week 1 through Week 6</em>, i.e., Logic, Set Theory, Functions, Proofs, and Theory of Computation.</p>
<p><strong>Set Theory and Mathematical Logic:</strong></p>
<ol>
<li>More application of Cantor&rsquo;s Diagonalization trick in proof.</li>
<li>Cantor-Schroeder-Bernstein theorem.</li>
<li><a href="https://lean-lang.org/">Lean</a> theorem prover.</li>
<li>SAT solver <a href="https://www.borealisai.com/research-blogs/tutorial-9-sat-solvers-i-introduction-and-applications/">tutorial</a>.</li>
<li>How to test a well formed formula of propositional logic?</li>
</ol>
<p><strong>Functions</strong></p>
<ol>
<li>The Cantor-Schroeder-Bernstein theorem.</li>
</ol>
<p><strong>Theory of Computation</strong></p>
<ol>
<li>Finite State Machine and Regular Expression.</li>
<li>Stack Machine.</li>
<li>Product of two finite state machine</li>
<li>Pigeonhole Principle and Pumping Lemma
The above list is not intended to be complete. Again, I expect that you will do you own research to pick your own topic.</li>
</ol>
<h2 id="topics-from-previous-semesters">Topics from previous semesters</h2>
<ul>
<li><a href="https://docs.google.com/spreadsheets/d/1JZ3cvqz-4t5NA23tpp0AHdyYEVXnww7jBlRTO6S8cKw/edit?pli=1#gid=0">Fall 2023</a>. For some reason the class likes gambling games and probability a lot.</li>
</ul>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>CSC 302:Final Oral Presentation</title>
      <link>https://xianghuang.me/course/csc302/final_oral/</link>
      <pubDate>Tue, 21 Nov 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/csc302/final_oral/</guid>
      <description>
        <![CDATA[
        <h1 id="purpose">Purpose</h1>
<ul>
<li>Show your understanding of a topic related to the course.</li>
<li>Presentation skills.</li>
</ul>
<h1 id="format">Format</h1>
<ul>
<li>A talk of length 10-15 minutes.</li>
<li>Slides. (Required for everyone. You need to submit those slides. )</li>
<li>You can use the whiteboard during your talk.</li>
</ul>
<h1 id="structure">Structure</h1>
<ol>
<li>Introduce the topic. Given the basic definition. Or state the problem you try to solve. (Be friendly to you audience.) You can lightly use some Youtube video to help. But please note that it is your talk, you don&rsquo;t want to use the video for too long.</li>
<li>Solve the problem, typically you present a proof or some calculation (typically for counting and probablity problems). Or if you are introducing some mathematical software, demo what kind of problem it can solve and how to solve it.</li>
<li>Summerize the skills that you used form this course.</li>
<li>Q and A.</li>
</ol>
<h1 id="topics">Topics.</h1>
<p>I don&rsquo;t sugguest topics. You need to pick you own topics. However, the following topics are examples to help you understand what is expected. Once you have selected a topic, you need to send me an email to seek my approval on the topic.</p>
<p><strong>Set Theory and Mathematical Logic:</strong></p>
<ol>
<li>More application of Cantor&rsquo;s Diagonalization trick in proof.</li>
<li>Cantor-Schroeder-Bernstein theorem.</li>
<li><a href="https://lean-lang.org/">Lean</a> theorem prover.</li>
<li>SAT solver <a href="https://www.borealisai.com/research-blogs/tutorial-9-sat-solvers-i-introduction-and-applications/">tutorial</a>.</li>
</ol>
<p><strong>Recursive function, inductive proof, and counting</strong></p>
<ol>
<li>Problems that has beautiful recursive solutions that we haven&rsquo;t talked about yet in the class. For example,
<ul>
<li><a href="https://en.wikipedia.org/wiki/Derangement">Derangement</a></li>
<li><a href="https://leetcode.com/problems/domino-and-tromino-tiling/">Domino and Tromino Tiling</a></li>
</ul>
</li>
<li>Inductive proofs and possibly the recursive algorithms inspired by them.</li>
<li>Counting with recursion. For instance, <a href="https://discrete.openmathbooks.org/more/mdm/sec_basic-catalan.html">the Catalan Numbers</a>.</li>
<li>Generating functions of counting problems. See example in <a href="https://www2.math.upenn.edu/~wilf/gfology2.pdf"><em>Generatingfunctionology</em></a>.</li>
<li>Correctness of an algorithm by induction.</li>
<li>Recursive definitions and structural inductive proof. Example: propositional logic string parsing.</li>
</ol>
<p><strong>Graphs and trees.</strong></p>
<ol>
<li>Recursive algorithms on Graphs and trees.</li>
<li>Proofs on graphs and trees.</li>
</ol>
<p><strong>Probability.</strong></p>
<ol>
<li>Understand Bayes' Rule via simulation. Example 1.10.1 (Page 59-62), <em>An Introduction to Kolmogorov Complexity and Its Application</em>, Fourth Edition.
The above list is not intended to be complete. Again, I expect that you will do you own research to pick your own topic.</li>
</ol>
<h2 id="topics-from-previous-semesters">Topics from previous semesters</h2>
<ul>
<li><a href="https://docs.google.com/spreadsheets/d/1JZ3cvqz-4t5NA23tpp0AHdyYEVXnww7jBlRTO6S8cKw/edit?pli=1#gid=0">Fall 2023</a>. For some reason the class likes gambling games and probability a lot.</li>
</ul>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Pip Cutting Problem</title>
      <link>https://xianghuang.me/course/pcp/</link>
      <pubDate>Thu, 30 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/pcp/</guid>
      <description>
        <![CDATA[
        <h2 id="purpose">Purpose</h2>
<ul>
<li>Dynamic Programming</li>
</ul>
<h2 id="problem-statement">Problem Statement</h2>
<p>You can find the statement through <a href="https://judge.beecrowd.com/en/search?q=1798&amp;for=problems">Beebrowd 1798</a> (You might need to login and search with the problem number). Note that you need to submit you code and report on Canvas for grading. I won&rsquo;t maintain the class page for the problem. You can just use the public page to test your code.
<strong>No ChatGPT generated codes are allowed for this task.</strong> You can always play it for fun <strong>after</strong> submitting your work.</p>
<h2 id="some-ideas">Some Ideas</h2>
<p>A full solution down to the pseudo-code level will <strong>not</strong> be provided. You are taking an algorithm course, not a programming course. To some extend, pseudo-code itself <strong>is</strong> the solution already.</p>
<p>Some hints:</p>
<ul>
<li>It is a Knapsack Problem variant. Think about how to interpret the problem with Knapsack Problem&rsquo;s terminology.</li>
<li>But this time for each element, you can take it multiple times. It not either take it or leave it; you can &ldquo;take&rdquo; something and take it as many times as you can while complying the constraints. For example, in the sample input, you can take 10= 6+ 2+2, with value 3+1+1 =5, where you take element with length 2 for twice. (Note that the total length is ten, and 6+2+2 already use all the length, so you can not &ldquo;take&rdquo; anything anymore.) What do you have to change to the recurrence under this new condition?</li>
<li>Modify the code from your previous lab on Knapsack Problem to obtain a solution for this one.</li>
<li>Think about how to make your memoization more efficient. Can you just use 1-D array(s) instead of 2-D array?</li>
<li>Please find test cases through Beecrowd/UDebug. You can do text comparison if you don&rsquo;t like Beecrowd auto test.</li>
</ul>
<h2 id="submission">Submission</h2>
<h3 id="beecrowd">Beecrowd</h3>
<ol>
<li>Submit it to Beecrowd public page and take a screenshot. Or do output comparison yourself and should me you have the right answer.</li>
</ol>
<h3 id="canvas">Canvas</h3>
<ol>
<li>Beecrowd passing screenshot. If you can not pass the tests, tell me that you cannot pass it in the submission comment.</li>
<li>You source file. I assume it just take one file.</li>
<li>A report on the things you try and your understanding on the problem.
<ul>
<li>It should be something you can read and understand after one year. Write some short introduction to help achieving that goal.</li>
<li>What is new in your solution comparing to the lab.</li>
<li>What is your understanding about the more space-efficient 1-D array implementation.</li>
</ul>
</li>
</ol>
<p>Last Note: <strong>You are already allowed to use a lot of other resources from previous Lab. No ChatGPT allowed for this task.</strong></p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>CSC 482 Lab: Weighted Job Scheduling Problem</title>
      <link>https://xianghuang.me/course/wjs/</link>
      <pubDate>Wed, 29 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/wjs/</guid>
      <description>
        <![CDATA[
        <div class="toc">
<nav id="TableOfContents">
  <ul>
    <li><a href="#purpose">Purpose</a></li>
    <li><a href="#problem-statement">Problem Statement</a></li>
    <li><a href="#solution-of-the-problem">Solution of The Problem</a>
      <ul>
        <li><a href="#dynamic-programming-and-memoization">Dynamic Programming and Memoization</a></li>
        <li><a href="#how-to-compute-pred-i">How to Compute $pred(i)$</a>
          <ul>
            <li><a href="#naive-linear-search">Naive Linear Search</a></li>
            <li><a href="#binary-search">Binary Search</a></li>
            <li><a href="#an-o-n-algorithm-once-and-for-all">An $O(n)$ Algorithm Once and For All</a></li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>
</div>



<h1 id="purpose">Purpose</h1>
<ul>
<li>Dynamic Programming.</li>
<li>Application of Sorting in Algorithm Design.</li>
</ul>
<h1 id="problem-statement">Problem Statement</h1>
<p>Let&rsquo;s schedule some jobs again! We have had a lab on job scheduling problem before and this time we consider jobs with weights.</p>
<p>The Lab is excerpted from Section 12.3 of <a href="/images/wsj.pdf">Algorithm Design and Applications</a> by Michael T. Goodrich and Roberto Tamassia. We also talked about weighted job scheduling in Kleinberg and Tardos. I will not repeat most of the contents in the books. I will just emphasis what I believe are the important aspects of the problem.</p>
<ul>
<li><strong>Input:</strong> A list of jobs $L$. A job $i$ is specified by a triple: ($s_i$, $f_i$, $b_i$) meaning the starting time, finishing time, and the benefit of performing the job $i$.</li>
<li><strong>Output:</strong> A selected subset of the jobs, so that
<ul>
<li>No jobs in the subset are conflict with each other.</li>
<li>The sum of the benefits are maximized.</li>
</ul>
</li>
</ul>
<p>In the first book above, the problem is introduced via a vivid language and is called &ldquo;telescope scheduling problem&rdquo;. Below is an example taking out of the book.</p>
<p><img src="/images/wjs_example.png" alt="">
<em>Figure 1: The telescope scheduling problem. The left and right boundary of each rectangle represent the start and finish times for an observation request. The height of each rectangle represents its benefit. We list each request&rsquo;s benefit on the left and its predecessor on the right. The requests are listed by increasing finish times. The optimal solution has total benefit 17 = 5+ 5+ 2+ 5.</em></p>
<h1 id="solution-of-the-problem">Solution of The Problem</h1>
<h2 id="dynamic-programming-and-memoization">Dynamic Programming and Memoization</h2>
<p>As we discussed in the lecture, we need the following notion.</p>
<p>We first assume $L$ is ordered by nondecreasing <strong>finish times</strong>.</p>
<p>\[
B_i = \text{the maximum benefit that can be achieved with the first $i$ request in $L$.}
\]
So, as a boundary condition, we get $B_0=0$.</p>
<p>We also define the predecessor, $pred(i)$, for each job $i$, to be the largest index $j$, such that $j$&lt;$i$ and job $i$ and $j$ don&rsquo;t conflict.  If there is no such index, then define the predecessor of to be 0 (use -1 if index starting from 0).</p>
<p>The definition of the predecessor of each job lets us easily reason about the effect that including or not including a job, $i$, in a schedule that includes the first $i$ jobs in $L$. That is, in a schedule that achieves the optimal value, $B_i$, for $i&gt;1$, either it includes the job $i$ or it doesn&rsquo;t; hence, we can reason as follows:</p>
<ul>
<li>If the optimal schedule achieving the benefit $B_i$ includes job $i$, then $B_i= B_{pred(i)} + b_i$. If this were not the case, then we could get a better benefit by substituting the schedule achieving $B_{pred(i)}$ for the one we used from among those with indices at most $pred(i)$.</li>
<li>On the other hand, if the optimal schedule achieving the benefit does not include job $i$ , then $B_{i-1}$. If this were not the case, then we could get a better benefit by using the schedule that achieves $B_{i-1}$.</li>
</ul>
<p>Therefore, we can make the following recursive definition:</p>
<p>\[
B_i  = \max\{B_{i-1}, B_{pred(i)}+ b_i\}
\]</p>
<p>It is most efficient for us to use memoization when computing $B_i$. We use the arrays $B$ and $P$, and $B[i]$ and $P[i]$ for $B_i$ and $pred[i]$ respectively in the following code.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">B[<span style="color:#ae81ff">0</span>]<span style="color:#f92672">=</span><span style="color:#ae81ff">0</span>
<span style="color:#66d9ef">for</span> i<span style="color:#f92672">=</span><span style="color:#ae81ff">1</span>  to n <span style="color:#66d9ef">do</span><span style="color:#f92672">:</span>
    B[i]<span style="color:#f92672">=</span>max{B[i<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>], B[P[i]]<span style="color:#f92672">+</span> b_i}
</code></pre></td></tr></table>
</div>
</div><p>We can see this algorithm runs in $O(n)$, where $n$ is the length of $L$. The bottleneck of the algorithm lies in the sorting of $L$, which costs $O(n\log(n))$. However, we still haven&rsquo;t discuss how to compute $P[i]$ or $pred(i)$.</p>
<h2 id="how-to-compute-pred-i">How to Compute $pred(i)$</h2>
<h3 id="naive-linear-search">Naive Linear Search</h3>
<p>If you do a Google search, you will easily find solutions using naive way to solve the problem.</p>
<p>For example, <a href="https://www.geeksforgeeks.org/weighted-job-scheduling/">this one</a>&rsquo;s Python implementation</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># Find the latest job (in sorted array) that</span>
<span style="color:#75715e"># doesn&#39;t conflict with the job[i]. If there</span>
<span style="color:#75715e"># is no compatible job, then it returns -1</span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">latestNonConflict</span>(arr, i):

    <span style="color:#66d9ef">for</span> j <span style="color:#f92672">in</span> range(i <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>):
        <span style="color:#66d9ef">if</span> arr[j]<span style="color:#f92672">.</span>finish <span style="color:#f92672">&lt;=</span> arr[i <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>start:
            <span style="color:#66d9ef">return</span> j

    <span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>

</code></pre></td></tr></table>
</div>
</div><p>does a linear search for each job $i$, and you need to do it for every $i$. So the complexity of calculating $P[]$ in this way is $O(n^2)$.</p>
<h3 id="binary-search">Binary Search</h3>
<p>You can improve the above process by using binary search. See <a href="https://www.geeksforgeeks.org/weighted-job-scheduling-log-n-time/">this link</a> for the full solution. Basically, since the jobs already sorted by finish time, you just need to binary search for the first job so that its <strong>finish</strong> time is earlier than the target job&rsquo;s <strong>start</strong> time.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># A Binary Search based function to find the latest job</span>
<span style="color:#75715e"># (before current job) that doesn&#39;t conflict with current</span>
<span style="color:#75715e"># job.  &#34;index&#34; is index of the current job.  This function</span>
<span style="color:#75715e"># returns -1 if all jobs before index conflict with it.</span>
<span style="color:#75715e"># The array jobs[] is sorted in increasing order of finish</span>
<span style="color:#75715e"># time.</span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">binarySearch</span>(job, start_index):

    <span style="color:#75715e"># Initialize &#39;lo&#39; and &#39;hi&#39; for Binary Search</span>
    lo <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
    hi <span style="color:#f92672">=</span> start_index <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>

    <span style="color:#75715e"># Perform binary Search iteratively</span>
    <span style="color:#66d9ef">while</span> lo <span style="color:#f92672">&lt;=</span> hi:
        mid <span style="color:#f92672">=</span> (lo <span style="color:#f92672">+</span> hi) <span style="color:#f92672">//</span> <span style="color:#ae81ff">2</span>
        <span style="color:#66d9ef">if</span> job[mid]<span style="color:#f92672">.</span>finish <span style="color:#f92672">&lt;=</span> job[start_index]<span style="color:#f92672">.</span>start:
            <span style="color:#66d9ef">if</span> job[mid <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>]<span style="color:#f92672">.</span>finish <span style="color:#f92672">&lt;=</span> job[start_index]<span style="color:#f92672">.</span>start:
                lo <span style="color:#f92672">=</span> mid <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>
            <span style="color:#66d9ef">else</span>:
                <span style="color:#66d9ef">return</span> mid
        <span style="color:#66d9ef">else</span>:
            hi <span style="color:#f92672">=</span> mid <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
    <span style="color:#66d9ef">return</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>
</code></pre></td></tr></table>
</div>
</div><p>This method takes $O(\log(n))$ time to compute $pred(i)$ for each $i$. So in total it costs $O(n\log(n))$ time.</p>
<p>Some implementations use in Python use
<code> bisect</code> module for binary search.</p>
<h3 id="an-o-n-algorithm-once-and-for-all">An $O(n)$ Algorithm Once and For All</h3>
<p>The previous solutions compute $pred(i)$ for each $i$ separately. We now introduce a method to compute $pred(i)$ for all $i$ all at once.</p>
<p>In the <em>Algorithms and Their Applications</em>, a proposed way to do it</p>
<blockquote>
    In particular, given a listing of $L$ ordered by finish times and another listing, $L'$, ordered by start times, then a merging of these two lists, as in the <b>merge-sort</b> algorithm, gives us what we want.
</blockquote>
Then the author mentioned
<blockquote>
    The predecessor of request $i$ is literally the index of the predecessor in $L$ of the value, $s_i$, in $L'$. 
</blockquote> (But this sentence is very hard to understand.)
I processed it in this way:
<ol>
<li>We have job $i$&rsquo;s start time, $s_i$, in our hand.</li>
<li>Look at the merged list of $L$ and $L'$, find out $s_i$&rsquo;s predecessor (but it need to be a finish time $e$). (If its predecessor is a start time, keep looking until you find an end time).</li>
<li>Report the index, $j$, of the finish time. (Which job it is coming form.) That is, set <code>pred(i)=j</code>.</li>
</ol>
<p>In implementation, I modified the above process slightly.</p>
<ol>
<li>I don&rsquo;t really store the merged list to save space. But I do write out the merging process.</li>
<li>The two cursors in the merging algorithm will keep a record on the index of the end time naturally. So I don&rsquo;t need to &ldquo;keep looking until I find the end time&rdquo;.</li>
<li>But I need to maintain a map between the start time and its original index before sorting. Note that I originally indexed the jobs by the end time.</li>
</ol>
<p>Index the job by end time.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># zip the three lists</span>
jobs <span style="color:#f92672">=</span> sorted([(e, s, p) 
       <span style="color:#66d9ef">for</span> e, s, p 
       <span style="color:#f92672">in</span> zip(endTime, startTime, profit)])
</code></pre></td></tr></table>
</div>
</div><p>Bind the start time and the job index.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># map between the start time and its original job index.</span>
jobs_by_start <span style="color:#f92672">=</span> sorted([
         (s, index)
        <span style="color:#66d9ef">for</span> index, (e, s, p) 
        <span style="color:#f92672">in</span> enumerate(jobs)])

</code></pre></td></tr></table>
</div>
</div><p>The merging process. Computing pred() for all jobs once and for all.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e"># ends: &#34;jobs&#34; as in the above</span>
<span style="color:#75715e"># starts: &#34;jobs_by_start&#34; as in the above</span>
<span style="color:#75715e"># P: the pred() function, stored in a list. </span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">merge</span>(self, ends, starts, P):
        j <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># cursor for end time </span>
        i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#75715e"># cursor for start time</span>
        <span style="color:#66d9ef">while</span> j <span style="color:#f92672">&lt;</span> len(ends) <span style="color:#f92672">and</span> i <span style="color:#f92672">&lt;</span> len(starts):
            <span style="color:#66d9ef">if</span> ends[j][<span style="color:#ae81ff">0</span>] <span style="color:#f92672">&lt;=</span> starts[i][<span style="color:#ae81ff">0</span>]:
                j <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
            <span style="color:#66d9ef">else</span>:
                <span style="color:#75715e"># we might want to do i-1, if we want things starting from 0</span>
                P[starts[i][<span style="color:#ae81ff">1</span>]] <span style="color:#f92672">=</span> j <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
                i <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
</code></pre></td></tr></table>
</div>
</div><p>Note that the algorithm does not work theoretically better than the previous binary searching algorithm, since it require the input to be sorted.</p>
<div class="theorem mathjax" text='Linear Algorithm with Two Sorted Input List'> 
    Given a list, $L$, of $n$ observation requests, provided in two sorted orders, one by nondecreasing finish times and one by nondecreasing start times, we can solve the telescope scheduling problem for $L$ in $O(n)$ time.
</div> 
<p>The full implementation can be found <a href="/src/WJS/wjs.py">here</a>. I changed some variables' name for consistency with the current blog piece.</p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Almost Shortest Path via ChatGPT</title>
      <link>https://xianghuang.me/course/asp/</link>
      <pubDate>Sun, 26 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/asp/</guid>
      <description>
        <![CDATA[
        <p>I teach CSC 482: Algorithm and Computation every semester. In the past few semesters, I like to assign <a href="https://www.beecrowd.com.br/judge/en/problems/view/1391">Beecrowd 1391: Almost Shortest Path</a> as a two-part homework assignment. In the first part, I asked my students to implement a customized heap, with some addition feature such as lookup dictionary for data items. In the second part, they need to solve the Beecrowd problem. The overall framework to solve the problem is simple.</p>
<ul>
<li>Read in a graph.</li>
<li>Run Dijkstra&rsquo;s Algorithm to get a subgraph consist of all the shortest paths.</li>
<li>Remove the subgraph via BFS algorithm.</li>
<li>Dijkstra&rsquo;s Algorithm again.</li>
</ul>
<p>It is a neat problem that can touch many topics we cover in the course.</p>
<ul>
<li>Heap.</li>
<li>Dijkstra;s Algorithm. (And they need to hack it.)</li>
<li>BFS algorithm.</li>
</ul>
<p>In the beginning of this semester, I thought some of the concepts in the ASP problem is not so easy to understand by ChatGPT. So it will still take quite some efforts for a student to solve it, even with the help of ChatGPT, since after all, the first time I ran ChatGPT and asked it to implement Dijkstra&rsquo;s algorithm a few month ago, it did not even compile. But as we know, ChapGPT evolved quickly in the past few months. (And I have not even try GPT-4 yet.) Now it can easily generate all the useful pieces to solve my homework assignment.</p>
<p><strong>Today I will demonstrate how to solve the problem via ChatGPT.</strong></p>
<div class="toc">
<nav id="TableOfContents">
  <ul>
    <li><a href="#input-processing">Input Processing</a></li>
    <li><a href="#min-heap-implementation">Min Heap Implementation</a></li>
    <li><a href="#modified-dijkstra-s-algorithm">Modified Dijkstra&rsquo;s Algorithm</a></li>
    <li><a href="#bfs-backtrack-deletion">BFS Backtrack Deletion</a></li>
    <li><a href="#putting-everything-together">Putting Everything Together</a>
      <ul>
        <li><a href="#break-early-in-dijkstra-s-algorithm">Break Early In Dijkstra&rsquo;s Algorithm</a></li>
        <li><a href="#no-changekey-needed">No <code>changeKey</code> Needed</a></li>
        <li><a href="#bfs-deletion">BFS Deletion</a></li>
        <li><a href="#the-full-solution">The Full Solution</a></li>
      </ul>
    </li>
    <li><a href="#conclusion">Conclusion</a></li>
  </ul>
</nav>
</div>



<h1 id="input-processing">Input Processing</h1>
<p>Beecrowd, as many ICPC programming contest sites, feeds formatted input through standard input. Each semester I have students complain they spend too much time on processing the input. Generally speaking, input processing is easy, and ChapGPT can make it easier: You can just speak English and it understands you.</p>
<p>Below is my conversation with ChatGPT. My occasional grammar error does not affect its &ldquo;understanding&rdquo;.</p>
<p>Person:</p>
<ul>
<li>
<p>create python code to read the following format data into a graph:
First line: two numbers, the first number &ldquo;n&rdquo; represent the number of nodes of the graph, the second number &ldquo;m&rdquo;  represent  the number of edges .
Second line:  two numbers. Read the first one into a variable name &ldquo;start&rdquo;, the second &ldquo;dest&rdquo;
Follow by  m lines. Each line is tuple (a, b, w), which means an edge from a to b with weight w.</p>
</li>
<li>
<p>We have multiple such graph as input, until we run into a line &ldquo;0 0&rdquo;. Then the input ends.</p>
</li>
<li>
<p>Create a loop and read each session of the data into a graph</p>
</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s the code to read the input data and create a graph:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">read_graph</span>():
    n, m <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read n and m from first line</span>
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">and</span> m <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:  <span style="color:#75715e"># end of input</span>
        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">None</span>
    start, dest <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read start and dest from second line</span>
    graph <span style="color:#f92672">=</span> {i: {} <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(n)}  <span style="color:#75715e"># initialize graph with n nodes</span>
    <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(m):
        a, b, w <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read edge from input</span>
        graph[a][b] <span style="color:#f92672">=</span> w  <span style="color:#75715e"># add edge to graph</span>
    <span style="color:#66d9ef">return</span> start, dest, graph

<span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
    data <span style="color:#f92672">=</span> read_graph()
    <span style="color:#66d9ef">if</span> data <span style="color:#f92672">is</span> <span style="color:#66d9ef">None</span>:
        <span style="color:#66d9ef">break</span>
    start, dest, graph <span style="color:#f92672">=</span> data
    <span style="color:#75715e"># do something with start, dest, and graph</span>
</code></pre></td></tr></table>
</div>
</div><ul>
<li>
<p>The <code>read_graph</code> function reads the input data for a single graph session and returns a tuple of <code>start</code>, <code>dest</code>, and <code>graph</code>. If the first line of input is &ldquo;0 0&rdquo;, it returns <code>None</code> to indicate the end of input.</p>
</li>
<li>
<p>The <code>while</code> loop repeatedly calls <code>read_graph</code> until it returns <code>None</code>, indicating the end of input. For each graph session, it unpacks the tuple into <code>start</code>, <code>dest</code>, and <code>graph</code> variables, and you can do whatever you want with them inside the loop.</p>
</li>
</ul>
<p><em>I found that it did not use adjacency list but matrix. So I request it to do so.</em></p>
<p>Person:</p>
<ul>
<li>use adj list for the graph in the above code</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s the modified code that uses an adjacency list to represent the graph:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">read_graph</span>():
    n, m <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read n and m from first line</span>
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">and</span> m <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:  <span style="color:#75715e"># end of input</span>
        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">None</span>
    start, dest <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read start and dest from second line</span>
    graph <span style="color:#f92672">=</span> [[] <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(n)]  <span style="color:#75715e"># initialize graph with n nodes</span>
    <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(m):
        a, b, w <span style="color:#f92672">=</span> map(int, input()<span style="color:#f92672">.</span>split())  <span style="color:#75715e"># read edge from input</span>
        graph[a]<span style="color:#f92672">.</span>append((b, w))  <span style="color:#75715e"># add edge to graph</span>
    <span style="color:#66d9ef">return</span> start, dest, graph

<span style="color:#66d9ef">while</span> <span style="color:#66d9ef">True</span>:
    data <span style="color:#f92672">=</span> read_graph()
    <span style="color:#66d9ef">if</span> data <span style="color:#f92672">is</span> <span style="color:#66d9ef">None</span>:
        <span style="color:#66d9ef">break</span>
    start, dest, graph <span style="color:#f92672">=</span> data
    <span style="color:#75715e"># do something with start, dest, and graph</span>
</code></pre></td></tr></table>
</div>
</div><p>The <code>graph</code> variable is initialized as a list of <code>n</code> empty lists. Each element of the list represents a node in the graph, and the list contains tuples representing edges from that node. Each tuple contains two values: the destination node and the weight of the edge.</p>
<p>When reading an edge from the input, we append a tuple of <code>(b, w)</code> to the <code>graph[a]</code> list to represent an edge from node <code>a</code> to node <code>b</code> with weight <code>w</code>.</p>
<h1 id="min-heap-implementation">Min Heap Implementation</h1>
<p><em>I asked ChatGPT to implement a min heap with extra requirements. It understood my request about the swap function.</em></p>
<p>Person:</p>
<ul>
<li>implement a min heap in python; add a dict name &ldquo;position&rdquo; to map the data items to their indices; add a changePriority() function to allow a user change an item&rsquo;s priority; add a swap function, in side the swap function, maintenance the position mapping.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s an implementation of a min heap in Python that includes the <code>position</code> dictionary and a <code>changePriority()</code> function:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">40
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">41
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">42
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">43
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">44
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">45
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">46
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">47
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">48
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">49
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">50
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">51
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">52
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">53
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">54
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">55
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">56
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">57
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">58
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">59
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">60
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">61
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">62
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MinHeap</span>:
    <span style="color:#66d9ef">def</span> __init__(self):
        self<span style="color:#f92672">.</span>heap <span style="color:#f92672">=</span> []
        self<span style="color:#f92672">.</span>position <span style="color:#f92672">=</span> {}
        
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">parent</span>(self, i):
        <span style="color:#66d9ef">return</span> (i<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)<span style="color:#f92672">//</span><span style="color:#ae81ff">2</span>
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">left_child</span>(self, i):
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">*</span>i<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">right_child</span>(self, i):
        <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">*</span>i<span style="color:#f92672">+</span><span style="color:#ae81ff">2</span>
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">swap</span>(self, i, j):
        self<span style="color:#f92672">.</span>heap[i], self<span style="color:#f92672">.</span>heap[j] <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>heap[j], self<span style="color:#f92672">.</span>heap[i]
        self<span style="color:#f92672">.</span>position[self<span style="color:#f92672">.</span>heap[i][<span style="color:#ae81ff">1</span>]] <span style="color:#f92672">=</span> i
        self<span style="color:#f92672">.</span>position[self<span style="color:#f92672">.</span>heap[j][<span style="color:#ae81ff">1</span>]] <span style="color:#f92672">=</span> j
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">insert</span>(self, item):
        self<span style="color:#f92672">.</span>heap<span style="color:#f92672">.</span>append(item)
        n <span style="color:#f92672">=</span> len(self<span style="color:#f92672">.</span>heap)
        self<span style="color:#f92672">.</span>position[item[<span style="color:#ae81ff">1</span>]] <span style="color:#f92672">=</span> n<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>
        self<span style="color:#f92672">.</span>sift_up(n<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)
        
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">sift_up</span>(self, i):
        <span style="color:#66d9ef">while</span> i <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">and</span> self<span style="color:#f92672">.</span>heap[i][<span style="color:#ae81ff">0</span>] <span style="color:#f92672">&lt;</span> self<span style="color:#f92672">.</span>heap[self<span style="color:#f92672">.</span>parent(i)][<span style="color:#ae81ff">0</span>]:
            self<span style="color:#f92672">.</span>swap(i, self<span style="color:#f92672">.</span>parent(i))
            i <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>parent(i)
        
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">extract_min</span>(self):
        min_item <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>heap[<span style="color:#ae81ff">0</span>]
        <span style="color:#66d9ef">del</span> self<span style="color:#f92672">.</span>position[min_item[<span style="color:#ae81ff">1</span>]]
        last_item <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>heap<span style="color:#f92672">.</span>pop()
        <span style="color:#66d9ef">if</span> self<span style="color:#f92672">.</span>heap:
            self<span style="color:#f92672">.</span>heap[<span style="color:#ae81ff">0</span>] <span style="color:#f92672">=</span> last_item
            self<span style="color:#f92672">.</span>position[last_item[<span style="color:#ae81ff">1</span>]] <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>
            self<span style="color:#f92672">.</span>sift_down(<span style="color:#ae81ff">0</span>)
        <span style="color:#66d9ef">return</span> min_item
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">sift_down</span>(self, i):
        n <span style="color:#f92672">=</span> len(self<span style="color:#f92672">.</span>heap)
        min_idx <span style="color:#f92672">=</span> i
        l <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>left_child(i)
        <span style="color:#66d9ef">if</span> l <span style="color:#f92672">&lt;</span> n <span style="color:#f92672">and</span> self<span style="color:#f92672">.</span>heap[l][<span style="color:#ae81ff">0</span>] <span style="color:#f92672">&lt;</span> self<span style="color:#f92672">.</span>heap[min_idx][<span style="color:#ae81ff">0</span>]:
            min_idx <span style="color:#f92672">=</span> l
        r <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>right_child(i)
        <span style="color:#66d9ef">if</span> r <span style="color:#f92672">&lt;</span> n <span style="color:#f92672">and</span> self<span style="color:#f92672">.</span>heap[r][<span style="color:#ae81ff">0</span>] <span style="color:#f92672">&lt;</span> self<span style="color:#f92672">.</span>heap[min_idx][<span style="color:#ae81ff">0</span>]:
            min_idx <span style="color:#f92672">=</span> r
        <span style="color:#66d9ef">if</span> i <span style="color:#f92672">!=</span> min_idx:
            self<span style="color:#f92672">.</span>swap(i, min_idx)
            self<span style="color:#f92672">.</span>sift_down(min_idx)
    
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">changePriority</span>(self, item, new_priority):
        <span style="color:#66d9ef">if</span> item <span style="color:#f92672">in</span> self<span style="color:#f92672">.</span>position:
            i <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>position[item]
            old_priority <span style="color:#f92672">=</span> self<span style="color:#f92672">.</span>heap[i][<span style="color:#ae81ff">0</span>]
            self<span style="color:#f92672">.</span>heap[i] <span style="color:#f92672">=</span> (new_priority, item)
            <span style="color:#66d9ef">if</span> new_priority <span style="color:#f92672">&lt;</span> old_priority:
                self<span style="color:#f92672">.</span>sift_up(i)
            <span style="color:#66d9ef">else</span>:
                self<span style="color:#f92672">.</span>sift_down(i)
</code></pre></td></tr></table>
</div>
</div><p>In this implementation, the heap is represented as a list of tuples, where the first element of each tuple is the priority value and the second element is the data item. The <code>position</code> dictionary maps each data item to its index in the heap.</p>
<p>The <code>swap()</code> function swaps two elements in the heap and updates their positions in the <code>position</code> dictionary accordingly.</p>
<p>The <code>changePriority()</code> function takes a data item and a new priority value and updates the heap and <code>position</code> dictionary accordingly. If the new priority is lower than the old priority, the function calls <code>sift_up()</code> to move the item up the heap, otherwise it calls <code>sift_down()</code> to move the item down the heap.</p>
<h1 id="modified-dijkstra-s-algorithm">Modified Dijkstra&rsquo;s Algorithm</h1>
<p><em>I asked ChatGPT to implement Dijkstra&rsquo;s algorithm for me. I asked it to preserve all the alternative paths with the same distance. And use a list of lists to maintain that information. It correctly implement the functionality I requested. I then tweaked it a little bit, asking it use <code>list</code>, instead of <code>dict</code> for distances.</em></p>
<p>Person:</p>
<ul>
<li>Dijkstra algorithm implementation via heap</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li><em>I skip the content here. ChapGPT gave me an standard implementation, not satisfying my needs.</em></li>
</ul>
<p>Person:</p>
<ul>
<li>in the above implementation: the alternative path where new_distance == distances[neighbor] is discard; use a data structure having the type list of lists with name prev, to maintain that information</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, we can modify the previous implementation to keep track of the predecessor of each node on the shortest path. Here&rsquo;s the updated Python code:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> heapq

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">dijkstra_heap</span>(graph, start):
    distances <span style="color:#f92672">=</span> {node: float(<span style="color:#e6db74">&#39;inf&#39;</span>) <span style="color:#66d9ef">for</span> node <span style="color:#f92672">in</span> graph}  <span style="color:#75715e"># set all distances to infinity</span>
    distances[start] <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>  <span style="color:#75715e"># set the distance to the start node to 0</span>
    heap <span style="color:#f92672">=</span> [(<span style="color:#ae81ff">0</span>, start)]  <span style="color:#75715e"># initialize heap with starting node and its distance</span>
    prev <span style="color:#f92672">=</span> {node: [] <span style="color:#66d9ef">for</span> node <span style="color:#f92672">in</span> graph}  <span style="color:#75715e"># initialize predecessor list for all nodes</span>
    <span style="color:#66d9ef">while</span> heap:
        (distance, node) <span style="color:#f92672">=</span> heapq<span style="color:#f92672">.</span>heappop(heap)  <span style="color:#75715e"># get node with smallest distance from heap</span>
        <span style="color:#66d9ef">if</span> distance <span style="color:#f92672">&gt;</span> distances[node]:  <span style="color:#75715e"># if node is already processed, skip it</span>
            <span style="color:#66d9ef">continue</span>
        <span style="color:#66d9ef">for</span> neighbor, weight <span style="color:#f92672">in</span> graph[node]<span style="color:#f92672">.</span>items():  <span style="color:#75715e"># visit neighbors of the node</span>
            new_distance <span style="color:#f92672">=</span> distances[node] <span style="color:#f92672">+</span> weight
            <span style="color:#66d9ef">if</span> new_distance <span style="color:#f92672">&lt;</span> distances[neighbor]:  <span style="color:#75715e"># if new distance to neighbor is shorter, update it</span>
                distances[neighbor] <span style="color:#f92672">=</span> new_distance
                prev[neighbor] <span style="color:#f92672">=</span> [node]  <span style="color:#75715e"># set the node as the only predecessor of the neighbor</span>
                heapq<span style="color:#f92672">.</span>heappush(heap, (new_distance, neighbor))  <span style="color:#75715e"># add neighbor and its distance to heap</span>
            <span style="color:#66d9ef">elif</span> new_distance <span style="color:#f92672">==</span> distances[neighbor]:  <span style="color:#75715e"># if there&#39;s a tie in distance, add the node as a predecessor</span>
                prev[neighbor]<span style="color:#f92672">.</span>append(node)
    <span style="color:#66d9ef">return</span> distances, prev
</code></pre></td></tr></table>
</div>
</div><p>The <code>prev</code> dictionary is initialized with empty lists as the predecessor of each node. In the main loop, if a shorter distance to a neighbor is found, its predecessor list is updated with the current node. If there&rsquo;s a tie in distance, the current node is added to the predecessor list.</p>
<p>The modified function returns two values: <code>distances</code> and <code>prev</code>. <code>distances</code> is the same as before, containing the shortest distances to all nodes from the starting node. <code>prev</code> is a dictionary where each key is a node, and its value is a list of nodes that are its predecessors on the shortest path.</p>
<p>Person:</p>
<ul>
<li>use list for distances, and name it dist instead</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s the modified implementation that uses a list for <code>distances</code> instead of a dictionary, and names it <code>dist</code>:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#f92672">import</span> heapq

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">dijkstra_heap</span>(graph, start):
    n <span style="color:#f92672">=</span> len(graph)
    dist <span style="color:#f92672">=</span> [float(<span style="color:#e6db74">&#39;inf&#39;</span>)] <span style="color:#f92672">*</span> n  <span style="color:#75715e"># set all distances to infinity</span>
    dist[start] <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>  <span style="color:#75715e"># set the distance to the start node to 0</span>
    heap <span style="color:#f92672">=</span> [(<span style="color:#ae81ff">0</span>, start)]  <span style="color:#75715e"># initialize heap with starting node and its distance</span>
    prev <span style="color:#f92672">=</span> [[] <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(n)]  <span style="color:#75715e"># initialize predecessor list for all nodes</span>
    <span style="color:#66d9ef">while</span> heap:
        (distance, node) <span style="color:#f92672">=</span> heapq<span style="color:#f92672">.</span>heappop(heap)  <span style="color:#75715e"># get node with smallest distance from heap</span>
        <span style="color:#66d9ef">if</span> distance <span style="color:#f92672">&gt;</span> dist[node]:  <span style="color:#75715e"># if node is already processed, skip it</span>
            <span style="color:#66d9ef">continue</span>
        <span style="color:#66d9ef">for</span> neighbor, weight <span style="color:#f92672">in</span> graph[node]<span style="color:#f92672">.</span>items():  <span style="color:#75715e"># visit neighbors of the node</span>
            new_distance <span style="color:#f92672">=</span> dist[node] <span style="color:#f92672">+</span> weight
            <span style="color:#66d9ef">if</span> new_distance <span style="color:#f92672">&lt;</span> dist[neighbor]:  <span style="color:#75715e"># if new distance to neighbor is shorter, update it</span>
                dist[neighbor] <span style="color:#f92672">=</span> new_distance
                prev[neighbor] <span style="color:#f92672">=</span> [node]  <span style="color:#75715e"># set the node as the only predecessor of the neighbor</span>
                heapq<span style="color:#f92672">.</span>heappush(heap, (new_distance, neighbor))  <span style="color:#75715e"># add neighbor and its distance to heap</span>
            <span style="color:#66d9ef">elif</span> new_distance <span style="color:#f92672">==</span> dist[neighbor]:  <span style="color:#75715e"># if there&#39;s a tie in distance, add the node as a predecessor</span>
                prev[neighbor]<span style="color:#f92672">.</span>append(node)
    <span style="color:#66d9ef">return</span> dist, prev
</code></pre></td></tr></table>
</div>
</div><p>The <code>dist</code> list is initialized with <code>float('inf')</code> for all nodes except the starting node, which is set to 0. The <code>prev</code> list is initialized with empty lists as the predecessor of each node.</p>
<p>In the main loop, the <code>distance</code> variable is renamed to <code>dist[node]</code> for readability, and the <code>distances</code> dictionary is replaced with <code>dist</code>. The <code>n</code> variable is added to store the number of nodes in the graph.</p>
<p>The <code>shortest_path</code> function from the previous answer should still work without any modification.</p>
<h1 id="bfs-backtrack-deletion">BFS Backtrack Deletion</h1>
<p><em>I ask ChatGPT to delete the edges stored in <code>prev</code>.</em></p>
<p>Person:</p>
<ul>
<li>Given dist, prev  as the returning result of the dijkstra_heap function. We consider deleting all the edge recorded in prev subgraph using a BFS algorithm. The function&rsquo;s signature looks like delete(graph, prev, t), where t is the starting vertex of hte algorithm. For any (u,v) in prev, delete it from graph.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s an implementation of the <code>delete</code> function that takes in the graph <code>graph</code>, the previous node list <code>prev</code>, and the starting vertex <code>t</code>. It uses a breadth-first search (BFS) to traverse the previous node list and remove all the edges in the subgraph represented by <code>prev</code>.</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">
<span style="color:#f92672">from</span> collections <span style="color:#f92672">import</span> deque

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">delete</span>(graph, prev, t):
    <span style="color:#75715e"># Initialize visited and queue for BFS</span>
    visited <span style="color:#f92672">=</span> set()
    queue <span style="color:#f92672">=</span> deque([t])
    visited<span style="color:#f92672">.</span>add(t)

    <span style="color:#75715e"># Traverse the previous node list with BFS</span>
    <span style="color:#66d9ef">while</span> queue:
        u <span style="color:#f92672">=</span> queue<span style="color:#f92672">.</span>popleft()
        <span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> prev[u]:
            <span style="color:#66d9ef">if</span> v <span style="color:#f92672">not</span> <span style="color:#f92672">in</span> visited:
                visited<span style="color:#f92672">.</span>add(v)
                queue<span style="color:#f92672">.</span>append(v)
            <span style="color:#75715e"># Remove the edge (u, v) from the graph</span>
            graph[u] <span style="color:#f92672">=</span> [(w, weight) <span style="color:#66d9ef">for</span> w, weight <span style="color:#f92672">in</span> graph[u] <span style="color:#66d9ef">if</span> w <span style="color:#f92672">!=</span> v]

    <span style="color:#66d9ef">return</span> graph
</code></pre></td></tr></table>
</div>
</div><p>The function starts by initializing a set of visited nodes and a queue for the BFS. We add the starting vertex <code>t</code> to the visited set and enqueue it to the queue.</p>
<p>We then traverse the previous node list with BFS. For each node <code>u</code> in the queue, we loop over all its previous nodes <code>v</code> and add them to the visited set if they haven&rsquo;t been visited before. We also remove the edge <code>(u, v)</code> from the graph by creating a new list of edges for node <code>u</code> that excludes the edge <code>(u, v)</code>.</p>
<p>Finally, we return the modified graph.</p>
<p>Person:</p>
<ul>
<li>add another parameter &ldquo;s&rdquo; to the above BFS algorithm. After the line &ldquo;u = queue.popleft()&rdquo;, check if u is s, if true, exit the loop.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure, here&rsquo;s the modified implementation of the <code>delete</code> function that adds a parameter <code>s</code> and checks if the current node <code>u</code> is equal to <code>s</code>. If <code>u</code> is equal to <code>s</code>, we exit the loop early.</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">
<span style="color:#f92672">from</span> collections <span style="color:#f92672">import</span> deque

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">delete</span>(graph, prev, t, s):
    <span style="color:#75715e"># Initialize visited and queue for BFS</span>
    visited <span style="color:#f92672">=</span> set()
    queue <span style="color:#f92672">=</span> deque([t])
    visited<span style="color:#f92672">.</span>add(t)

    <span style="color:#75715e"># Traverse the previous node list with BFS</span>
    <span style="color:#66d9ef">while</span> queue:
        u <span style="color:#f92672">=</span> queue<span style="color:#f92672">.</span>popleft()
        <span style="color:#66d9ef">if</span> u <span style="color:#f92672">==</span> s:
            <span style="color:#66d9ef">break</span>
        <span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> prev[u]:
            <span style="color:#66d9ef">if</span> v <span style="color:#f92672">not</span> <span style="color:#f92672">in</span> visited:
                visited<span style="color:#f92672">.</span>add(v)
                queue<span style="color:#f92672">.</span>append(v)
            <span style="color:#75715e"># Remove the edge (u, v) from the graph</span>
            graph[u] <span style="color:#f92672">=</span> [(w, weight) <span style="color:#66d9ef">for</span> w, weight <span style="color:#f92672">in</span> graph[u] <span style="color:#66d9ef">if</span> w <span style="color:#f92672">!=</span> v]

    <span style="color:#66d9ef">return</span> graph
</code></pre></td></tr></table>
</div>
</div><p>We add the parameter <code>s</code> to the function&rsquo;s signature, which represents the node at which we want to stop the BFS. Inside the while loop, we check if <code>u</code> is equal to <code>s</code>. If it is, we exit the loop early by using the <code>break</code> statement.</p>
<p>Note that this modification assumes that <code>s</code> is reachable from <code>t</code> in the graph. If <code>s</code> is not reachable from <code>t</code>, the function will continue to remove edges until the BFS has traversed the entire graph.</p>
<p>Person:</p>
<ul>
<li>Instead of remoing (u,v) from the graph, we should remove (v, u) from the graph, since prev records predesessors&hellip;&hellip;.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>You&rsquo;re correct! Since the <code>prev</code> list records the predecessors, we should remove the edge <code>(v, u)</code> instead of <code>(u, v)</code> from the graph.</li>
</ul>
<p>Here&rsquo;s the modified implementation of the <code>delete</code> function that removes the edge <code>(v, u)</code> instead of <code>(u, v)</code>:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">
<span style="color:#f92672">from</span> collections <span style="color:#f92672">import</span> deque

<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">delete</span>(graph, prev, t, s):
    <span style="color:#75715e"># Initialize visited and queue for BFS</span>
    visited <span style="color:#f92672">=</span> set()
    queue <span style="color:#f92672">=</span> deque([t])
    visited<span style="color:#f92672">.</span>add(t)

    <span style="color:#75715e"># Traverse the previous node list with BFS</span>
    <span style="color:#66d9ef">while</span> queue:
        u <span style="color:#f92672">=</span> queue<span style="color:#f92672">.</span>popleft()
        <span style="color:#66d9ef">if</span> u <span style="color:#f92672">==</span> s:
            <span style="color:#66d9ef">break</span>
        <span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> prev[u]:
            <span style="color:#66d9ef">if</span> v <span style="color:#f92672">not</span> <span style="color:#f92672">in</span> visited:
                visited<span style="color:#f92672">.</span>add(v)
                queue<span style="color:#f92672">.</span>append(v)
            <span style="color:#75715e"># Remove the edge (v, u) from the graph</span>
            graph[v] <span style="color:#f92672">=</span> [(w, weight) <span style="color:#66d9ef">for</span> w, weight <span style="color:#f92672">in</span> graph[v] <span style="color:#66d9ef">if</span> w <span style="color:#f92672">!=</span> u]

    <span style="color:#66d9ef">return</span> graph
</code></pre></td></tr></table>
</div>
</div><p>Inside the <code>for</code> loop, we remove the edge <code>(v, u)</code> from the graph by creating a new list of edges for node <code>v</code> that excludes the edge <code>(u, v)</code>.</p>
<p>Thanks for bringing this to my attention!</p>
<h1 id="putting-everything-together">Putting Everything Together</h1>
<p>By now I have everything we need. Let&rsquo;s put them all together. There are very few lines of codes that I really need to write, in the case I need to do so, my GitHub Copilot plugin give me very good suggestion: I just need to type a few initial letters and then hit <code>Tab</code>.</p>
<p>Besides changing a few variables/functions name. Here are some modification I did.</p>
<h2 id="break-early-in-dijkstra-s-algorithm">Break Early In Dijkstra&rsquo;s Algorithm</h2>
<p>We don&rsquo;t care about the shortest distance of other nodes more than necessary. When <code>dest</code> is extracted from the heap, its shortest distance is not going to change anymore. Hence we break the loop. See <strong>line 21-23</strong>. (GitHub Copilot promote the right code and write the comments for me, although its not always accurate.)</p>
<div class="highlight myclass"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="display:block;width:100%;background-color:#3c3d38"><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span></span><span style="display:block;width:100%;background-color:#3c3d38"><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span></span><span style="display:block;width:100%;background-color:#3c3d38"><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span></span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">dijkstra</span>(graph, start):
    n <span style="color:#f92672">=</span> len(graph)
    dist <span style="color:#f92672">=</span> [float(<span style="color:#e6db74">&#39;inf&#39;</span>)] <span style="color:#f92672">*</span> n  <span style="color:#75715e"># set all distances to infinity</span>
    dist[start] <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>  <span style="color:#75715e"># set the distance to the start node to 0</span>
    heap <span style="color:#f92672">=</span> MinHeap()  <span style="color:#75715e"># initialize heap</span>
    heap<span style="color:#f92672">.</span>insert((<span style="color:#ae81ff">0</span>, start))  <span style="color:#75715e"># initialize heap with starting node and its distance</span>
    prev <span style="color:#f92672">=</span> [[] <span style="color:#66d9ef">for</span> _ <span style="color:#f92672">in</span> range(n)]  <span style="color:#75715e"># initialize predecessor list for all nodes</span>
    <span style="color:#66d9ef">while</span> heap<span style="color:#f92672">.</span>isempty() <span style="color:#f92672">==</span> <span style="color:#66d9ef">False</span>:
        (distance, node) <span style="color:#f92672">=</span> heap<span style="color:#f92672">.</span>extract_min()  <span style="color:#75715e"># get node with smallest distance from heap</span>
        <span style="color:#66d9ef">if</span> distance <span style="color:#f92672">&gt;</span> dist[node]: <span style="color:#75715e"># if node is already processed, skip it</span>
            <span style="color:#66d9ef">continue</span>
        <span style="color:#66d9ef">for</span> neighbor, weight <span style="color:#f92672">in</span> graph[node]:  <span style="color:#75715e"># visit neighbors of the node</span>
            new_distance <span style="color:#f92672">=</span> dist[node] <span style="color:#f92672">+</span> weight
            <span style="color:#66d9ef">if</span> new_distance <span style="color:#f92672">&lt;</span> dist[neighbor]:  <span style="color:#75715e"># if new distance to neighbor is shorter, update it</span>
                dist[neighbor] <span style="color:#f92672">=</span> new_distance
                prev[neighbor] <span style="color:#f92672">=</span> [node]  <span style="color:#75715e"># set the node as the only predecessor of the neighbor</span>
                heap<span style="color:#f92672">.</span>insert((new_distance, neighbor))  <span style="color:#75715e"># add neighbor and its distance to heap</span>
            <span style="color:#66d9ef">elif</span> new_distance <span style="color:#f92672">==</span> dist[neighbor]:  <span style="color:#75715e"># if there&#39;s a tie in distance, add the node as a predecessor</span>
                prev[neighbor]<span style="color:#f92672">.</span>append(node)

<span style="display:block;width:100%;background-color:#3c3d38">    <span style="color:#75715e"># break early if we reached the destination</span>
</span><span style="display:block;width:100%;background-color:#3c3d38">        <span style="color:#66d9ef">if</span> node <span style="color:#f92672">==</span> dest:  <span style="color:#75715e"># if we reached the destination, stop</span>
</span><span style="display:block;width:100%;background-color:#3c3d38">            <span style="color:#66d9ef">break</span>
</span>    <span style="color:#66d9ef">return</span> dist, prev

</code></pre></td></tr></table>
</div>
</div><h2 id="no-changekey-needed">No <code>changeKey</code> Needed</h2>
<p>Note that in this implementation, no <code>changeKey()</code> function is needed. The trick happens in line 10-11 of the above code block.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">        <span style="color:#66d9ef">if</span> distance <span style="color:#f92672">&gt;</span> dist[node]: <span style="color:#75715e"># if node is already processed, skip it</span>
            <span style="color:#66d9ef">continue</span>
</code></pre></td></tr></table>
</div>
</div><p>The distance is saved in two places: the heap and the array <code>dist</code>. The distances <code>dist[node]</code> get updated more often than the copy in the heap: whenever some neighbor of the node get popped from the heap, it might receive an alternative value. If we want to make all the copy of the <code>dist[node]</code> up-to-date, we need to do a <code>changeKey</code>. However, the <code>changeKey</code> operation is expensive: we need to look though the underlying array of the heap, or use a fast look-up table to find where the <code>(dist[node], node)</code> is stored in the heap and changing it will cause a heapify process.</p>
<p>The above code use a <strong>lazy strategy</strong>. When a alternative (smaller) distance is found, we just insert into the heap the node and its new distance. The heap-copy of the distance is now outdated. But we still leave it in the heap, until at some point we pop it and do the above comparison to find that it is outdated, then discard it. This strategy is more efficient, but it can incur higher space cost since we will have many copy of the <code>(dist, node)</code> pair in the heap. The correctness is always guarantee, for the smallest copy always get processed first since we are using a min heap!</p>
<h2 id="bfs-deletion">BFS Deletion</h2>
<p>Similarly to the early exit of Dijkstra&rsquo;s algorithm, I add a line of code to exit the BFS deletion function early. See line 10-11.</p>
<div class="highlight myclass"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="display:block;width:100%;background-color:#3c3d38"><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span></span><span style="display:block;width:100%;background-color:#3c3d38"><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span></span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">delete</span>(graph, prev, s, t):
    <span style="color:#75715e"># Initialize visited and queue for BFS</span>
    visited <span style="color:#f92672">=</span> set()
    queue <span style="color:#f92672">=</span> deque([t])
    visited<span style="color:#f92672">.</span>add(t)

    <span style="color:#75715e"># Traverse the previous node list with BFS</span>
    <span style="color:#66d9ef">while</span> queue:
        u <span style="color:#f92672">=</span> queue<span style="color:#f92672">.</span>popleft()
<span style="display:block;width:100%;background-color:#3c3d38">        <span style="color:#66d9ef">if</span> u <span style="color:#f92672">==</span> s:
</span><span style="display:block;width:100%;background-color:#3c3d38">            <span style="color:#66d9ef">break</span>
</span>        <span style="color:#66d9ef">for</span> v <span style="color:#f92672">in</span> prev[u]:
            <span style="color:#66d9ef">if</span> v <span style="color:#f92672">not</span> <span style="color:#f92672">in</span> visited:
                visited<span style="color:#f92672">.</span>add(v)
                queue<span style="color:#f92672">.</span>append(v)
            <span style="color:#75715e"># Remove the edge (u, v) from the graph</span>
            graph[v] <span style="color:#f92672">=</span> [(w, weight) <span style="color:#66d9ef">for</span> w, weight <span style="color:#f92672">in</span> graph[v] <span style="color:#66d9ef">if</span> w <span style="color:#f92672">!=</span> u]


    <span style="color:#66d9ef">return</span> graph

</code></pre></td></tr></table>
</div>
</div><p>Note that we just want to delete shortest paths starting from <code>s</code> and ending at <code>t</code>, and we begin this BFS in a backward way. When <code>s</code> is pop from the queue, we need to end immediately, otherwise the algorithm might delete other useful edges.</p>
<p>The following test case can make the idea clearer.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">9
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-txt" data-lang="txt">5 6
0 1
0 1 1
0 2 1
2 3 1
2 4 1
3 1 1
4 1 1
0 0
</code></pre></td></tr></table>
</div>
</div><p>You can easily draw the graph out. After the first round, if you break early from Dijkstra&rsquo;s algorithm, your <code>prev</code> will basically contain two edges {(0,1),(0,2)}. The BFS algorithm will only need to delete (0,1), since s=0, t=1. If you delete also (0,2), you will get a wrong answer! I had to run a debugger to figure this out.</p>
<p><strong>The above few lines of code are the real codes that I add to this project!</strong> Easy task? No! If you don&rsquo;t know the algorithm well, there is no way you know what to do! That is why you still need to learn.</p>
<h2 id="the-full-solution">The Full Solution</h2>
<p>This blog has already becoming too long. You can download the file <a href="/src/ASP/main.py">here</a>.</p>
<p><img src="/images/ASP.png" alt="Beecrowd"></p>
<h1 id="conclusion">Conclusion</h1>
<ol>
<li><a href="https://github.blog/2023-03-22-github-copilot-x-the-ai-powered-developer-experience/">ChatGPT and GitHub Copilot</a>  dramatically changes the way we write codes. In the above project, I only &ldquo;wrote&rdquo; four lines of codes, which are generated by Copilot after I typed the first few letters. With ChatGPT and Copilot, one can have great confidence even when writing in an unfamiliar language.</li>
<li>A lot of laborious intermediate-level software development jobs will be accelerated by them, if not <strong>replace</strong> by them. ChatGPT will become a basic tool, just like the calculator in your pocket. You can not get a job by claiming you know how to press the buttons on a calculator. You need to go beyond that.</li>
<li>Learning is still important. As you can see from the above, insights into the algorithms are critical. Without a good understanding of the algorithms, you can not go very far.</li>
</ol>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Gray&#39;s Binary Code</title>
      <link>https://xianghuang.me/course/gpt_gray/</link>
      <pubDate>Sun, 26 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/gpt_gray/</guid>
      <description>
        <![CDATA[
        <p>I will teach recursion and induction next week and I will use Gray&rsquo;s code as an example. I asked ChatGPT about it. Summary:</p>
<ol>
<li>The programs ChatGPT gave are correct. But it did make a mistake: it&rsquo;s example test cases output does not correctly correspond to its program. The order of reflected codes and non-reflected codes were switched. I pointed that out and ChatGPT fixed it.</li>
<li>The inductive proof it wrote misses did not discuss the adjacent codes (last one in the non-reflected codes and the first one in the reflected codes). I pointed out and ChatGPT seemed to try to fixed it but mainly just copy my words.</li>
<li>The space complexity $O(1)$ ChatGPT claimed is not true.</li>
</ol>
<p><strong>Below is the conversation I have with ChatGPT on Gray&rsquo;s code.</strong></p>
<p>Person:</p>
<ul>
<li>Can you recursively generate all Gray' binary code of length n and explain the code to me?</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Sure! The Gray code is a binary numeral system where two consecutive values differ in only one bit position. To recursively generate all Gray codes of length <code>n</code>, we can use the following algorithm:</li>
</ul>
<ol>
<li>If <code>n = 1</code>, the Gray code is <code>['0', '1']</code>.</li>
<li>Otherwise, generate the Gray code of length <code>n-1</code> recursively.</li>
<li>Reflect the Gray code of length <code>n-1</code> around its middle (i.e., reverse the order of the elements).</li>
<li>Add a <code>0</code> prefix to each element of the reflected Gray code.</li>
<li>Add a <code>1</code> prefix to each element of the original Gray code of length <code>n-1</code>.</li>
<li>Concatenate the two lists obtained in steps 4 and 5 to obtain the Gray code of length <code>n</code>.</li>
</ol>
<p>Here is the implementation of the above algorithm in Python:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">9
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">gray_code</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">1</span>:
        <span style="color:#66d9ef">return</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>]
    <span style="color:#66d9ef">else</span>:
        prev_code <span style="color:#f92672">=</span> gray_code(n<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)
        reflected_code <span style="color:#f92672">=</span> prev_code[::<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>]
        zero_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;0</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> reflected_code]
        one_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;1</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> prev_code]
        <span style="color:#66d9ef">return</span> zero_prefixed <span style="color:#f92672">+</span> one_prefixed
</code></pre></td></tr></table>
</div>
</div><p>To use this function, you can simply call <code>gray_code(n)</code> where <code>n</code> is the length of the Gray code you want to generate. For example:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">result <span style="color:#f92672">=</span> gray_code(<span style="color:#ae81ff">3</span>)
print(result)
</code></pre></td></tr></table>
</div>
</div><p>This will output:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-css" data-lang="css"><span style="color:#f92672">[</span><span style="color:#e6db74">&#39;000&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;001&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;011&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;010&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;110&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;111&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;101&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;100&#39;</span><span style="color:#f92672">]</span>
</code></pre></td></tr></table>
</div>
</div><p>which are all the possible Gray codes of length 3.</p>
<p>Note that this algorithm has a time complexity of <code>O(2^n)</code> since it generates all possible Gray codes of length <code>n</code>.</p>
<p>Person:</p>
<ul>
<li>Do you have a way to generate the codes with less space?</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Yes, there is a more memory-efficient way to generate the Gray code sequence of length <code>n</code> using an iterative approach, which uses only <code>O(1)</code> extra space.</li>
</ul>
<p>The basic idea is to start with the Gray code of length <code>1</code>, and then generate the Gray code of length <code>n</code> by iteratively inserting a new bit to the left of the previous sequence, while reflecting the previous sequence and adding a new bit to the left of the reflected sequence. This process generates all possible Gray codes of length <code>n</code> without storing all of them explicitly in memory.</p>
<p>Here is the implementation of the iterative algorithm in Python:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">gray_code</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> [<span style="color:#e6db74">&#39;&#39;</span>]
    
    prev_code <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>]
    <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>, n<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>):
        reflected_code <span style="color:#f92672">=</span> prev_code[::<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>]
        zero_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;0</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> reflected_code]
        one_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;1</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> prev_code]
        prev_code <span style="color:#f92672">=</span> zero_prefixed <span style="color:#f92672">+</span> one_prefixed
    
    <span style="color:#66d9ef">return</span> prev_code
</code></pre></td></tr></table>
</div>
</div><p>This algorithm starts by initializing the <code>prev_code</code> variable with the Gray code of length 1 (<code>['0', '1']</code>), and then generates the Gray code of length <code>n</code> by iteratively applying the steps described above.</p>
<p>To use this function, you can simply call <code>gray_code(n)</code> where <code>n</code> is the length of the Gray code you want to generate. For example:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python">result <span style="color:#f92672">=</span> gray_code(<span style="color:#ae81ff">3</span>)
print(result)
</code></pre></td></tr></table>
</div>
</div><p>This will output:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-css" data-lang="css"><span style="color:#f92672">[</span><span style="color:#e6db74">&#39;000&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;001&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;011&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;010&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;110&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;111&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;101&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;100&#39;</span><span style="color:#f92672">]</span>
</code></pre></td></tr></table>
</div>
</div><p>which are all the possible Gray codes of length 3.</p>
<p>Note that this algorithm has a time complexity of <code>O(2^n)</code> since it generates all possible Gray codes of length <code>n</code>. However, it only uses <code>O(1)</code> extra space, which makes it more memory-efficient than the recursive approach.</p>
<p>Person:</p>
<ul>
<li>I felt like you need to do prev_code  in zero_prefixed = [f'0{c}' for c in reflected_code]  and reflected_code in the one_prefixed to get the order you output up there</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>You are correct! Thank you for pointing that out. The order of the lists in the concatenation step should be reversed to get the correct order of the Gray code sequence. Here is the corrected implementation:</li>
</ul>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">gray_code</span>(n):
    <span style="color:#66d9ef">if</span> n <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> [<span style="color:#e6db74">&#39;&#39;</span>]
    
    prev_code <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;0&#39;</span>, <span style="color:#e6db74">&#39;1&#39;</span>]
    <span style="color:#66d9ef">for</span> i <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">2</span>, n<span style="color:#f92672">+</span><span style="color:#ae81ff">1</span>):
        reflected_code <span style="color:#f92672">=</span> prev_code[::<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>]
        zero_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;0</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> prev_code]
        one_prefixed <span style="color:#f92672">=</span> [<span style="color:#e6db74">f</span><span style="color:#e6db74">&#39;1</span><span style="color:#e6db74">{</span>c<span style="color:#e6db74">}</span><span style="color:#e6db74">&#39;</span> <span style="color:#66d9ef">for</span> c <span style="color:#f92672">in</span> reflected_code]
        prev_code <span style="color:#f92672">=</span> zero_prefixed <span style="color:#f92672">+</span> one_prefixed
    
    <span style="color:#66d9ef">return</span> prev_code
</code></pre></td></tr></table>
</div>
</div><p>Now, calling <code>gray_code(3)</code> will produce the expected output:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-css" data-lang="css"><span style="color:#f92672">[</span><span style="color:#e6db74">&#39;000&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;001&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;011&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;010&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;110&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;111&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;101&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;100&#39;</span><span style="color:#f92672">]</span>
</code></pre></td></tr></table>
</div>
</div><p>Person:</p>
<ul>
<li>Can you write a inductive proof that the python code above indeed produces correct Gray code, i.e., the consecutive codes differ by exactly one bit.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>
<p>Sure! Here&rsquo;s an inductive proof that the Python code provided earlier in our conversation indeed generates a correct Gray code sequence, where each consecutive code differs by exactly one bit:</p>
</li>
<li>
<p><strong>Claim</strong>: The Python code generates a correct Gray code sequence of length n, where each consecutive code differs by exactly one bit.</p>
</li>
<li>
<p><strong>Base Case</strong>: When n = 1, the code generates the list [&lsquo;0&rsquo;, &lsquo;1&rsquo;], which is a correct Gray code sequence of length 1, where each consecutive code differs by exactly one bit.</p>
</li>
<li>
<p><strong>Inductive Hypothesis</strong>: Assume that the Python code generates a correct Gray code sequence of length k, where k &gt; 1, and each consecutive code differs by exactly one bit.</p>
</li>
<li>
<p><strong>Inductive Step</strong>: We will show that the Python code generates a correct Gray code sequence of length k+1, where each consecutive code differs by exactly one bit.</p>
<ul>
<li>
<p>First, we obtain the Gray code sequence of length k using the Python code, which we assume to be correct by the inductive hypothesis. Then, we reverse this sequence to obtain a reflected Gray code sequence of length k, which also has the property that each consecutive code differs by exactly one bit. We then add a &lsquo;0&rsquo; prefix to each code in the original Gray code sequence, and a &lsquo;1&rsquo; prefix to each code in the reflected Gray code sequence. We then concatenate these two lists to obtain a new list of codes of length 2k. This new list of codes has the property that each consecutive code differs by exactly one bit, because adding a &lsquo;0&rsquo; prefix to each code in the original Gray code sequence ensures that the first bit in each code changes from 0 to 1 as we go from one code to the next, while adding a &lsquo;1&rsquo; prefix to each code in the reflected Gray code sequence ensures that the first bit in each code changes from 1 to 0 as we go from one code to the next. Since the remaining k-1 bits in each code remain the same as we move from one code to the next, we have that each consecutive code in the new list differs by exactly one bit. Therefore, the Python code generates a correct Gray code sequence of length k+1, where each consecutive code differs by exactly one bit.</p>
</li>
<li>
<p>By the principle of mathematical induction, the claim holds for all n &gt; 0. Therefore, the Python code provided earlier in our conversation indeed produces a correct Gray code sequence, where the consecutive codes differ by exactly one bit.</p>
</li>
</ul>
</li>
</ul>
<p>Person:</p>
<ul>
<li>You should emphasize that the last code in the prev block and the first code in the reflected prev block are the same, but there are added a prefix of &ldquo;0&rdquo; and &ldquo;1&rdquo; respectively, so now in the new code they differ by one bit.</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>
<p>You&rsquo;re absolutely right, thank you for pointing that out! Let me clarify that part of the proof.</p>
<ul>
<li>When we concatenate the list of zero-prefixed codes from the original Gray code sequence with the list of one-prefixed codes from the reflected Gray code sequence, the last code in the zero-prefixed block and the first code in the one-prefixed block are the same. However, since we add a prefix of &ldquo;0&rdquo; to the last code in the zero-prefixed block and a prefix of &ldquo;1&rdquo; to the first code in the one-prefixed block, these codes become different in the new Gray code sequence. Specifically, the last code in the zero-prefixed block becomes the first code in the new Gray code sequence, and the first code in the one-prefixed block becomes the second code in the new Gray code sequence. Since the last code in the zero-prefixed block and the first code in the one-prefixed block differ by exactly one bit (the first bit), this ensures that all consecutive codes in the new Gray code sequence differ by exactly one bit, as required.</li>
</ul>
</li>
<li>
<p>Thank you for bringing this to my attention, and I apologize for any confusion my previous explanation may have caused.</p>
</li>
</ul>
<p>Person:</p>
<ul>
<li>You are a little wordy. Can you give a more conciser summary?</li>
</ul>
<p>ChatGPT:</p>
<ul>
<li>Certainly! Here is a more concise summary of the inductive proof that the Python code generates a correct Gray code sequence, where each consecutive code differs by exactly one bit:</li>
<li>The base case of the proof is when n = 1, and the code generates the list [&lsquo;0&rsquo;, &lsquo;1&rsquo;], which is a correct Gray code sequence of length 1, where each consecutive code differs by exactly one bit.</li>
<li>The inductive hypothesis is that the Python code generates a correct Gray code sequence of length k, where k &gt; 1, and each consecutive code differs by exactly one bit.</li>
<li>The inductive step involves using the previous Gray code sequence of length k to generate a new Gray code sequence of length k+1, where each consecutive code differs by exactly one bit. This is achieved by taking the previous Gray code sequence, reversing it to obtain a reflected Gray code sequence, and then adding a prefix of &ldquo;0&rdquo; to each code in the previous sequence, and a prefix of &ldquo;1&rdquo; to each code in the reflected sequence. Concatenating these two lists yields a new Gray code sequence of length 2k, where each consecutive code differs by exactly one bit due to the added prefix, as well as the fact that the previous Gray code sequence and its reflection have the property that each consecutive code differs by exactly one bit.</li>
<li>By the principle of mathematical induction, the claim holds for all n &gt; 0.</li>
</ul>
<p>I hope this summary is helpful! Let me know if you have any further questions.</p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>A Powerset Enumberating Algorithm</title>
      <link>https://xianghuang.me/course/powerset/</link>
      <pubDate>Thu, 23 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/powerset/</guid>
      <description>
        <![CDATA[
        <p>One year when I taught Discrete Math, I assigned a Lab asking my students to enumberate the powerset of $\{1,2,\cdots,n\}$. There are a lot of solutions out there, either by binary counting or a standard backtracking algorithm. One can see <a href="https://afteracademy.com/blog/print-all-subsets-of-a-given-set/">this link</a> to check those solutions. The backtracking algorithms basically goes through all the elements and consider taking it or not.</p>
<p>One of my student, Eli Exner, said he would do things differently, but need some time to work out the detail. It turned out his implement the way we would have used to enumerate the powerset. Say, let $n=4$. He would enumerate the sets as follows:</p>
<div class="has-mathjax">

$$
    \emptyset, \{1\}, \{2\}, \{3\}, \{4\}, \{1,2\}, \{1,3\}, \{1,4\}, \{2,3\},\{2,4\}, \{3,4\}, \{1,2,3\}, \{1,2,4\}, \{1,3,4\},\{2,3,4\}, \{1,2,3,4\}
$$

</div>

<p>That is a very natural way to enumerate the sets. Basically that is to generate all $\binom{n}{k}$ size $k$ subsets. But how to program it? Eli observed the following features of the enumeration.</p>
<ol>
<li>We enumerate sets in batches of the same size. First batch, size zero (empty set);  then size one, size two, etc.</li>
<li>The initial set of each batch is a set that packing all number together, starting from 1. For example, for the size two batch, it will start with {1,2}.</li>
<li>After listing the initial set, we will increase the last number in the set, until it heats $n$. For example, after {1,2}, we list {1,3}, and then {1,4}.</li>
<li>Once we heat $n$ in the previous step. We increase the second to the last number, and pack numbers starting from the increased number, until we have enough numbers (hit the size of the current batch). For example,  after {1,2,4}, we would increase the second to the last number, which is 2. Now we have 3. Starting from 3, we need to pack numbers, so we have a 4.
Therefore, we get {1,3,4}. Note that 1 remains the same, we don&rsquo;t touch it. After that we repeat step 3.</li>
</ol>
<p>There is something special about the above process: why are we interested in the last number, and second to the last number etc.? What does the locations of these numbers that we are increasing mean? Eli develop this notion that he called &ldquo;depth&rdquo;.</p>
<div class="definition mathjax" text='Depth'>
    the
</div> 
<div class="definition mathjax" >
</div> 

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Lab: Subset Sum Problem and Knapsack problem</title>
      <link>https://xianghuang.me/course/partition_subset_sum/</link>
      <pubDate>Thu, 23 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/partition_subset_sum/</guid>
      <description>
        <![CDATA[
        <p>We talk about Subset Sum Problem and Knapsack Problem in our lecture. We now attack the following simple variant of Subset Sum Problem.</p>
<h2 id="problem-leetcode-416-partition-equal-subset-sum">Problem: Leetcode 416 - Partition Equal Subset Sum.</h2>
<p><strong>Problem Statement</strong>: Given an integer array <code>nums</code>, return <code>true</code> if you can partition the array into two subsets such that the sum of the elements in both subsets is equal or <code>false</code> otherwise.</p>
<p>You can find the full statement <a href="https://leetcode.com/problems/partition-equal-subset-sum/description/">here</a> on Leetcode.com.</p>
<h2 id="reduction">Reduction</h2>
<p>You might want to say this is not the version of Subset Sum we discussed in our class. True. The version we discussed has a target number $t$. Then what is the target number in this problem? Let&rsquo;s denote the set of number as $S$, then we let</p>
<p>$$
t =\frac{\sum_{n\in S} n}{2}.
$$</p>
<p>If you can find a subset of number sum up to $t$, then the rest of the number must also sum up to $t$. Hence you partition the set into two partitions with the same sum!
This idea, turning a problem to another <strong>solved</strong> problem, is called reduction. We will talk about it in the coming weeks!</p>
<h2 id="coding">Coding!</h2>
<p>Now it is time to do some coding! This is a Lab, not an assignment. So feel free to try whatever you want to try! One very helpful link is <a href="https://leetcode.com/discuss/study-guide/1152328/01-Knapsack-Problem-and-Dynamic-Programming">this</a>, where people discuss the implementation of classical Knapsack Problem. Here are a few things you want to do:</p>
<ol>
<li>If you haven&rsquo;t familiarize yourself with the <em>tabular method</em>, you can try the example there. (I was a little struggled doing the table, too.)</li>
<li>Try an implementation with 2-D array (the table!)</li>
<li>Try an implementation with 1-D array. (Scroll down and you will find people talk about it.)</li>
</ol>
<p>In the lecture I talk about the <strong>wavefront</strong> of memory when you did memoization. The wavefront of the 2-D table is actually just a single line! So that is why you can improve it by using only one line (the 1-D array)!</p>
<h2 id="submission-via-canvas">Submission via Canvas</h2>
<ol>
<li>A short report on the lab, in PDF format.</li>
<li>The codes you try.</li>
<li>A few Leetcode screenshots (Don&rsquo;t do too many).</li>
</ol>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>Recursion Review</title>
      <link>https://xianghuang.me/course/module-1-recursion-review/</link>
      <pubDate>Fri, 17 Mar 2023 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/module-1-recursion-review/</guid>
      <description>
        <![CDATA[
        <h1 id="introduction">Introduction</h1>
<p>Recursion is a commonly used, yet often difficult to grasp problem solving technique. Recursion itself is not an algorithm, but a process that can be implemented as part of an algorithm. The notion of recursion sometimes conjures up mental images like the one shown below, which is reminiscent of what one might see when two mirrors are placed so they are facing each other, allowing an image to be reflected back and forth indefinitely:</p>
<p><img src="/CSC482/pic/recursion.png" alt="">{width=&ldquo;563&rdquo; height=&ldquo;450&rdquo;}</p>
<p>We may think about solving a problem recursively during the process of problem decomposition, where we are trying to break a complex problem into smaller, less complex sub-problems that are easier to solve. For certain types of problems we may find that we can repetitively decompose a problem such that each sub-problem is really just a smaller version of the larger problem. In those cases, recursion may be an excellent way to solve those problems. The notion of a larger problem being repetitively broken down into similar but smaller problems is encapsulated in the diagram above.</p>
<p>In order for recursion to work, however, there must be a <strong>base case</strong>, which can be computed without using recursion. The base case serves as a termination point for recursion. Without a base case, infinite recursion results, which is similar to an infinite loop. A base case is conspicuously absent in the above diagram.</p>
<h1 id="some-classical-examples-of-recursive-problems">Some Classical Examples of Recursive Problems</h1>
<p>Examples of problems that lend themselves to recursive solutions abound. We&rsquo;ll look briefly at a few of the more classical examples of recursive problems here, but this list is by no means exhaustive.</p>
<h2 id="calculating-fibonacci-numbers">Calculating Fibonacci Numbers</h2>
<p>The Fibonacci sequence is a famous mathematical sequence:</p>
<p>0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, &hellip;</p>
<p>If squares whose sides measure individual Fibonacci numbers (except 0) are created and arranged as shown in the following diagram, a spiral that is found throughout nature can be drawn:</p>
<p><img src="/CSC482/pic/fibonacci_spiral_320.png" alt="">{width=&ldquo;320&rdquo; height=&ldquo;202&rdquo;}</p>
<p>Furthermore, for any consecutive pair of Fibonacci numbers, if you divide the greater number by the lesser number; e.g., $\frac{13}{8}$, you will get a decimal value that is very close to the Golden Ratio, an irrational number approximately equal to $1.61803&hellip;$</p>
<p>The rule for computing the $n$th Fibonacci number is very simple:
$$
F(n)=\begin{cases}
0,&amp;\text{for } n=0.\
1,&amp;\text{for } n=1.\
F(n-1)+ F(n-2),&amp;\text{otherwise.}
\end{cases}
$$
In plain English, any given Fibonacci number is equal to the sum of the previous two Fibonacci numbers in the sequence. The exceptions, of course, are the first two Fibonacci numbers, which are given as 0 and 1, respectively. Once you have the first two numbers in the sequence you can use the above rule to compute any other Fibonacci number.</p>
<p>To see how recursion might be used to find the $n$th Fibonacci number, you would begin at $n$, then you need to compute $F(n-1)$ and $F(n-2)$. To compute $F(n-1)$ you would compute $F(n-2)$ and $F(n-3)$ , and to compute $F(n-2)$ you would compute $F(n-3)$ and $F(n-4)$, and so on, until $n = 1$ and $n=0$, whose Fibonacci number are given by definition. So the first and second Fibonacci number serves as a base case. You can see the computation of $F(6)$ in the following picture.</p>
<p><img src="/CSC482/pic/fib_tree.png" alt="">{width=&ldquo;500&rdquo;     }</p>
<p>It is important to note that the Fibonacci sequence is a 0-based sequence. That is, the first number of the sequence, $F(0)$, is 0, the second number of the sequence, $F(1)$, is 1, the third number of the sequence, $F(2)$, is 1, and so on.</p>
<h2 id="euclid-s-algorithm">Euclid&rsquo;s Algorithm</h2>
<p>To find the GCD of two integers A and B:</p>
<ol>
<li>If A = 0 then GCD(A,B)=B, since the GCD(0,B)=B, and we can stop.</li>
<li>If B = 0 then GCD(A,B)=A, since the GCD(A,0)=A, and we can stop.</li>
<li>Write A in quotient remainder form (A = B·Q + R)</li>
<li>Find GCD(B,R) using the Euclidean Algorithm since GCD(A,B) = GCD(B,R)</li>
</ol>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">gcd</span>(a, b):
    <span style="color:#66d9ef">if</span> a <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>:
        <span style="color:#66d9ef">return</span> b
 
    <span style="color:#66d9ef">return</span> gcd(b <span style="color:#f92672">%</span> a, a)
</code></pre></td></tr></table>
</div>
</div><p>Euclid&rsquo;s Algorithm is a classical algorithm for finding the greatest common divisor (GCD) of two integers. The algorithm can be formally stated as follows:</p>
<p>For example, suppose you want to find the GCD of 72 and 54. The following illustrates how the algorithms works:</p>
<p>A = 72, B = 58</p>
<p>Find GCD(A, B), or GCD(72, 58):</p>
<p>A = B * Q + R: 72 = 58 * 1 + 14</p>
<p>Next we must find GCD(B, R). We use the same procedure as in the previous step. When we write the quotient form, we are essentially setting A = B and B = R. Each time we do this we will get a new value for B and a new value for R.</p>
<p>Find GCD(B, R), or GCD(54, 14):</p>
<p>54 = 14 * 3 + 12</p>
<p>Find GCD(B, R), or GCD(14, 12):</p>
<p>14 = 12 * 1 + 2</p>
<p>Find GCD(B, R), or GCD(12, 2):</p>
<p>12 = 2 * 6 + 0</p>
<p>Find GCD(B, R), or GCD(2, 0):</p>
<p>Since B = 0, we can stop, and say that GCD(2, 0), and therefore GCD(72, 58) = 2.</p>
<p>Euclid&rsquo;s Algorithm lends itself to a recursive solution since at each step we are solving a smaller version of the same problem. We are still solving GCD(A, B), we just keep reducing the values of A and B until one of them reaches 0, at which point we have a base case and can conclude that the GCD is whichever number, A or B, is not 0.</p>
<p>In this example, finding that GCD(72, 58) = 2 might appear to be in error since 2 is such a small value. However, 58 is the product of 2 and 29, both which are prime numbers and cannot be factored any further.</p>
<h2 id="the-towers-of-hanoi">The Towers of Hanoi</h2>
<p>The Towers of Hanoi is a classic problem or puzzle that appears in many CS textbooks. Given 3 pegs labeled A, B, and C, and a tower of N disks arranged on peg A such that the disks are stacked in descending order of diameter, as shown in the following diagram:</p>
<p><img src="/CSC482/pic/Towers_of_Hanoi.png" alt="">{width=&ldquo;500&rdquo;}</p>
<p>The problem is to move all N disks from peg A to another peg (peg C, for example) such that the following rules are always obeyed:</p>
<p>1.Only one disk may be moved at a time.
2.Only the topmost disk of a stack may be moved; i.e., a disk may not be moved until all the disks on top of that disk have been moved.
3.No disk ever has a larger disk stacked on top of it, on any peg.
4.Peg B may be used as a designated spare to temporarily hold disks.</p>
<p>You can find here a <a href="https://yifyan-yusuzech.shinyapps.io/tower_of_hanoi/">live demo</a>.</p>
<p>The ideal goal is to move all the disks from peg A to peg C using the fewest number of moves. The problem sounds simple, but developing an algorithm to solve it turns out to be somewhat complex. Using recursion, however, a relatively elegant solution can be designed to solve this problem. Keeping in mind the notion of repetitively going from a larger problem to a similar but smaller problem, a recursive solution by necessity needs to begin at the largest problem, which is moving disk 4 along with all the disks on top of it (i.e., the entire stack of disks) from peg A to peg C. We can think of the recursive solution as something like the following:</p>
<p>| Move 4 disks starting at disk 4 from peg A to peg C (can&rsquo;t do this directly since disk 4 has disks on top of it).</p>
<p>|   Move 3 disks starting at disk 3 from peg A to peg C (can&rsquo;t do this directly since disk 3 has disks on top of it).</p>
<p>|       Move 2 disks starting at disk 2 from peg A to peg C (can&rsquo;t do this directly since disk 2 has disks on top of it).</p>
<p>|           Move 1 disk starting at disk 1 from peg A to peg C (can do this — base case).</p>
<p>Once disk 1 has been moved to peg C (the spare peg), we have solved the simplest case of the problem, which is moving a single disk with no disks on top of it. We can return to the previous step, to move disk 2, which we can now move since it no longer has disk 1 on top of it. We move disk 2 to peg B, then move disk 1 from peg C to peg B. We have then solved the next highest case of the problem, which is moving 2 disks.</p>
<p>Generalizing the algorithm above is necessary to prevent problems that will arise if we specify pegs by name. We don&rsquo;t really care so much where we move the disks so long as we obey the rules of the problem. Either peg B or peg C can be used as the spare peg, as needed, and at times we may need to use peg A as a spare as well. So for each move we need to specify the source peg, the destination peg, and the spare peg, along with the number of disks to move. A generalized solution in Python might look something like this:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#75715e">## move n disk from &#34;source (s)&#34; peg to &#34;destinate (t)&#34; peg </span>
<span style="color:#75715e">## with the help of &#34;helper (h)&#34; peg</span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">Hanoi</span>(n, s, t, h):
    <span style="color:#66d9ef">if</span> n<span style="color:#f92672">==</span><span style="color:#ae81ff">1</span>:
        move(<span style="color:#ae81ff">1</span>,s,t)
    <span style="color:#66d9ef">else</span>:
        Hanoi(n<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>,s, h, t)
        move(n,s,t)
        Hanoi(n<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>,h,t,s)
        
<span style="color:#75715e"># move disk n form s to t</span>
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">move</span>(n,s,t):
    print(<span style="color:#e6db74">&#34;Move disk </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> from </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> to </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>format(n, s, t))

Hanoi(<span style="color:#ae81ff">4</span>,<span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#e6db74">&#34;B&#34;</span>,<span style="color:#e6db74">&#34;C&#34;</span>)
</code></pre></td></tr></table>
</div>
</div><h2 id="golomb-s-tromino-problem">Golomb&rsquo;s tromino Problem</h2>
<p>A unit square has been removed from a $2^n \times 2^n$ board. Gave an algorithm to tile the rest of the board with L-shaped trominos.</p>
<p>You can find the solution (and proof) in <a href="files/tiling.pdf">this document</a>.</p>
<h2 id="the-8-queens-problem">The 8 Queens Problem</h2>
<p>The 8 Queens problem can be stated as follows:</p>
<p><em>Given a 8x8 chessboard, place 8 queens on the chessboard such that no queen can capture another queen.</em></p>
<p>Put another way, no queen may share a row, column, or diagonal with another queen. The diagram below shows one possible solution to this problem:</p>
<p><img src="/CSC482/pic/eight-queens.png" alt="">{width=&ldquo;282&rdquo; height=&ldquo;282&rdquo;}</p>
<p>Other solutions are possible, but the problem only requires that we find a solution, it doesn&rsquo;t matter which one.</p>
<p>The problem is commonly formulated by representing the chessboard as a 8x8 array of integers:</p>
<pre>

0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
</pre>
<p>where a 1 indicates the presence of a queen on a square, and a 0 indicates no queen is present on that square. A solution to the problem would then look something like this:</p>
<pre>
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
</pre>
<p>The most straightforward approach to solving the problem is a <strong>brute-force search</strong>. We begin by placing a queen at (row = 0, col = 0), where (0,0) refers to the upper left corner of the 2D array. Then, for each row, including the row we are currently on, we shift one column to the right and see if we can place a queen there safely. In this case we would try to place a queen at (0, 1), which will fail since the queen can be captured by the queen we previously placed at (0,0). We continue incrementing the column and attempting placements until we reach the end of the row, at which point we must reset col to 0 and increment the row. This process continues until we either successfully place all 8 queens, or we encounter a situation where there is no square left to place the current queen. When this happens we must backtrack to the last queen that was placed, and remove it from that square, since having a queen in that particular square does not allow for a solution. We then move to the next possible location for the queen we just removed and see if we can place it at the new location. Eventually, either a solution will be found, or we will get the result that there is no solution given the parameters of the problem.</p>
<p>Conceptually, the process for placing the queens is easy to understand. What may not be immediately intuitive, though, is that backtracking is a naturally recursive process, and as such any problem that requires backtracking lends itself to a recursive solution. We need to think about each queen as being able to remember its own placement history independently of the placement of the other queens. If a queen is placed in a location that ultimately produces a board state from which a solution is not possible, that queen needs to be able to know where it left off in its placement history so that it can undo its current placement and move naturally to its next logical placement. Trying to implement this iteratively can be a complex and confusing task. However, the nature of recursion and how recursion uses a stack to keep track of its history makes recursion a good strategy for solving a problem like the 8 8Queens problem. We don&rsquo;t need to take special pains to keep track of each queen&rsquo;s placement history because the recursion does that for us automatically.</p>
<p>The recursive portion of a recursive solution the the 8 Queens problem can be described in pseudocode as shown below. The framework of representing the chessboard and the queens, as well as a function for determining whether a placement is safe or not, have been omitted for brevity.</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">Begin at row <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, col <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, N <span style="color:#f92672">=</span> <span style="color:#ae81ff">8</span> (where N <span style="color:#f92672">=</span> one dimension of the chessboard)

function placeQueen(row, col)

  <span style="color:#75715e">// base case: all queens placed
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">if</span> col <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">8</span> <span style="color:#66d9ef">return</span> True

  <span style="color:#75715e">// recursive case
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">for</span> row <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> to N <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>
    <span style="color:#66d9ef">if</span> safePlacement
    <span style="color:#75715e">// currently safe to place queen at (row, col)
</span><span style="color:#75715e"></span>      place queen at (row, col)

      <span style="color:#75715e">// recurse
</span><span style="color:#75715e"></span>      <span style="color:#66d9ef">if</span> placeQueen(row, col <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">==</span> True <span style="color:#66d9ef">return</span> True
      <span style="color:#75715e">// turns out placing queen at (row, col) did not lead to a solution,
</span><span style="color:#75715e"></span>      <span style="color:#75715e">// so remove queen from (row, col)
</span><span style="color:#75715e"></span>      remove queen from (row, col)

  <span style="color:#75715e">// queen cannot be placed safely in any row in current column
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">return</span> False
</code></pre></td></tr></table>
</div>
</div><p>One thing to note about a recursive backtracking solution such as this one is the efficiency of the algorithm. Since N = 8 in this case, we would expect the most efficient solution will require only 8 queen placements, one placement per queen. However, with backtracking there will be some trial and error involved before the solution is found, and this will result in a number of attempted queen placements that is greater than 8. The exact number of attempted placements will depend on several factors, including:</p>
<ol>
<li>
<p>Which square is tried first (in our example it is the square at location (0, 0), but it could be any one of the 64 squares on the board)</p>
</li>
<li>
<p>The nature of the successor function that determines the order in which the squares are tried (we&rsquo;ve opted for the straightforward left to right, top down order, but any ordering, even random ordering, would work)</p>
</li>
<li>
<p>Whether the safety check occurs after a queen is added (post-check) or before the queen is added (pre-check); pre-checking will require fewer actual queen placements than will post-checking</p>
</li>
</ol>
<p>Thus, computing the efficiency of a backtracking algorithm is not a trivial process.</p>
<h2 id="solving-a-maze">Solving a Maze</h2>
<p>Mazes are another type of problem in which backtracking plays a key role in finding a solution. The basic principles are very similar to those of the 8 Queens problem, so I will just give a general description here.</p>
<p>When attempting to solve a maze, the key is determining the correct sequence of branchpoints to take. When the only move is to move forward, there are no decisions to be made. When there is a branchpoint, however, in the absence of any information leading us to favor one branch over the others, finding the correct branch will be trial and error. We choose one branch path and proceed until we encounter another branchpoint, a dead end, or the maze exit. Both the maze exit and a dead end are considered base cases. Finding the exit means we have solved the maze. Finding a dead end forces us to backtrack to the most recent branchpoint, where we then proceed down a different branch until we find the exit, a dead end, or another branchpoint, and so on.</p>
<p>Comparing the maze to the 8 Queens problem, each branchpoint in the maze is analogous to a queen. Selecting the correct branch in a maze equates to placing a queen safely. One way in which the two problems differ is that there are multiple solutions to the 8 Queens problem, all of which have the same intrinsic value. A maze, however, often has only one path from the entrance to the exit, so finding the correct path through the maze is equivalent to finding one specific solution to the 8 Queens problem.</p>
<p>As with the recursive solution to the 8 Queens problem, the efficiency of a recursive backtracking solution to solving a maze will depend on a number of factors, including:</p>
<ol>
<li>
<p>The number of branchpoints in the maze. More branchpoints increase the complexity of the problem, and will generally increase the time needed to find a solution.</p>
</li>
<li>
<p>The order in which the branchpoints are taken. For example, if left branchpoints are always attempted first, but only the right branchpoints are the correct ones to take, a left-centric algorithm will be less efficient than a right-centric algorithm.</p>
</li>
</ol>
<h2 id="depth-first-searching">Depth-first Searching</h2>
<p>Depth-first searching is a general search algorithm that applies to tree and graph structures, and any structure that resembles a tree or graph. The problem with searching branched structures like trees and graphs is that it usually isn&rsquo;t known beforehand what the depth of the structure is, or whether the branching is consistent. When the depth is arbitrary, trying to use an iterative solution can be problematical since you don&rsquo;t know when you have hit the end of a branch. Thus, depth-first searches, like maze-solving algorithms, are naturally suited to being implemented recursively.</p>
<h1 id="relationship-between-recursion-recurrence-relations-and-induction">Relationship Between Recursion, Recurrence Relations, and Induction</h1>
<p>Recursion has its basis in mathematics in the form of recurrence relations. A recurrence relation is a relation that is defined in terms of itself (much like a recursive method calls itself). In general, a recurrence relation requires 2 elements:</p>
<ol>
<li>One or more predefined terms that serve as the initial case, or boundary condition.</li>
<li>A rule for defining the next term in the relation based on the value(s) of previously defined terms.</li>
</ol>
<p>Recurrence relations typically define sequences of numbers. The Fibonacci sequence can be defined using a recurrence relation, as can the sequence of factorial numbers, and the sequence of counting numbers, to name just a few. As an example, let&rsquo;s look at the recurrence relation that defines the factorial function. Loosely defined, we can say that n! is the product of an integer n and all the integer values less than n, but greater than 0. So, if n = 5, n! = 5 * 4 * 3 * 2 * 1 = 120. This is easy to understand in plain English, but we need to be a bit more formal if we want to define the factorial operation as a recurrence relation.</p>
<p>To define n! as a recurrence relation we first need to define the boundary condition. We know the recurrence relation has to be able to define the next term in the sequence in terms of the relation itself, but in order to do that we must have at least one predefined value. For n! we can define the boundary condition as n = 1. The sequence used in calculating n! never goes less than 1, so using 1! as the boundary condition is appropriate. We can now write a more formal definition of n! as a recurrence relation:</p>
<ul>
<li>Boundary Case:	$a_1 = 1$</li>
<li>General Case:	$a_n = n * a_{n-1}$, for all n &gt; 1</li>
</ul>
<p>So we have a rule for defining $n!$, and if we look at a few values we can see that the relation holds for $n = 2$, $n = 3$, and $n = 4$. It seems like it should hold for all integers $n &gt; 1$, but we need to prove the general case before we can be assured our rule is correct. To prove a recurrence relation we need to use a technique known as mathematical induction.</p>
<p>The basic principle behind using mathematical induction to prove a recurrence relation is that, given both the boundary and the general case, we assume the relation holds for some arbitrary value, $k$. We then show that the relation also holds for the value $k + 1$. The idea is that if we can show that the recurrence relation holds for two arbitrary consecutive values, $k$ and $k + 1$, inductive logic states that the relation will hold for all values within the specified range, in this case all positive integer values.</p>
<p>As an example, let&rsquo;s look at how to use an inductive proof to show that $1 + 2 + 3 + &hellip; + n = \frac{n(n + 1)}{2}$, a counting formula commonly used to express the efficiency of a nested loop.</p>
<p><strong>Proof by Induction that $1 + 2 + 3 + &hellip; + n =\frac{n(n + 1)}{2}$</strong></p>
<p>Let $P(n) \equiv 1 + 2 + 3 + &hellip; + n = \frac{n(n + 1)}{2}$</p>
<p><strong>Boundary Case</strong>:</p>
<p>When n = 1, the left hand side of P(n) equals 1 and the right-hand side of P(n) equals 1(1 + 1)/2 = 1. Therefore, P(1) is true.</p>
<p><strong>Inductive Hypothesis</strong>:</p>
<p>Assume that $P(k) = \frac{k(k + 1)}{2}$ for some positive integer, k. That is, show that $1 + 2 + 3 + \cdots + k =\frac{k(k + 1)}{2}$</p>
<p><strong>Induction Step</strong>:</p>
<p>Show that $P(k + 1) = \frac{(k + 1)(k + 2)}{2}$. That is, show that $1 + 2 + 3 + &hellip; + k + k + 1 = \frac{(k + 1)(k + 2)}{2}$</p>
<p><strong>Proof:</strong></p>
<p>We begin by writing out $P(k + 1)$:</p>
<p>$$
P(k + 1) = 1 + 2 + 3 + &hellip; + k + (k + 1)
$$</p>
<p>Our goal is to make this sequence equal to the right-hand side of the inductive step, $\frac{(k + 1)(k + 2)}{2}$.</p>
<p>Step 1: Group terms</p>
<p>Using parentheses we can rewrite the left-hand side as:</p>
<p>$$P(k + 1) = (1 + 2 + 3 + &hellip; + k) + (k + 1)$$</p>
<p>This does not change the sequence, it merely separates the sequence into the sum of two groups of terms.</p>
<p>Step 2: Use the inductive hypothesis to substitute for the leftmost group of terms</p>
<p>Our inductive hypothesis states that $1 + 2 + 3 + &hellip; + k = \frac{k(k + 1)}{2}$, so we can substitute for the left-hand group of terms to give:</p>
<p>P(k + 1) = k(k + 1)/2 + (k + 1)</p>
<p>Step 3: Place the right hand side of P(k + 1) under a common denominator</p>
<p>The next step is to simplify the right-hand side of P(k + 1) by putting both terms over a common denominator. Doing so gives:</p>
<p>P(k + 1) = [k(k + 1) + 2(k + 1)] / 2</p>
<p>Step 4: Use factoring to further simplify the right hand side</p>
<p>In the numerator of the right-hand side we see a common term, (k + 1), so we can further simplify by factoring out this term to give:</p>
<p>$$P(k + 1) = \frac{(k + 1)(k + 2) }{2}$$</p>
<p>The right-hand side of P(k + 1) now matches the right-hand side from the inductive step.</p>
<p>Conclusion:</p>
<p>$P(k + 1)$ is true. Therefore, $P(n) = \frac{n(n + 1)}{2}$for all n &gt; 0.</p>
<h1 id="structure-of-a-recursive-algorithm">Structure of a Recursive Algorithm</h1>
<p>Imperative programming languages use methods or functions that may contain a number of variables whose scope is local to a given method, and the values of those local variables can change depending on the logic contained in the method. Execution of a program involves a sequence of method invocations. The state of each method invocation must be stored in memory to ensure execution within the method continues correctly when the overall flow of execution comes back to that method. Every time a method is invoked, a record of the method invocation is added to the stack frame for that method. The record contains the values of the input parameters, the values for any local variables declared within the method, and address where execution should continue when the method terminates.</p>
<p>Practically speaking, a recursive algorithm involves a method or function that calls itself with the parameters necessary to specify the next smallest problem size. Strictly speaking, a recursive method does not actually call itself, but rather calls another instance of the same method. Like all other method invocations, when a recursive method calls itself another record is added to the method&rsquo;s stack frame, but with different values for the parameters and local variables.</p>
<p>A simple example will illustrate how the structure of a recursive method uses the stack frame. The following example uses a recursive algorithm to compute the $3$rd Fibonacci number, and uses a technique known as the box trace technique to show how the stack frame is used. The code for the recursive method is as follows:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">7
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-python" data-lang="python"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fib</span>(n)
{
    <span style="color:#66d9ef">if</span> (n <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">1</span>)
       <span style="color:#66d9ef">return</span> n;
    <span style="color:#66d9ef">else</span>
       <span style="color:#66d9ef">return</span> fib(n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>) <span style="color:#f92672">+</span> fib(n <span style="color:#f92672">-</span> <span style="color:#ae81ff">2</span>);
}
</code></pre></td></tr></table>
</div>
</div><p>There are 2 base cases for this algorithm, which correspond to the first two Fibonacci numbers, 0 and 1. (Recall that the first two Fibonacci numbers must be pre-defined, since you need to already have at least two numbers in order to compute the next number in the sequence.) Every other case for n &gt; 1 is thus a recursive case. The diagram below shows how the box trace technique might be used to represent the stack frame as the algorithm&rsquo;s execution is manually traced. Keep in mind that the stack frame actually would just look like a single column, as records are pushed onto and popped off the stack. I have expanded the stack frame sideways to better illustrate both the past and current changes to the local variables and return values.</p>
<p><img src="/CSC482/pic/box_trace.png" alt=""></p>
<p>In reality, for this example the stack frame would have at most 3 records, since each recursive call will eventually be replaced by a return value when one recursive call hits a base case. Following each row in the diagram from left to right shows chronologically how each of the 3 records changes as the algorithm progresses. When both recursive calls in the first record have been replaced by literal values, the recursion is over, and the computed value can be returned.</p>
<h1 id="fundamental-rules-for-using-recursion">Fundamental Rules for Using Recursion</h1>
<p>There are 4 fundamental rules, or guidelines that must be observed when designing any recursive algorithm:</p>
<ol>
<li><strong>There must be a base case that can be solved without using recursion.</strong></li>
</ol>
<p>The recursive process is used to simplify a complex problem by breaking it into a similar but smaller problem. At some point, however, this decomposition process must result in a smaller problem that can be solved directly, without using recursion. This smaller problem, or base case as it is called, essentially serves to put the brakes on the recursion and allow the solution to the smaller problem to be used to solve the next largest problem. Without a base case the recursion will proceed indefinitely, or practically speaking, until the computer&rsquo;s storage capacity is exhausted. There is no hard and fast rule to how many base cases a recursive solution must have. Most contain only a single base case, but some contain multiple base cases.</p>
<ol start="2">
<li><strong>Every recursive call must progress towards the base case.</strong></li>
</ol>
<p>The basic tenet of recursion is that a complex problem is simplified by breaking it into a smaller, but similar problem. Therefore, any recursive solution must progress from a larger or more complex problem to a smaller, simpler problem. If this is not the case, infinite recursion will result.</p>
<ol start="3">
<li><strong>Always assume the recursive calls will work.</strong></li>
</ol>
<p>This rule seems counterintuitive since we are often taught the dangers of making assumptions. To clarify, this rule does not mean to simply assume your recursive algorithm is correct. It simply means that if you know the base case is handled correctly, and you have verified your algorithm works for several larger problem sizes, you can assume the logic of the algorithm will continue to work correctly down to the base case. This assumption is a natural extension of inductive proofs, a strategy that has already been proven to be sound mathematically. Thus, you do not need to prove a recursive algorithm will work for every possible problem size. This assumption does not account for limitations with respect to computer hardware or programming languages, however. A perfectly sound recursive algorithm may be rendered useless if it exhausts the storage capacity of a computer, or if it must use data values that are beyond the capacity of a particular programming language to represent.</p>
<ol start="4">
<li><strong>If you have multiple recursive calls in an algorithm, make sure they don&rsquo;t solve the same instance of a problem more than once.</strong></li>
</ol>
<p>In some cases, when a recursive solution contains more than one recursive call, it is possible that the inputs to one recursive call will overlap the inputs used in a previous recursive call. This results in the same instance of a problem being solved more than once by the algorithm, which can significantly reduce the algorithm&rsquo;s efficiency.</p>
<h1 id="direct-recursion-vs-indirect-recursion">Direct Recursion vs. Indirect Recursion</h1>
<p>Most of the time when we write a recursive algorithm we have a method that directly calls itself. This is an example of <strong>direct recursion</strong>. It is also possible to have one method call another method, which in turn calls the first method. This is an example of <strong>indirect recursion</strong>, since in this case no method directly calls itself. Any number of methods could lie between the initial method call and the method that eventually calls the initial method. A simple example of indirect recursion is an algorithm that traverses a directory structure in a file system, as shown in the following pseudocode:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">displayDirectoryContents(Directory d)
{
    <span style="color:#66d9ef">if</span> d is a valid Directory
        processDirectory(d)
    <span style="color:#66d9ef">else</span>
        print error message
}

processDirectory(d)
{
    <span style="color:#66d9ef">for</span> each item in d
    {
        print filename of item

        <span style="color:#66d9ef">if</span> item is a directory
            displayDirectoryContents(item)
    }
}

</code></pre></td></tr></table>
</div>
</div><p>In this case it really isn&rsquo;t necessary to use indirect recursion, as this algorithm can easily be written using direct recursion, but this example is enough to illustrate what indirect recursion looks like.</p>
<h1 id="tail-recursion">Tail Recursion</h1>
<p>Tail recursion, sometimes called &ldquo;tail call&rdquo;, is a form of recursion where the last statement of a recursive method is the recursive call. Consider the following recursive algorithms for computing factorial values:</p>
<p><strong>Standard Recursion</strong></p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">factorial</span>(<span style="color:#66d9ef">int</span> n)
{
    <span style="color:#66d9ef">int</span> r;

    <span style="color:#66d9ef">if</span> (n <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">1</span>)
        r <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>;
    <span style="color:#66d9ef">else</span>
        r <span style="color:#f92672">=</span> n <span style="color:#f92672">*</span> factorial(n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>);

    <span style="color:#66d9ef">return</span> r;
}
</code></pre></td></tr></table>
</div>
</div><p><strong>Tail Recursion</strong></p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">factorial</span>(<span style="color:#66d9ef">int</span> n)
{
    <span style="color:#66d9ef">return</span> tail_factorial(<span style="color:#ae81ff">1</span>, n);
}

<span style="color:#66d9ef">int</span> <span style="color:#a6e22e">tail_factorial</span>(<span style="color:#66d9ef">int</span> m, <span style="color:#66d9ef">int</span> n)
{
    <span style="color:#66d9ef">if</span> (n <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">1</span>)
        <span style="color:#66d9ef">return</span> m;

    <span style="color:#66d9ef">return</span> tail_factorial(m <span style="color:#f92672">*</span> n, n <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>);
} 
</code></pre></td></tr></table>
</div>
</div><p>In the standard recursive algorithm, the stack frame will fill with records since the recursive case of the problem cannot be evaluated until the base case is reached. Each record will contain a pending computation of n * factorial(n - 1). Once the base case is reached, and execution proceeds back up through the stack, all the pending computations can be quickly resolved, but there is inherent inefficiency in having all the unresolved recursive calls on the stack.</p>
<p>The tail recursive algorithm avoids the problem of storing unresolved recursive calls at the expense of some extra code. The original factorial(int n) method now uses a helper method that takes an additional argument to store the current product in the calculation. Using the tail recursive algorithm there will be no unresolved recursive calls waiting on the stack. This avoids the problem of exhausting the available stack space. Also, many compilers are capable of optimizing tail recursion by converting the recursion into a loop, so although the source code may be recursive, the compiled code is not.</p>
<p>While tail recursion would seem to be the de facto standard when implementing a recursive algorithm based on these benefits, it may not always be easy to implement tail recursion for every recursive problem. Additionally, using tail recursion may result in code that is somewhat more difficult to understand.</p>
<h2 id="efficiency-of-recursive-algorithms">Efficiency of Recursive Algorithms</h2>
<p>While recursive algorithms are elegant in terms of the simplicity of their logic, they are not particularly efficient. The available stack space memory of a computer determines how deep a recursive algorithm can go. The amount of data that must be stored for each record in the stack frame also plays a role. The less space required for local variables, the more records there can be, and thus the deeper the recursion can go. Depending on the limitations of the available stack space, it may be that a recursive algorithm will not work, simply because there aren&rsquo;t enough resources to accommodate the storage of all the recursive calls.</p>
<p>The running time of a recursive algorithm is often difficult to determine, as it may or may not match what one would expect from an inspection of the problem. Using the Fibonacci example, an iterative solution to find the nth Fibonacci number should require no more than n - 1 computations (since both $F_0$ and $F_1$ are given):</p>
<p>$F_2 = F_1 + F_0 = 1 + 0 = 1$  (n = 2; 1 computation)</p>
<p>$F_3 = F_2 + F_1 = 1 + 1 = 2$   (n = 3; 2 computations)</p>
<p>$F_4 = F_3 + F_2 = 2 + 1 = 3$   (n = 4; 3 computations)</p>
<p>If we look at the recursive solution shown in the box trace diagram, we see that the value for the first Fibonacci number is returned twice when computing the 3rd Fibonacci number. Although the box trace example doesn&rsquo;t show it, this redundancy in computation increases exponentially as n increases.</p>
<h2 id="recursion-vs-iteration">Recursion vs. Iteration</h2>
<p>Generally speaking, an iterative solution is preferable to a recursive one. Recursion is typically used to develop relatively simple, elegant solutions to complex problems where the formulation of an iterative solution proves to be very difficult. There are a number of pitfalls associated with using recursion. As previously mentioned, an improperly designed recursive algorithm may result in infinite recursion, or redundantly solve the same instance of a problem repeatedly. Even a well formed recursive solution may prove to be unworkable. There is a limit to the number of recursive calls that can practically be made, depending on the storage capacity of the computer running the algorithm and the amount of information that must be stored in each activation record on the call stack.</p>
<p>Iterative solutions are generally more efficient than recursive solutions, in terms of both storage usage and running time. One issue common to recursive algorithms is that once a base case has been reached, execution must proceed back up the call stack. This tends to cause a performance hit, although with modern computer hardware the hit is not as noticeable as it was in timed past.</p>
<p>As a rule, any problem that can be solved recursively can also be solved iteratively. An iterative solution will usually be faster and require less storage than a recursive algorithm. However, an iterative solution to a problem that can be solved easily using recursion often requires a great deal more logic, and this logic may be significantly more convoluted and subsequently error-prone.</p>

        
        ]]>
      </description>
    </item>
    
    
    
    <item>
      <title>A Hanoi Tower Variation</title>
      <link>https://xianghuang.me/course/teaching/hanoi/</link>
      <pubDate>Sun, 29 Mar 2020 00:00:00 +0000</pubDate>
      
      <guid>https://xianghuang.me/course/teaching/hanoi/</guid>
      <description>
        <![CDATA[
        <div class="toc">
<nav id="TableOfContents">
  <ul>
    <li>
      <ul>
        <li><a href="#the-variation">The Variation</a></li>
        <li><a href="#pseudo-code-for-the-core-function">Pseudo-code for the core function:</a></li>
        <li><a href="#algorithm-analysis">Algorithm Analysis:</a>
          <ul>
            <li><a href="#detailed-solution-for-g-n">Detailed Solution for $ g(n) $:</a></li>
            <li><a href="#detailed-solution-for-f-n">Detailed Solution for $ f(n) $:</a></li>
            <li><a href="#output-for-n-3">Output for $n=3$:</a></li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>
</nav>
</div>



<p>It is challenging to teach students recursion, especially in an introductory course where students are not yet familiar with complex data structures. Therefore, teaching concepts like searching on a tree might be premature. I realized why we often start with the Hanoi Tower problem when introducing recursive algorithms.</p>
<p>It&rsquo;s an excellent problem for teaching because:</p>
<ul>
<li>It doesn&rsquo;t involve complex data structures.</li>
<li>The problem itself is an interesting game.</li>
<li>It illustrates beautiful recursive ideas.</li>
</ul>
<p>In the past, I have used this problem to introduce recursion. I tried to add a twist by assigning them a variation of the problem as an assignment.</p>
<h2 id="the-variation">The Variation</h2>
<p><strong>If all moves must be between adjacent pegs (i.e., given pegs A, B, C, one cannot move directly between pegs A and C, and vice versa), how should we write the recursive function?</strong></p>
<p>Consider we want to move a tower of &lsquo;n&rsquo; from a peg named “from” to another peg “to” by using the peg “aux”, that is:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java">move<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">)</span>
</code></pre></td></tr></table>
</div>
</div><p>We need to ensure the condition:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java">not <span style="color:#f92672">(</span>from <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;A&#34;</span> and to <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;C&#34;</span> or from <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;C&#34;</span> and to <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;A&#34;</span><span style="color:#f92672">)</span>
</code></pre></td></tr></table>
</div>
</div><p>Or equivalently:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java">not <span style="color:#f92672">(</span>aux <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;B&#34;</span><span style="color:#f92672">).</span>
</code></pre></td></tr></table>
</div>
</div><p>If the auxiliary peg is not B, the task is straightforward. We proceed as in the classic Hanoi Tower solution:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">3
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java">move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">)</span>
moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> to<span style="color:#f92672">)</span>
move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> from<span style="color:#f92672">)</span>
</code></pre></td></tr></table>
</div>
</div><p>Here, <code>moveDisk()</code> function moves disk #n from “from” to “to”.</p>
<p>If the auxiliary peg is B, the process becomes more complex, as demonstrated below:</p>
<img src="/CSC482/pic/Hanoi/Hanoi.webp" alt="Moving a distance of two." style="border: 2px solid  gray;">
<p>Question arises: How can we move from A to C directly? This is where our recursive function comes into play. We assume it is correct. It is not the <code>moveDisk()</code> function where we move one disk directly and are bound by the moving rule immediately.</p>
<h2 id="pseudo-code-for-the-core-function">Pseudo-code for the core function:</h2>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java">move<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">):</span>
  <span style="color:#66d9ef">if</span> n<span style="color:#f92672">==</span>0<span style="color:#f92672">:</span> <span style="color:#66d9ef">return</span>
  <span style="color:#66d9ef">if</span> aux<span style="color:#f92672">!=</span><span style="color:#e6db74">&#34;B&#34;</span><span style="color:#f92672">:</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">)</span>
    moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> to<span style="color:#f92672">)</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> from<span style="color:#f92672">)</span>
  <span style="color:#66d9ef">else</span><span style="color:#f92672">:</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span>from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">)</span>
    moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">)</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">)</span>
    moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">)</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">)</span>
</code></pre></td></tr></table>
</div>
</div><p><strong>Java Implementation:</strong></p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">27
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">28
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">29
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">30
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">31
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">32
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">33
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">34
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">35
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">36
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">37
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">38
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">39
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#f92672">import</span> java.util.Scanner<span style="color:#f92672">;</span>
<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Hanoi_2</span> <span style="color:#f92672">{</span>
  <span style="color:#75715e">// Main method
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
    <span style="color:#75715e">// Create a Scanner
</span><span style="color:#75715e"></span>    Scanner input <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Scanner<span style="color:#f92672">(</span>System<span style="color:#f92672">.</span><span style="color:#a6e22e">in</span><span style="color:#f92672">);</span>
    System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">print</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Enter number of disks: &#34;</span><span style="color:#f92672">);</span>
    <span style="color:#66d9ef">int</span> n <span style="color:#f92672">=</span> input<span style="color:#f92672">.</span><span style="color:#a6e22e">nextInt</span><span style="color:#f92672">();</span>
    <span style="color:#75715e">// Find the solution recursively
</span><span style="color:#75715e"></span>    System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;The moves are:&#34;</span><span style="color:#f92672">);</span>
    move<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;A&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;C&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;B&#39;</span><span style="color:#f92672">);</span>
    input<span style="color:#f92672">.</span><span style="color:#a6e22e">close</span><span style="color:#f92672">();</span>
  <span style="color:#f92672">}</span>
  
  <span style="color:#75715e">// The method for finding the solution to move n disks
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// from fromTower to toTower with auxTower
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">move</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> n<span style="color:#f92672">,</span> <span style="color:#66d9ef">char</span> from<span style="color:#f92672">,</span> <span style="color:#66d9ef">char</span> to<span style="color:#f92672">,</span> <span style="color:#66d9ef">char</span> aux<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
    <span style="color:#75715e">// Simplified stop condition. Goes through one more recursive step
</span><span style="color:#75715e"></span>    <span style="color:#75715e">// than the previous solution.
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>n <span style="color:#f92672">==</span> 0<span style="color:#f92672">)</span> <span style="color:#75715e">// Stopping condition
</span><span style="color:#75715e"></span>      <span style="color:#66d9ef">return</span><span style="color:#f92672">;</span>
    <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>aux<span style="color:#f92672">!=</span><span style="color:#e6db74">&#39;B&#39;</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
        move<span style="color:#f92672">(</span>n <span style="color:#f92672">-</span> 1<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">);</span>
        moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span>from<span style="color:#f92672">,</span> to<span style="color:#f92672">);</span>
        move<span style="color:#f92672">(</span>n <span style="color:#f92672">-</span> 1<span style="color:#f92672">,</span> aux<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> from<span style="color:#f92672">);</span>
    <span style="color:#f92672">}</span>
    <span style="color:#66d9ef">else</span> <span style="color:#f92672">{</span>   
        move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span>from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">);</span>
        moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span>from<span style="color:#f92672">,</span> aux<span style="color:#f92672">);</span>
        move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span>to<span style="color:#f92672">,</span> from<span style="color:#f92672">,</span> aux<span style="color:#f92672">);</span>
        moveDisk<span style="color:#f92672">(</span>n<span style="color:#f92672">,</span>aux<span style="color:#f92672">,</span>to<span style="color:#f92672">);</span>
        move<span style="color:#f92672">(</span>n<span style="color:#f92672">-</span>1<span style="color:#f92672">,</span>from<span style="color:#f92672">,</span> to<span style="color:#f92672">,</span> aux<span style="color:#f92672">);</span>
    <span style="color:#f92672">}</span>
  <span style="color:#f92672">}</span>
  
  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">moveDisk</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> n<span style="color:#f92672">,</span> <span style="color:#66d9ef">char</span> from<span style="color:#f92672">,</span> <span style="color:#66d9ef">char</span> to<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
    System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Move disk &#34;</span> <span style="color:#f92672">+</span> n <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34; from &#34;</span> <span style="color:#f92672">+</span> from <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34; to &#34;</span> <span style="color:#f92672">+</span> to<span style="color:#f92672">);</span>
  <span style="color:#f92672">}</span>
<span style="color:#f92672">}</span>
</code></pre></td></tr></table>
</div>
</div><h2 id="algorithm-analysis">Algorithm Analysis:</h2>
<p>How many steps does it take to move a tower of n from one place to another? Before we answer this, we must consider the starting and ending points, as there are obviously two different scenarios:</p>
<ol>
<li>The steps needed when the distance from source and destination is 1.</li>
<li>The steps needed when the distance is 2.</li>
</ol>
<p>Let:</p>
<ul>
<li>$f(n)$ be the number of steps needed to move a tower of n when the moving distance is 1.</li>
<li>$g(n)$ be the number of steps needed to move a tower of n when the moving distance is 2.</li>
</ul>
<p>Observing the pseudo-code of the core function, we have:</p>
<p>\[ f(n) = g(n-1) + f(n-1) + 1 \]
\[ g(n) = 3g(n-1) + 2 \]</p>
<h3 id="detailed-solution-for-g-n">Detailed Solution for $ g(n) $:</h3>
<p>We define a new function $ h(n) = g(n) + 1 $. The recurrence relation for $ g(n)$ becomes:</p>
<p>\[ h(n) - 1 = 3(h(n-1) - 1) + 2 \]</p>
<p>Simplifying this gives:</p>
<p>\[ h(n) = 3h(n-1) \]</p>
<p>Using the base case $ h(0) = g(0) + 1 = 1 $, we find:</p>
<p>\[ h(n) = 3^n \]</p>
<p>Substituting back for $ g(n) $:</p>
<p>\[ g(n) = h(n) - 1 \]
\[ g(n) = 3^n - 1 \]</p>
<h3 id="detailed-solution-for-f-n">Detailed Solution for $ f(n) $:</h3>
<p>Using the solution for $ g(n)$, we can solve $f(n)$:</p>
<p>\[ f(n) = (3^{n-1} - 1) + f(n-1) + 1 \]</p>
<p>Recognizing this as a geometric series, we can express it as:</p>
<p>\[ f(n) = \frac{3^n - 1}{2} \]</p>
<h3 id="output-for-n-3">Output for $n=3$:</h3>
<p>When $n=3$, the sequence of moves for the Hanoi Tower variation is as follows:</p>
<div class="highlight"><div style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">
<table style="border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 2
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 3
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 4
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 5
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 6
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 7
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 8
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 9
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">10
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">11
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">12
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">13
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">14
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">15
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">16
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">17
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">18
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">19
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">20
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">21
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">22
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">23
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">24
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">25
</span><span style="margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f">26
</span></code></pre></td>
<td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%">
<pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-plaintext" data-lang="plaintext">1. Move disk 1 from A to B
2. Move disk 1 from B to C
3. Move disk 2 from A to B
4. Move disk 1 from C to B
5. Move disk 1 from B to A
6. Move disk 2 from B to C
7. Move disk 1 from A to B
8. Move disk 1 from B to C
9. Move disk 3 from A to B
10. Move disk 1 from C to B
11. Move disk 1 from B to A
12. Move disk 2 from C to B
13. Move disk 1 from A to B
14. Move disk 1 from B to C
15. Move disk 2 from B to A
16. Move disk 1 from C to B
17. Move disk 1 from B to A
18. Move disk 3 from B to C
19. Move disk 1 from A to B
20. Move disk 1 from B to C
21. Move disk 2 from A to B
22. Move disk 1 from C to B
23. Move disk 1 from B to A
24. Move disk 2 from B to C
25. Move disk 1 from A to B
26. Move disk 1 from B to C
</code></pre></td></tr></table>
</div>
</div><p>This sequence shows all the steps needed to move a tower of 3 disks from peg A to peg C using the variation of the rules where each move must be between adjacent pegs.</p>
<hr>

        
        ]]>
      </description>
    </item>
    
    
  </channel>
</rss>
