<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Mr Philomath: Quantum]]></title><description><![CDATA[Entangled thoughts and thoughts on entanglement]]></description><link>https://www.malharmanek.com/s/quantum</link><image><url>https://substackcdn.com/image/fetch/$s_!IHM2!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0f582fa-bde0-48af-8430-086182b9c844_360x360.png</url><title>Mr Philomath: Quantum</title><link>https://www.malharmanek.com/s/quantum</link></image><generator>Substack</generator><lastBuildDate>Fri, 28 Aug 2026 07:47:39 GMT</lastBuildDate><atom:link href="https://www.malharmanek.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Malhar Manek]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[malharmanek@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[malharmanek@substack.com]]></itunes:email><itunes:name><![CDATA[Malhar Manek]]></itunes:name></itunes:owner><itunes:author><![CDATA[Malhar Manek]]></itunes:author><googleplay:owner><![CDATA[malharmanek@substack.com]]></googleplay:owner><googleplay:email><![CDATA[malharmanek@substack.com]]></googleplay:email><googleplay:author><![CDATA[Malhar Manek]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[HGP Codes in Python]]></title><description><![CDATA[Reproducing some results from a quantum computing paper]]></description><link>https://www.malharmanek.com/p/hgp-python</link><guid isPermaLink="false">https://www.malharmanek.com/p/hgp-python</guid><dc:creator><![CDATA[Malhar Manek]]></dc:creator><pubDate>Sun, 23 Aug 2026 07:08:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZMbj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In 2024, Nature Physics published a <a href="https://www.nature.com/articles/s41567-024-02479-z">paper</a> by Qian Xu, J. Pablo Bonilla Ataides and others titled <em>Constant-overhead fault-tolerant quantum computation with reconfigurable atom arrays</em> &#8212; a proposal to implement hypergraph product codes on neutral atom arrays.</p><p>The key insight, as the paper puts it, is that -</p><blockquote><p>The product structure of one of the prototypical qLDPC codes, HGP codes, naturally matches the product structure of crossed AOD optical hardware, enabling its hardware-efficient implementation</p></blockquote><p>I wrote some Python code to reproduce a few of the paper&#8217;s results, and this article explains it. The code of my work can be found at the <a href="https://github.com/mhmanek/hgp-codes">GitHub repository</a>.</p><div><hr></div><p>The paper&#8217;s methods section provides the formula for computing the hypergraph product of two classical codes:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZMbj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZMbj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 424w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 848w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 1272w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZMbj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png" width="518" height="372.90909090909093" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:586,&quot;width&quot;:814,&quot;resizeWidth&quot;:518,&quot;bytes&quot;:113639,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZMbj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 424w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 848w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 1272w, https://substackcdn.com/image/fetch/$s_!ZMbj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F30f76df3-5d8b-432d-a7e4-0bad5d175d1e_814x586.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>To implement this, I wrote the hypergraph function:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;602f1def-a467-4609-9ebc-f0391e770d2b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def hypergraph(H1, H2):
    """Hypergraph product of two classical codes. Returns (Hx, Hz)."""
    H1 = H1.copy().astype(np.uint8) % 2
    H2 = H2.copy().astype(np.uint8) % 2
    r1, n1 = H1.shape
    r2, n2 = H2.shape
    def I(k):
        return np.eye(k, dtype=np.uint8)
    Hx = np.hstack([np.kron(np.transpose(H1), I(r2)),
                    np.kron(I(n1), H2)])
    Hz = np.hstack([np.kron(I(r1), np.transpose(H2)),
                    np.kron(H1, I(n2))])
    return Hx, Hz</code></pre></div><p>But which classical codes do we feed as inputs to this function? The paper then tells us exactly which classical codes we are HGP-ing together:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!A9Cg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!A9Cg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 424w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 848w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 1272w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!A9Cg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png" width="632" height="362.1485148514852" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:463,&quot;width&quot;:808,&quot;resizeWidth&quot;:632,&quot;bytes&quot;:123706,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!A9Cg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 424w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 848w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 1272w, https://substackcdn.com/image/fetch/$s_!A9Cg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5c75212-669d-47b8-ba1d-77ccebf173cb_808x463.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So we generate a random (3, 4)-regular Tanner graph and look at the corresponding parity check matrix. To do this, I defined the function regular_seed:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;36dc83c9-7aa9-4e0e-83a3-622237b61a1d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def regular_seed(n_bits, wc=3, wr=4, seed=0):
    """Random (wc, wr)-regular parity check matrix"""
    assert (n_bits * wc) % wr == 0
    r = n_bits * wc // wr
    bit_stubs   = np.repeat(np.arange(n_bits), wc)   # [0,0,0,1,1,1,2,2,2,...]
    check_stubs = np.repeat(np.arange(r), wr)        # [0,0,0,0,1,1,1,1,2,2,2,2,...]
    rng = np.random.default_rng(seed)
    while True:
        rng.shuffle(bit_stubs)
        H = np.zeros((r, n_bits), dtype=np.uint8)
        for i in range(n_bits * wc):
            H[check_stubs[i], bit_stubs[i]] += 1
        if np.all(H &lt;= 1):
            break
    assert np.all(np.sum(H, axis=0) == wc) # assert the column sums are all wc
    assert np.all(np.sum(H, axis=1) == wr) # assert the row sums are all wr
    return H</code></pre></div><p>But the condition &#8220;(3, 4)-regular Tanner graph&#8221; specifies an entire ensemble of classical codes. The regular_seed function just produced a random matrix from the ensemble. What if we want to produce a particular matrix from the ensemble that also satisfies some <em><strong>good properties</strong></em>? Indeed, the paper suggests the following criteria:</p><ol><li><p>Filter the ensemble of (3, 4)-regular Tanner graphs to only consider Tanner graphs with <em><strong>girth &#8805; 6</strong></em>. (This property is useful in decoding error syndromes.)</p></li><li><p>Within the set of (3, 4)-regular Tanner graphs with girth &#8805; 6, prioritize those with the <em><strong>largest distance</strong></em>.</p></li><li><p>Within the set of (3, 4)-regular Tanner graphs with girth &#8805; 6 and maximum distance, prioritize those with the <em><strong>largest spectral gap</strong></em>.</p></li></ol><p>The standard way to do this &#8212; the way I tried doing it at first &#8212; is to first define the following functions:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;a001e8be-40e5-4a62-8576-79f09aeef847&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def best_seed(n_bits, trials=100):
    """Sample many seeds, keep the one with the largest exact distance."""
    best_H, best_d = None, -1
    for s in range(trials):
        H = regular_seed(n_bits, wc=3, wr=4, seed=s)
        d = exact_distance(H)
        if d &gt; best_d:
            best_H, best_d = H, d
    return best_H, best_d

def has_four_cycle(H):
    """True iff two checks share two or more bits. Equivalent to girth &lt; 6."""
    G = H.astype(np.int64) @ H.astype(np.int64).T
    np.fill_diagonal(G, 0)
    return bool((G &gt;= 2).any())

def spectral_gap(H):
    """sigma_1 - sigma_2 of H"""
    s = np.linalg.svd(H.astype(float), compute_uv=False)
    return float(s[0] - s[1])</code></pre></div><p>And then run a flow chart algorithm like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!47Eo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!47Eo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 424w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 848w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 1272w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!47Eo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png" width="728" height="109.07534246575342" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:175,&quot;width&quot;:1168,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:39954,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!47Eo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 424w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 848w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 1272w, https://substackcdn.com/image/fetch/$s_!47Eo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6d3e28df-43fe-496f-8740-7366d483c2d7_1168x175.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Unfortunately, this doesn&#8217;t work so well in practice, because the proportion of (3, 4)-regular Tanner graphs that have girth &#8805; 6 is quite small, so one would have to wait a long time to generate enough graphs. In particular, this is related to the Poisson distribution, which is beyond the scope of this article. But the key result is that</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{Pr}[\\text{girth}\\geq 6] \\underset{n \\to \\infty}{\\longrightarrow} \\exp \\bigl(- \\frac{(w_c-1)^2(w_r-1)^2}{4}\\bigr) = e^{-9}&quot;,&quot;id&quot;:&quot;ITUNDFGPHY&quot;}" data-component-name="LatexBlockToDOM"></div><p>One <em>could</em>, of course, just brute force search for a long time. But I used a different approach instead &#8212; constructing graphs with girth &#8805; 6 from the get-go, using the following progressive edge growth function:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;743cdab1-5f7d-4ca1-bac0-3165000444ec&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def regular_seed_girth6(n_bits, rng, wc=3, wr=4, attempts=200):
    """A random (wc,wr)-regular seed whose Tanner graph has girth &gt;= 6.

    girth &gt;= 6 iff no two bits share more than one check.  We enforce that
    edge by edge while building: walk the bits in random order and, 
    for each of its wc edges, connect it to
    the least-loaded check that would not close a 4-cycle."""

    r = n_bits * wc // wr
    for _ in range(attempts):
        H       = np.zeros((r, n_bits), dtype=np.uint8)
        rowd    = [0] * r                          # bits placed in each check
        co      = [set() for _ in range(n_bits)]   # bits sharing a check with b
        members = [[] for _ in range(r)]
        order   = list(range(n_bits))
        rng.shuffle(order)
        ok = True

        for b in order:
            for _edge in range(wc):
                cand = [c for c in range(r)
                        if rowd[c] &lt; wr                     # check not yet full
                        and H[c, b] == 0                    # no repeated edge
                        and not (co[b] &amp; set(members[c]))]  # no 4-cycle
                if not cand:
                    ok = False
                    break
                lo = min(rowd[c] for c in cand)             # least-loaded check
                cand = [c for c in cand if rowd[c] == lo]   # random tie-break
                c = cand[rng.randrange(len(cand))]

                H[c, b] = 1
                for x in members[c]:
                    co[x].add(b)
                    co[b].add(x)
                members[c].append(b)
                rowd[c] += 1
            if not ok:
                break

        if ok and all(d == wr for d in rowd):
            return H
    raise RuntimeError(f"no girth-6 seed at n_bits={n_bits} in {attempts} attempts")</code></pre></div><p>By construction, this function always gives us (3, 4)-regular Tanner graphs with girth &#8805; 6. Excellent!</p><p>Now, I run a search function that uses regular_seed_girth6 to generate many samples of such graphs, and then optimize for distance and spectral gap to give the final seed that we desired.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;python&quot;,&quot;nodeId&quot;:&quot;6403c094-412e-467b-9179-d343def0b11c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-python">def search(n_bits, draws=1000, seed=0):
    """Returns (best_H, record).
    record holds (d, gap, k1, rank) for every accepted draw"""

    rng = random.Random(seed)
    record, best_H, best_key = [], None, None

    for _ in range(draws):
        H = regular_seed_girth6(n_bits, rng)   # girth &gt;= 6 by construction
        assert not has_four_cycle(H)           # cheap independent confirmation

        k1  = nullspace(H).shape[0]
        d   = exact_distance(H)
        gap = spectral_gap(H)
        record.append({"d": d, "gap": gap, "k1": k1, "rank": n_bits - k1})

        key = (d, gap)                         # distance first, gap as tie-break
        if best_key is None or key &gt; best_key:
            best_key, best_H = key, H

    return best_H, record</code></pre></div><p>Finally, we have good classical seeds that we can take the HGP of. Here, I take the best classical matrix returned by the search function and take the HGP with itself.</p><p>Now, the only question remains, what size <em>n</em> of bits should we take? To answer this, I look at the codes that the paper uses. Figure 3 a of the paper gives the codes:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aJ1d!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aJ1d!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 424w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 848w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 1272w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aJ1d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png" width="465" height="267.1608040201005" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/658e93f8-22f2-41a3-9903-512092180d9a_597x343.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:343,&quot;width&quot;:597,&quot;resizeWidth&quot;:465,&quot;bytes&quot;:61568,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aJ1d!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 424w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 848w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 1272w, https://substackcdn.com/image/fetch/$s_!aJ1d!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F658e93f8-22f2-41a3-9903-512092180d9a_597x343.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Reading from the figure, we see that the codes used by the paper are [[225, 9, 4]], [[625, 25, 6]], [[1225, 49, 8]], [[2500, 100, 12]], [[5625, 225, 16]], and [[10000, 400, 18]].</p><p>Now, we must reverse-engineer the classical seed that would give us an HGP code with parameters [[225, 9, 4]], and we will later repeat this for the other codes too.</p><p>Let <em>H<sub>seed</sub></em> be a classical (3, 4)-regular parity check matrix that we will use as a &#8216;seed&#8217; in the hypergraph product. Suppose <em>H<sub>seed</sub></em> acts on <em>n<sub>seed</sub></em> bits, and assume <em>H</em> has full rank. We would like to know, how many checks <em>r<sub>seed</sub></em> does <em>H<sub>seed</sub></em> have? How many physical qubits <em>n<sub>qubits</sub></em> does the HGP have? How many logical qubits <em>k<sub>qubits </sub></em>does the HGP have? What is the rate <em>k<sub>qubits </sub>/ n<sub>qubits </sub></em>of the HGP code?</p><p>We can count the checks <em>r<sub>seed</sub></em> two different ways using the (3, 4)-regular property: 3<em>n</em> or 4<em>r</em>. Setting these equal, we get </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;3n = 4r \\implies r = \\frac{3}{4}n&quot;,&quot;id&quot;:&quot;ELVFKPOYTU&quot;}" data-component-name="LatexBlockToDOM"></div><p>The number of message bits of the classical code <em>H<sub>seed</sub></em> is then </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;k_{seed} = n_{seed} - r_{seed} = \\frac{1}{4}n&quot;,&quot;id&quot;:&quot;ILNWSSHXYQ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Recalling that the hypergraph product places qubits on check &#215; check and bit &#215; bit positions, we get that the physical qubit count of the HGP is </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;n_{qubits} = r_{seed}^2 + n_{seed}^2 = n_{seed}^2 + \\frac{9}{16} n_{seed}^2 = \\frac{25}{16} n_{seed}^2&quot;,&quot;id&quot;:&quot;SHDININHLN&quot;}" data-component-name="LatexBlockToDOM"></div><p>and the logical qubit count of the HGP is </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;k_{qubits} = k_{seed}^2 = \\frac{1}{16} n_{seed}^2&quot;,&quot;id&quot;:&quot;OHTAGZCCMT&quot;}" data-component-name="LatexBlockToDOM"></div><p>So rate of the HGP code is </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{k_{qubits}}{n_{qubits}} = \\frac{(1/16) n_{seed}^2}{(25/16) n_{seed}^2} = \\frac{1}{25} = 0.04&quot;,&quot;id&quot;:&quot;LHJDNLUFNS&quot;}" data-component-name="LatexBlockToDOM"></div><p>Observe that the rate is independent of <em>n </em>&#8212; this is exactly the &#8220;constant overhead&#8221; in the paper&#8217;s title. </p><p>But the paper says that the rate of the HGP code is <em><strong>lower-bounded</strong></em> by 0.04, why is that?</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;k_{seed} = n_{seed} - \\text{rank}(H_{seed})&quot;,&quot;id&quot;:&quot;FIUUOBVEZL&quot;}" data-component-name="LatexBlockToDOM"></div><p><em><strong>If H<sub>seed</sub> has full rank</strong></em>, then the number of checks (i.e., number of rows) <em>r<sub>seed</sub></em> = rank(<em>H<sub>seed</sub></em>), and the rate of the HGP code is exactly 0.04. But in the general case, </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{rank}(H_{seed}) \\leq r_{seed} \\implies k_{seed} \\geq n_{seed} - r_{seed} \\implies \\frac{k_{qubits}}{n_{qubits}} \\geq 0.04&quot;,&quot;id&quot;:&quot;IMXUCEOAUX&quot;}" data-component-name="LatexBlockToDOM"></div><p>Now, back to the task of reverse-engineering, we want <em>n<sub>qubits </sub></em>= 225 and <em>k<sub>qubits </sub></em>= 9, so</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{25}{16} n_{seed}^2 = 225 \\text{ and } \\frac{1}{16} n_{seed}^2 = 9 \\implies n_{seed} = 12&quot;,&quot;id&quot;:&quot;EYJPSDOGTR&quot;}" data-component-name="LatexBlockToDOM"></div><p>Repeating similarly for the other codes, we find that </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Zkuj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Zkuj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 424w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 848w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 1272w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Zkuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png" width="487" height="256" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:256,&quot;width&quot;:487,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48583,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Zkuj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 424w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 848w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 1272w, https://substackcdn.com/image/fetch/$s_!Zkuj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ab732f5-0dd6-4203-9885-e2c63290cb68_487x256.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Once I got these <em>n<sub>seed </sub></em>values, I ran my search function to reproduce the codes used by the paper. Here are my results:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WLSS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WLSS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 424w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 848w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 1272w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WLSS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png" width="964" height="406" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:406,&quot;width&quot;:964,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41919,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WLSS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 424w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 848w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 1272w, https://substackcdn.com/image/fetch/$s_!WLSS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F956227a1-b2b7-45fd-8fc4-ae0e7bcc4162_964x406.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I am not sure why I got a higher distance than the paper in the cases of <em>n<sub>seed</sub></em> being 12, 20, and 28. In all likelihood, there is some error in my code that I am trying to find out. In the case <em>n<sub>seed</sub></em> = 60, I got a lower distance than the paper, presumably because I searched only 1000 samples.</p><div><hr></div><p>Next, I also cross-checked Table 1 of the paper, which tells us their calculation of the overhead savings in using HGP or LP codes over the surface code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xMqX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xMqX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 424w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 848w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 1272w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xMqX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png" width="506" height="393.2772277227723" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:628,&quot;width&quot;:808,&quot;resizeWidth&quot;:506,&quot;bytes&quot;:137554,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/212099664?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xMqX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 424w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 848w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 1272w, https://substackcdn.com/image/fetch/$s_!xMqX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9234811c-1513-4cd2-a6f6-5ab1e44f1a7e_808x628.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>We will focus on the row about HGP codes. From the above results, we already know that 25 logical qubits &#8592;&#8594; <em>n<sub>seed</sub></em> = 20 and 400 logical qubits &#8592;&#8594; <em>n<sub>seed</sub></em> = 80. So let us try to understand where the corresponding physical qubit counts for those HGP codes (1,235 and 19,600 respectively) come from.</p><p>We already know that a (3, 4)-regular seed on <em>n<sub>seed</sub></em> bits gives an HGP code with 25/16 <em>n</em><sup>2</sup><em><sub>seed </sub></em>data qubits. Syndrome extraction needs one ancilla atom per stabilizer generator, so how many ancilla qubits do we have?</p><p>Well, recalling that HGP places stabilizers on check &#215; bit and bit &#215; check positions, the number of stabilizer generators (i.e., the number of ancilla qubits) is</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;r_1n_2+n_1r_2 = 2\\cdot \\frac{3}{4}n_{seed}^2 = \\frac{3}{2}n_{seed}^2&quot;,&quot;id&quot;:&quot;PJWIPNMYNM&quot;}" data-component-name="LatexBlockToDOM"></div><p>So the total number of physical qubits is data qubits + ancilla qubits, which gives us</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\frac{25}{16} n_{seed}^2 +\\frac{3}{2}n_{seed}^2 = \\frac{49}{16} n_{seed}^2&quot;,&quot;id&quot;:&quot;JRSARKVUZD&quot;}" data-component-name="LatexBlockToDOM"></div><p>And indeed, plugging in <em>n<sub>seed</sub></em> = 20 gives total qubits = 1,225 (a disagreement with the 1,235 figure in the table) and plugging in <em>n<sub>seed</sub></em> = 80 gives total qubits = 19,600.</p><div><hr></div><p>To conclude this article, here are some questions and observations I had while working on this project -</p><ol><li><p>It is not clear to me from reading the paper whether they took HGP of a good seed code with itself, or HGP of two different good seed codes.</p></li><li><p>It is not clear to me from reading the paper whether they first generated entire sets of (3, 4)-regular Tanner graphs and then rejected those with girth &#8804; 4, or they too used a progressive edge growth algorithm to deliberately construct only those (3, 4)-regular Tanner graphs that already have girth &#8805; 6.</p></li><li><p>In Table 1, I had a disagreement with the paper for total qubits for an HGP code at 25 logical qubits (paper says 1,235 v/s my result of 1,225). Also, 80 and 180 are not <em>k</em><sup>2</sup> for any integer <em>k</em>, so perhaps they interpolated the fit to a continuous code size? Or maybe they used HGP of two different seed codes (perhaps with something like <em>k</em><sub>1</sub> = 8 and <em>k</em><sub>2</sub> = 10)</p></li><li><p>While distance and spectral gap had a maximisation constraint, girth only had a threshold. We were not trying to maximise girth, instead we were allowing everything above threshold girth ( &#8805; 6). To understand this better, I will look into <em><strong>how exactly decoders rely on the no-4-cycle property</strong></em>.</p></li><li><p>In the flow chart for seed generation, we did not optimise for low-rank (say, non-full rank) even though low rank improves the code rate. What if we include a rank-minimisation criteria in the seed generation algorithm?</p></li><li><p>Why exactly do we maximise spectral gap?</p></li><li><p>It would be interesting to see what fraction of criteria-satisfying seeds of a given size come out full rank.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.malharmanek.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.malharmanek.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Linear Codes]]></title><description><![CDATA[A linear algebraic introduction]]></description><link>https://www.malharmanek.com/p/linear-codes</link><guid isPermaLink="false">https://www.malharmanek.com/p/linear-codes</guid><dc:creator><![CDATA[Malhar Manek]]></dc:creator><pubDate>Sun, 02 Aug 2026 18:39:12 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0e879840-77b1-4dc6-a74d-de821fe3d59c_768x768.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is the first in a series of posts that will seek to explain, both rigorously and intuitively, concepts from quantum computing.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>Let&#8217;s start by understanding linear codes &#8212; a key notion in classical error correction &#8212; and use it to set the stage for quantum error correction. </p><p>The usual presentation of linear codes begins with the 3-bit repetition code, then considers a general [<em>n</em>, <em>k</em>, <em>d</em>] code and its rate <em>k</em>/<em>n</em>, and so on, all from the engineer&#8217;s perspective of building practical codes. But as any math major at UChicago would ask, &#8220;<span>that&#8217;s </span>all well and good in practice<span>... but how does it work in theory?&#8221;</span></p><p><span>In this post, I want to present linear codes from the abstract, pure math perspective of linear algebra.</span></p><div><hr></div><p>Consider the space of <em>n</em>-bit strings, denoted {0, 1}<em><sup>n</sup></em>. Notice that {0, 1} = F<sub>2</sub>, so the space of <em>n</em>-bit strings is exactly {0, 1}<em><sup>n</sup> </em>= F<sub>2</sub><em><sup>n</sup></em>.</p><p>Just as &#8477;<em><sup>n</sup></em> is a vector space over the field &#8477;, we might guess that F<sub>2</sub><em><sup>n</sup></em> is a vector space over F<sub>2</sub>. Before we can evaluate this guess, we must <em><strong>define</strong></em> an addition operator on the space of <em>n</em>-bit strings.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>So, how can we add <em>n</em>-bit strings? Here are a few ideas one might think of:</p><ol><li><p>Convert the <em>n</em>-bit strings into decimal numbers, add them in decimal, and convert back to binary. </p><p>For example, if I want to add the 2-bit strings 10 and 11, I look at their decimal representations, 2 and 3 respectively, add them in decimal to get 2 + 3 = 5, then convert 5 back into binary to get 101.</p><p>But clearly, this doesn&#8217;t work, because we added 2-bit strings (10 and 11) and got a 3-bit string (101), so the space is not closed under addition!</p></li><li><p>To resolve this, one can do the same thing &#8212; convert to decimal, add in decimal and convert back &#8212; but this time do the decimal addition modulo <em>n</em>.</p><p>For example, if I want to add the 3-bit strings 101 and 110, I look at their decimal representations, 5 and 6 respectively, add them in decimal to get 5 + 6 = 11, take modulo 3 to get 2, then convert 2 back into binary to get 010. So under this definition of the addition operator, we get 101 + 110 = 010.</p><p>The space is now closed under addition, but <em>intuitively</em>, this feels strange. To see why, think about what possible answers we can get when we add modulo <em>n</em>: we can only get the remainders 0, 1, &#8230;, <em>n</em>-1. So, adding <em>any</em> 3-bit strings can never give an output greater than 010 (i.e., 2). Isn&#8217;t this strange?</p><p>More rigorously, the addition map is not surjective onto {0, 1}<em><sup>n</sup></em>, which means that the space under this addition operator has no identity element. (Exercise: think about how failure of surjectivity implies lack of identity element. Suppose there was an identity element <em>e</em>, and try adding it to the 3-bit string 111 &#8212; what happens?)</p></li><li><p>To fix this, we repeat the same procedure, but we add modulo 2<em><sup>n</sup></em> instead of <em>n</em>. (Exercise: think about why this fixes the problem of the identity element!)</p><p>Alas, we are not yet done. Think about what we originally set out to do: we wanted to construct a vector space over the field F<sub>2</sub>. Observe that on F<sub>2</sub>, 1 + 1 = 0, so any vector <em>v</em> added to itself must give:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;1 v + 1 v = (1 + 1) v = 0&quot;,&quot;id&quot;:&quot;JGBDHBWHNR&quot;}" data-component-name="LatexBlockToDOM"></div><p>But with our modulo 2<em><sup>n </sup></em>definition, 011 + 011 = 110 &#8800; <strong>0</strong>.</p><p>Let us think back to the analogy with &#8477;<em><sup>n </sup></em>that we began with. How does &#8477;<em><sup>n </sup></em>avoid this problem? Well, addition on &#8477;<em><sup>n</sup></em> is <em><strong>coordinate-wise</strong></em>, i.e., (<em>u</em> + <em>v</em>)<em><sub>j</sub></em> depends only on <em>u<sub>j</sub></em><sub> </sub>and <em>v<sub>j</sub>.</em></p><p>If we generalised such a notion of coordinate-wise addition to our space, we naturally get addition of <em>n</em>-bit strings defined as a bitwise modulo 2 addition (i.e., a bitwise XOR).</p></li></ol><p>Finally, we have an addition operator under which {0, 1}<em><sup>n</sup></em> is a genuine vector space over F<sub>2</sub>. (Exercise: convince yourself that with the addition operator defined as bitwise XOR, this satisfies all the vector space axioms).</p><div><hr></div><p>Whew! All that work was just to define an addition operator?! Let&#8217;s take a breather.</p><p>In pure mathematics, one often encounters the idea of a <em>space</em> &#8212; metric space, vector space, topological space, etc. &#8212; and one wonders what this means. After all, this is not the same space as one thinks of in the astronomical sense of the word. </p><p>An abstract space in mathematics is simply a <em><strong>set endowed with some structure</strong></em>. For example, a metric space is a set equipped with a notion of distance between points. A topological space is a set equipped with a collection of open subsets. A vector space is a set associated with a field, equipped with addition and scalar multiplication operators.</p><p>Given two spaces <em>X</em> and <em>Y</em> of the same kind, it is a natural question to ponder &#8220;which functions <em>f</em>: <em>X</em> &#8594; <em>Y</em> preserve the structure of the space?&#8221; For example, if <em>X</em> and <em>Y</em> are both metric spaces, then it is natural to study the functions that preserve distance. In the general case, given a space, we would like to consider the functions that preserve the essential structure of the space. The general name for such a function is <em><strong>homomorphism</strong></em>.</p><p>(Exercise: Considering the structure of vector spaces &#8212; namely, the operations they are equipped with &#8212; think about and write down the conditions required for a function to be a vector space homomorphism. Concretely, what properties would a function between two vector spaces <em>f</em>: <em>V</em> &#8594; <em>W</em> need to satisfy, in order to preserve the essential structure of a vector space?)</p><p>Spoiler: these requirements are exactly the definition of a linear transformation between vector spaces. In other words, a vector space homomorphism is precisely a linear transformation. This explains why we care so much about linear transformations: they preserve the essential structure of vector spaces.</p><div><hr></div><p>Back to our study of {0, 1}<em><sup>n</sup>.</em></p><p>Note that this space has an additional structure: we can think of the &#8220;weight&#8221; of an <em>n</em>-bit string vector as the number of 1&#8217;s in it. For example, the weight of 10010 is 2, and the weight of 10111 is 4. We call this the Hamming weight of the vector.</p><p>And observe that our choice of the bitwise XOR as addition operator naturally gives a metric: given two <em>n</em>-bit string vectors, simply add them to get a new vector, and look at the Hamming weight of that vector to get the distance between the original two vectors:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;d(x,y) := \\text{HW}(x \\oplus y), \\text{ where HW denotes Hamming weight}&quot;,&quot;id&quot;:&quot;QAUCXSUSKH&quot;}" data-component-name="LatexBlockToDOM"></div><p>So we actually have not just a vector space, but also a metric space! We call this the <em>n</em>-dimensional Hamming space. (Exercise: check that this is a valid metric: it is symmetric, non-negative, d(<em>x</em>, <em>y</em>)<em> = </em>0 iff <em>x </em>= <em>y</em>, and satisfies the triangle inequality).</p><p>Going forward, <em><strong>we can think about Hamming space both as a vector space and as a metric space</strong></em>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cKui!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cKui!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 424w, https://substackcdn.com/image/fetch/$s_!cKui!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 848w, https://substackcdn.com/image/fetch/$s_!cKui!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!cKui!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cKui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp" width="282" height="282" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:768,&quot;resizeWidth&quot;:282,&quot;bytes&quot;:520162,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://www.malharmanek.com/i/208370903?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cKui!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 424w, https://substackcdn.com/image/fetch/$s_!cKui!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 848w, https://substackcdn.com/image/fetch/$s_!cKui!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 1272w, https://substackcdn.com/image/fetch/$s_!cKui!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc3f99fc6-112c-460d-90f8-dced91ded3ee_768x768.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg aria-hidden="true" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An aesthetic picture of Hamming distance, from <a href="https://chalkdustmagazine.com/features/the-hidden-harmonies-of-hamming-distance/">this article</a></figcaption></figure></div><p>Now, what does one do when handed vector spaces? One thinks about maps between them, of course! So let us consider <em>k</em>-dimensional Hamming space <em>H<sub>k</sub></em> and <em>n</em>-dimensional Hamming space <em>H<sub>n</sub></em> and a map <em>T</em>: <em>H<sub>k </sub>&#8594; H<sub>n</sub></em> between them. (For now, this can be any arbitrary map &#8212; we will impose constraints on it soon).</p><p>Our linear algebra intuition already tells us that imposing the constraint that <em>T</em> be a linear transformation might <em>somehow</em> make it interesting, though we don&#8217;t know <em>exactly</em> <em>how</em> just yet. Hold onto this intuition; it will come up soon!</p><div><hr></div><p>Now, finally, let us turn to the application of all this theory.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> </p><p>I posit the following for your consideration: if we wish to reliably send a <em>k</em>-bit message to a friend, across a noisy channel that may introduce errors in our message, then it is necessary to transmit more than <em>k</em> bits. (Exercise: think about why we need strictly more bits &#8212; what would happen if we sent exactly <em>k</em> bits and an error occurred?)</p><p>Let <em>n</em> and <em>k </em>be integers representing the number of transmitted bits and the number of bits in the message, respectively. Clearly, then, <em>n</em> &gt; <em>k.</em></p><p>Let us revisit the map <em>T</em>: <em>H<sub>k </sub>&#8594; H<sub>n</sub></em>. We may think of this map as <em><strong>encoding</strong></em> our <em>k</em>-bit message as an <em>n</em>-bit string. </p><p>For example, if <em>k</em> = 3 and <em>n</em> = 5 and if our message is 101, then <em>T</em> might, for instance, map this to <em>T</em>(101) = 10111. Or some other choice of the map might give us, say, <em>T</em>(101) = 01101. For now, <em>T</em> is arbitrary and all that matters is that it is converting a <em>k</em>-bit message into an encoded <em>n</em>-bit codeword.</p><p>Let us think about what extra properties we desire <em>T</em> should have. For one thing, it would be strange if two different messages got encoded into the same codeword &#8212; e.g., if <em>T</em>(101) = <em>T</em>(111) &#8212; for how would our friend decode the codeword to extract our intended message? So we require <em>T</em> to be injective.</p><p>What is the cardinality of the image of <em>T</em>? Well, the domain has 2<em><sup>k</sup></em> elements and <em>T</em> is injective, so |Image(<em>T</em>)| = 2<em><sup>k</sup>. </em>So the image of <em>T </em>is a 2<em><sup>k</sup></em>-element subset of the 2<em><sup>n</sup></em>-element set {0, 1}<em><sup>n</sup>. </em>By the way, we refer to Image(<em>T</em>) by <em>C</em>, the set of codewords.</p><p>Now, just for fun, how about we force <em>T</em> to be linear and see what happens?<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></p><p>If <em>T</em>: <em>H<sub>k </sub>&#8594; H<sub>n</sub></em> is a linear transformation, then the image of <em>T </em>is a linear subspace of the codomain <em>H<sub>n</sub></em>. When this is the case, we call the code a <em><strong>linear code</strong></em>.</p><p>What does this mean? It means that adding any two codewords always produces another codeword. Peculiar! How could this possibly be of use to us? Stow this question and we&#8217;ll return to it.</p><div><hr></div><p>In what scenario is an error correctable? Suppose, with <em>k</em> = 3 and <em>n</em> = 5, that my message is 101 and the corresponding codeword &#8212; the thing that I transmit through the channel &#8212; is <em>T</em>(101) = 11101. If no errors occur, then we are done, because <em>T</em> is injective so the recipient can simply invert to get <em>T </em><sup>-1</sup>(11101) = 101.</p><p>If errors do occur, however, then the recipient will receive something different from 11101; for example, they may receive 11000. Therefore, note that the recipient flags an error when the received string is not a codeword.</p><p>In this case, we need to supply a decoding mechanism: a way to interpret the received, faulty <em>n</em>-bit string to extract the original <em>k</em>-bit message. Even without specifying the particular decoding mechanism, it is easy to imagine a case in which it fails: if so many errors occur that the received, faulty <em>n</em>-bit string is a codeword, then the situation is hopeless. For example, if 11000 is <em>itself</em> a codeword, then how can the recipient possibly know that the true message is not <em>T </em><sup>-1</sup>(11000)?</p><p>Observe that there are two ways in which the recipient can receive a codeword: either no errors occurred, or so many errors occurred that <em>another</em> codeword was received.</p><p>So the operative question is: how many errors must occur to turn one codeword into another? But the codewords need not be evenly spaced apart, so what matters is, in the set of all 2<em><sup>k </sup></em>codewords, what is the minimum distance over all pairs of <em>distinct</em> codewords? We call this the distance <em>d</em> of the code, because it quantifies the code&#8217;s robustness: the larger the distance <em>d</em>, the more errors that can be detected.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a></p><p>How does one compute the distance of a code? A priori, one would need to compute (2<em><sup>k </sup></em>choose 2)-many pairwise Hamming distances and find the minimum. But recall that for a linear <em>T</em>, the set of codewords is closed under addition. So we may simply find the minimum Hamming weight over non-zero codewords and we&#8217;re done!</p><p><em><strong>For a linear code, the code distance is equal to the minimum, over all non-zero codewords, of the Hamming weights of the codewords.</strong></em></p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{If }T \\text{ is linear then } d = \\min_{c\\in \\mathcal{C}, c\\neq 0} \\text{HW}(c), \\text{ where HW denotes Hamming weight}&quot;,&quot;id&quot;:&quot;FQHVODUAOS&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is the first indication of our vindication &#8212; we already see that forcing <em>T</em> to be a linear transformation, in line our with linear-algebraic intuition, made it much easier for us to compute <em>d</em>.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a></p><div><hr></div><p>We said earlier that the larger the code distance <em>d</em>, the more errors that can be detected. It is natural to ask, then, how exactly does the code distance <em>d</em> relate to the number of errors that can be corrected, call it <em>t</em> &#8212; what equation relates them?</p><p>Firstly, we must distinguish the number of <em>detectable</em> errors from the number of <em>correctable</em> errors &#8212; a priori, they may or may not be the same.</p><p>We defined the code distance <em>d </em>as the minimum number of bits that need to be flipped to go from one codeword to another. Clearly, this means that if <em>d</em> errors occur, then our code cannot detect them. But if fewer than <em>d</em> errors occur, then no matter what the original codeword was, it cannot have been distorted into another codeword &#8212; so it now sits somewhere in Hamming space, between codewords.</p><p>Recall that the recipient flags an error whenever the received string is not a codeword. This tells us that if fewer than <em>d</em> errors occur, then we know for sure that our code can detect them &#8212; so upto <em>d</em>-1 are guaranteed detectable.</p><p>What about <em>correctable</em> errors? In order to correct an error, we must construct a decoder function <em>D</em>: <em>H<sub>n</sub></em> &#8594; <em>C</em> that reads the received <em>n</em>-bit string and outputs the codeword that was transmitted.</p><p>We say that <em>D</em> corrects <em>t</em> errors if <em>D</em>(<em>c</em> + <em>e</em>) = <em>c</em> for every <em>n</em>-bit-error-string <em>e</em> that has Hamming weight &#8804; <em>t</em>. This is a condition that an arbitrary function may or may not satisfy; what we are interested in is whether there exists a particular decoder function <em>D</em> that satisfies it. (Exercise: prove that such a <em>D</em> exists if and only if <em>d</em> &#8805; 2<em>t</em> + 1).</p><p>So, detection works with guarantee up to <em>d</em>-1 errors, correction only up to (<em>d</em>-1)/2 errors. To detect, the error need only be <em>visible</em>; to correct, it must be <em>unambiguous</em>, and ambiguity sets in at the midpoint between codewords.</p><div><hr></div><p>Having used an abstract path to getting here, let us reflect on the intuition it provides us.</p><p>Our linear algebra intuition told us that we should pick <em>T</em> to be a <em><strong>vector space homomorphism</strong></em>, namely a linear transformation, and this worked out well, giving us the concept of linear codes.</p><p>Seeing as Hamming space is also a metric space, we may very well have the idea of making <em>T</em> a <em><strong>metric space homomorphism</strong></em> too, namely a distance-preserving map, also called an isometry.</p><p>But in fact, <em><strong>an isometric </strong>T<strong> is the worst possible encoder</strong></em>, for it means that the code has <em>d</em> = 1 (exercise: why?), meaning that no errors can be detected, let alone corrected! The very nature of a useful code is that any two distinct <em>k</em>-bit messages &#8212; no matter how far apart in <em>H<sub>k</sub></em> &#8212; get mapped to codewords that are Hamming distance &#8805; <em>d</em> apart in <em>H<sub>n</sub></em> &#8212; namely, the fact that <em>T</em> is not an isometry!</p><p>Clearly, we have an asymmetry that begs to be resolved: why are vector space homomorphisms &#8216;good&#8217; but metric space homomorphisms &#8216;bad&#8217;? The answer lies in revisiting the notion of homomorphism as a map that preserves essential structure. But the question is, what is essential?</p><p>In this case, the message &#8212; the <em>k</em>-bit string vector &#8212; is essential. The notion of Hamming distance as a metric is used only as an evaluation criteria to gauge how good the code is &#8212; how many errors it can correct &#8212; and is not essential.</p><p>Put differently, a structure can come up as a <em>constraint</em> defining which maps are admissible, or as an <em>objective</em> that measures which admissible maps are good. Here, the vector space structure plays the first role, and the metric space structure plays the second.</p><div><hr></div><p>To recapitulate,</p><ul><li><p>Bitwise XOR is the natural addition operator that makes {0, 1}<em><sup>n</sup></em> a vector space over F<sub>2</sub></p></li><li><p>A linear code is one where the encoding operator <em>T</em>: <em>H<sub>k </sub>&#8594; H<sub>n</sub></em> is a linear transformation</p></li><li><p><em>T</em>: <em>H<sub>k </sub>&#8594; H<sub>n</sub></em> is a vector space homomorphism but not a metric space homomorphism (even though Hamming space is both, a vector space and a metric space).</p></li></ul><div><hr></div><p>We are only just scratching the surface of error correction theory (pun intended), and future posts will expand on further topics.</p><p>Feedback and reading recommendations are invited at malhar.manek@gmail.com</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.malharmanek.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Get new posts in your inbox</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>Some resources I found useful and would recommend:</p><ol><li><p>This <a href="https://www.youtube.com/watch?v=X8jsijhllIA">video</a> on Hamming codes by 3blue1brown</p></li><li><p>This <a href="https://arthurpesah.me/blog/2022-05-21-classical-error-correction/">blog article</a> on classical error correction by Arthur Pesah</p></li></ol><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I will try to use the <a href="https://michaelnotebook.com/df/index.html">discovery fiction</a> approach suggested by <a href="https://michaelnotebook.com/index.html">Michael Nielsen</a>, where one presents a plausible line of reasoning through which the reader, with some thought, might have discovered the ideas on their own.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>As the aphorism <a href="https://www.dwarkesh.com/p/grant-sanderson-2">goes</a>, &#8220;good mathematicians prove theorems, great mathematicians come up with conjectures, and the greatest mathematicians come up with definitions.&#8221;</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I deliberately chose to present an abstract explanation of linear codes. The standard presentation begins with the 3-bit repetition code and then generalises from it, but I find it worth at least exploring an alternative presentation, because:</p><ol><li><p>The <em>n</em>-bit repetition code, while easy to grasp, has a rate <em>k</em>/<em>n </em>that tends to 0 as <em>n</em> goes to infinity, i.e., it is an inefficient code.</p></li><li><p>Personally, I love abstract linear algebra (and pure math more generally) and thought it would be worthwhile to approach <em>linear</em> codes from a <em>linear</em> algebraic perspective.</p></li><li><p>Generally, it is always good to have multiple different expositions of the same topic, and consider how each one illuminates a different facet of the idea.</p></li></ol></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Often in math, we have an intuition for something &#8212; e.g., our intuition might tell us that linear maps are vector space isomorphisms, so <em>maybe</em>, just maybe, something special might happen if <em>T</em> is linear? &#8212; and we test it out, and course-correct accordingly. When one solves many problems of a certain nature, one starts to develop an intuition for what might work.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>Notice that we now have the [<em>n</em>, <em>k</em>, <em>d</em>] notation for a generic classical error correcting code.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>Searching through the list of 2<em><sup>k </sup></em>codewords rather than computing (2<em><sup>k </sup></em>choose 2)-many pairwise Hamming distances. (Linear codes have several other nice properties, that we will explore in future posts).</p></div></div>]]></content:encoded></item></channel></rss>