<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>KJ</title>
  <subtitle>A corner of the internet where I think in public.</subtitle>
  <link href="https://karanjanthe.me/feed.xml" rel="self"/>
  <link href="https://karanjanthe.me/"/>
  <updated>2026-03-06T00:00:00Z</updated>
  <id>https://karanjanthe.me/</id>
  <author>
    <name>KJ</name>
  </author>
  
  
  <entry>
    <title>The Bunny in 100 Holes</title>
    <link href="https://karanjanthe.me/posts/bunny-hopping/"/>
    <updated>2026-03-06T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/bunny-hopping/</id>
    <content type="html">&lt;p&gt;&lt;label for=&quot;mn-bunny&quot; class=&quot;margin-toggle&quot;&gt;⊕&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-bunny&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/bunny.jpeg&quot; alt=&quot;bunny&quot; /&gt;&lt;br /&gt;jump bunny jump&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Problem goes like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are 100 holes in a line and there is bunny🐇 hiding in one of them.&lt;/li&gt;
&lt;li&gt;You can only look in one hole at a time, every time you look it jumps to adjacent hole.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What’s your strategy?&lt;/p&gt;
&lt;p&gt;Take a breath. Think before reading on.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I found this through &lt;a href=&quot;https://uli.rocks/p/bunny/&quot;&gt;Uli’s blog&lt;/a&gt;. Uli tried the obvious “smart” strategy (always check the most probable hole) and found it barely beat random guessing. That bothered me. So I went down a rabbit hole. Yes, I know.&lt;/p&gt;
&lt;p&gt;What I thought would be a quick afternoon turned into bandit algorithms and eventually a lesson I should have learned much earlier: make sure you’re measuring the right thing before you start optimizing.&lt;/p&gt;
&lt;h2 id=&quot;randomly-picking-hole&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#randomly-picking-hole&quot;&gt;§&lt;/a&gt; Randomly picking hole:&lt;/h2&gt;
&lt;p&gt;The naive strategy: just pick a random hole each time, no thinking involved. In code:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# No of holes:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;N &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; jump&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(hole):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    elif&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; N &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.choice([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; play&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    # pickup random hole&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.randint(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, N &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    t &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; True&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        t &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        guess &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; random.randint(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, N &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; guess:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;Found the bunny in hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;guess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; after &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tries!&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;            print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;] Guessed &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;guess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; (true is &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;hole&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;)&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;            # wrong hole, bunny jumps:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            hole &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; jump(hole)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; t&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; __name__&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;__main__&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    play()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you run it you will see the number of tries it took to find the bunny:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; uv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; bunn.py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[1] Guessed 29 (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[2] Guessed 75 (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 56&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[3] Guessed 68 (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[175] Guessed 28 (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[176] Guessed 74 (&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; is&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 54&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Found&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; bunny&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; hole&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 55&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; after&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 177&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tries!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One simple way to find out how good my strategy is to find out how well it does on average:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;r &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [play() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; statistics &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stats&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;mean, median, stdev &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; stats.mean(r), stats.median(r), stats.stdev(r)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;mean: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;mean&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; median: &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;median&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; stddev &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;stdev&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I get this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mean: 99.3195 median: 70.0 stddev 97.85726556670393&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;About 100 guesses on average. Half the time I finish in 70 or fewer. But sometimes it drags past 500. Very unpredictable.&lt;/p&gt;
&lt;h2 id=&quot;getting-smarter-track-where-the-bunny-probably-is&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#getting-smarter-track-where-the-bunny-probably-is&quot;&gt;§&lt;/a&gt; Getting smarter: track where the bunny probably is&lt;/h2&gt;
&lt;p&gt;Random guessing throws away all information. Every time I check a hole and miss, I &lt;em&gt;know&lt;/em&gt; the bunny is not there. And since the bunny can only move one step, I also know something about where it went. Let’s use that.&lt;/p&gt;
&lt;p&gt;The idea: maintain a probability distribution &lt;code&gt;P&lt;/code&gt; over all 100 holes. Start uniform (bunny equally likely anywhere). After each miss, update two things. First, zero out the hole I just checked and renormalize. Second, spread the distribution one step to account for the bunny jumping.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; guess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(P, j):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    # bunny is not in hole j, remove it and renormalize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; sum&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(P) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[j]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[i] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; s &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(N)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; jumps&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(P):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    # bunny took one random step, diffuse the distribution&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Pn &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P.copy()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Pn[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    Pn[N&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[N&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; j &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, N&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        Pn[j] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[j&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0.5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; P[j&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Pn&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then always check &lt;code&gt;argmax(P)&lt;/code&gt;, the most probable hole. After every miss, zero out that hole, renormalize, and diffuse to neighbors to account for the jump. Makes sense in theory. Let’s see.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mean: 94.5  median: 50.5  stddev: 118.4&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Barely beats random on mean. &lt;em&gt;Worse&lt;/em&gt; stddev. What went wrong?&lt;/p&gt;
&lt;p&gt;The belief state &lt;code&gt;P[]&lt;/code&gt; is actually correct. The problem is what I do with it. Always picking &lt;code&gt;argmax(P)&lt;/code&gt; causes a ping-pong trap. I check hole 50, miss, probability peaks split to 49 and 51. I check 51, miss, peak shifts to 50 and 52. I check 50 again. I keep bouncing in the same neighborhood while the bunny has long since wandered off to hole 30. I am laser-focused on a region the bunny already escaped.&lt;/p&gt;
&lt;p&gt;The information is good. The decision rule on top of it is not.&lt;/p&gt;
&lt;h2 id=&quot;getting-excited-bandit-algorithms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#getting-excited-bandit-algorithms&quot;&gt;§&lt;/a&gt; Getting excited: bandit algorithms&lt;/h2&gt;
&lt;p&gt;This felt like a classic exploration vs exploitation problem. I have a good estimate of where the bunny is (exploit that), but I also need to check holes I have not visited in a while in case the bunny drifted there (explore those). There is a whole field built around this exact tradeoff: multi-armed bandits.&lt;/p&gt;
&lt;p&gt;The standard algorithm is UCB (Upper Confidence Bound). Add a bonus to each option based on how long it has been since I tried it. Holes I have not checked recently get boosted, which forces me to spread attention over time.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ucb_choice&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(P, visits, t, c&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    scores &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [P[i] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; c &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; np.sqrt(np.log(t) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (visits[i] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;              for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; range&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(N)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; argmax(scores)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Result:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;mean: 79.9  median: 56.0  stddev: 76.5&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mean dropped from 94 to 79. I got excited. I started tuning &lt;code&gt;c&lt;/code&gt;, trying linear staleness instead of the log-sqrt formula, trying hybrid approaches. Each run felt like progress because the mean kept inching down. Linear staleness (&lt;code&gt;P[i] + c*(t - last_visit[i])&lt;/code&gt;), gradient-aware scoring, anti-ping-pong penalties. Eventually got the mean down to around 75.&lt;/p&gt;
&lt;p&gt;I thought I was winning.&lt;/p&gt;
&lt;h2 id=&quot;the-column-i-was-not-looking-at&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#the-column-i-was-not-looking-at&quot;&gt;§&lt;/a&gt; The column I was not looking at&lt;/h2&gt;
&lt;p&gt;Here is the full comparison I should have been looking at from the very beginning.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Strategy         Mean    Median   StdDev   Max&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;------------------------------------------------&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;random           97.3      65.0     97.6    727&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;argmax           94.5      50.5    118.4   1021&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ucb_c1.5         79.9      56.0     76.5    574&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;sweep            98.5     100.0     58.1    198&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look at the sweep row. Just scanning left to right, then right to left, repeating forever. The mean looks bad at 98.5, worse than UCB’s 79.9. I had been dismissing it the whole time based on that one number. But look at the last column. Max of 198. Always. No exceptions across 10,000 runs.&lt;/p&gt;
&lt;p&gt;UCB occasionally takes 574 steps. My best staleness strategy hits 620 in the worst case. The sweep never exceeds 198.&lt;/p&gt;
&lt;p&gt;The reason is a simple physical argument. The bunny moves one step per turn. The sweep also advances one position per turn. The bunny cannot outrun a sweep. On a 100-hole line, one full back-and-forth covers every hole in exactly 2x(100-1) = 198 steps, and that bound is guaranteed.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sweep_position&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(t):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    period &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (N &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# 198&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    pos &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; t &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; period&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pos &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; N:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pos           &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# forward: 0 to 99&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; period &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pos  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# backward: 99 to 0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The stddev tells the same story. Sweep gets 58. UCB gets 76. All my staleness variants get 75 or higher. The boring sweep is the most consistent strategy by a wide margin.&lt;/p&gt;
&lt;p&gt;I spent days pushing the mean from 94 down to 76, completely ignoring the max and stddev columns. The sweep had better variance and a hard upper bound the whole time. I just was not looking.&lt;/p&gt;
&lt;h2 id=&quot;why-mean-was-the-wrong-thing-to-optimize&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#why-mean-was-the-wrong-thing-to-optimize&quot;&gt;§&lt;/a&gt; Why mean was the wrong thing to optimize&lt;/h2&gt;
&lt;p&gt;UCB was designed for stationary slot machines. Each arm has a fixed unknown payout and you want to find the best one over time. Here the “arms” are not stationary. The bunny moves. UCB has no model of that movement at all. Its exploration bonus happened to force rotation, which happened to reduce the mean, but this was accidental. UCB has no worst-case guarantee because it was never built to think about a moving target.&lt;/p&gt;
&lt;p&gt;The sweep encodes exactly one fact: the bunny is a 1D random walker and cannot teleport. That physical constraint is where the hard guarantee comes from. No bandit algorithm can exploit that constraint because bandit algorithms do not model the target at all.&lt;/p&gt;
&lt;p&gt;Depending on what I actually care about, the right answer is very different:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Best strategy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Minimize average steps&lt;/td&gt;
&lt;td&gt;UCB or lin_staleness (~76 mean)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimize worst case&lt;/td&gt;
&lt;td&gt;Sweep (198 steps, guaranteed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimize variance&lt;/td&gt;
&lt;td&gt;Sweep (StdDev 58 vs 76+)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search and rescue, anything high stakes&lt;/td&gt;
&lt;td&gt;Sweep, not even close&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;one-more-twist-what-if-the-bunny-is-smart&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/bunny-hopping/#one-more-twist-what-if-the-bunny-is-smart&quot;&gt;§&lt;/a&gt; One more twist: what if the bunny is smart?&lt;/h2&gt;
&lt;p&gt;Everything above assumed the bunny moves randomly. What if it moves against me, always jumping away from the hole I just checked?&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Holes: 1, 2, 3, 4, 5. I just checked hole 3.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Random bunny in hole 2: goes to 1 or 3 with equal probability&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Adversarial bunny in hole 2: always goes to 1, never toward the checked hole&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the sweep fails completely. A bunny that knows my pattern can stay one step ahead of a predictable sweep forever. The problem becomes pursuit-evasion, and I need randomness in my own strategy to have any guarantee. Everything changes.&lt;/p&gt;
&lt;p&gt;That is a rabbit hole for another day.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;*Full source code &lt;a href=&quot;https://gist.github.com/KMJ-007/f55f0e2aad1df5d3227714998527ed56&quot;&gt;here&lt;/a&gt;. Problem originally from &lt;a href=&quot;https://uli.rocks/p/bunny/&quot;&gt;Uli’s blog&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>You want to do everything?</title>
    <link href="https://karanjanthe.me/posts/optionality-curse/"/>
    <updated>2026-03-05T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/optionality-curse/</id>
    <content type="html">&lt;p&gt;You wake up and see someone playing guitar. Now you want to play guitar.&lt;br /&gt;
&lt;label for=&quot;mn-bunny&quot; class=&quot;margin-toggle&quot;&gt;⊕&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-bunny&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/bunny.jpeg&quot; alt=&quot;bunny&quot; /&gt;&lt;br /&gt;jump bunny jump&lt;/span&gt;&lt;br /&gt;
You see someone with great physique. Now you want that body. Hardware,Software, AI, Design, Hacking, Painting… the list never ends and every new thing feels urgent.&lt;/p&gt;
&lt;p&gt;Her’s the pattern: You spend hours researching the hobby/skill. Watching videos, reading threads, gathering information as much as you can. It feels productive. It isn’t. The research is simulation of commitment, your brain gets the illusion of progress without the discomfort of actual practice.&lt;/p&gt;
&lt;p&gt;And even if you start, you quit after one or two attempts. Not because you didn’t want it, but because something new arrived before the old thing got hard enough to get good.&lt;/p&gt;
&lt;p&gt;People say the silver bullet is just being high agency at everything. well it isn’t. People treat agency as the solution to everything, but agency without commitment is just faster context-switching. You become extremely efficient at starting things. That’s not a virtue, that’s a more energetic version of the same problem.&lt;/p&gt;
&lt;p&gt;What actually works is staying with something long enough to be genuinely bored by it. That dead zone between beginner excitement and real skill, where nothing feels fun and results aren’t comming yet, is where most people quit. It’s also where everything important happens. Sitting in that discomfort is how you find out what you actually like versus what just looked good from the outside. People call this type 2 fun. The enjoyment that only arrives after the struggle.&lt;/p&gt;
&lt;p&gt;Palmer Luckey said it better than I can:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“At some point, in business and in life and in romance, you have to commit to a path,” said the 31-year-old Luckey. “A lot of my peers in the tech industry do not share this philosophy … They’re always pursuing everything with optionality. ’Oh, I need to be able to raise money from anybody. I need to be able to sell my business in any way. I need to have liquidity in any way. I need to make sure that I’m not closing myself off to future romantic partners. I need to make sure I’ve got my options open. I need to make sure that I’m not going to buy a house and settle down in one place and lock myself down. Oh, having children. I don’t know. Maybe I’m not ready to commit to that path.’”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“In keeping their options open, they ensure that they’re going to jump from option to option. If you don’t commit to a path, you’re going to fail at it … You have to commit to it to make it work, and I think marriage is the same way. You just have to commit to it. You have to say, ’This is the path I’m on. For better or for worse, I’m going to double down on it.’”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The trap isn’t curiosity. Curiosity is good. The trap is using optionality as a permanent address. Staying open to everything because closing off feels like loss. It doesn’t feel like a trap. It feels like freedom. But you’re not free, you’re just permanently in preview mode. Never in the actual movie.&lt;/p&gt;
&lt;p&gt;Commitment isn’t about certainty. You rarely know before you commit. Commitment is the mechanism by which you find out. You don’t commit because you’re sure, you commit to become sure.&lt;/p&gt;
&lt;p&gt;Take whatever time you need to find the thing. But at some point, pick it and stay.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>What I learned building a vector database on object storage</title>
    <link href="https://karanjanthe.me/posts/vecpuff/"/>
    <updated>2025-12-09T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/vecpuff/</id>
    <content type="html">&lt;p&gt;When I came across &lt;a href=&quot;https://turbopuffer.com/&quot;&gt;Turbopuffer&lt;/a&gt;, a vector database built entirely on object storage, I got curious. Really curious. The architecture seemed almost too simple. &lt;code&gt;Write-ahead logs&lt;/code&gt; on S3? &lt;code&gt;Centroid-based indexes&lt;/code&gt;? &lt;code&gt;Stateless query nodes&lt;/code&gt;? It felt like someone had taken all the “rules” of database design and just… ignored them.&lt;/p&gt;
&lt;p&gt;I wanted to understand the tradeoffs myself. Not by reading more blog posts, but by actually building something. Also I broke up with my girlfriend, so I have nothing else to do.&lt;/p&gt;
&lt;p&gt;We’ll build a naive vector database on S3, inspired by &lt;a href=&quot;https://turbopuffer.com/architecture&quot;&gt;Turbopuffer’s architecture&lt;/a&gt;, using first principles and &lt;a href=&quot;https://youtu.be/IxkSlnrRFqc?si=L9iDnoB7jp7t9rQR&quot;&gt;napkin math&lt;/a&gt;. We’ll hit walls, make mistakes, and hopefully learn what design decisions we need to make.&lt;/p&gt;
&lt;p&gt;The more interesting thing about this is, S3 is meant to be object storage, it’s not that designed for database operations. We need to think about updates, deletes, managing indexes - how we store them, update them, and minimize roundtrips because every extra roundtrip is 200ms latency which your users will not like&lt;label for=&quot;sn-1&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Traditional databases optimize for low latency, S3 optimizes for throughput and cost.&lt;/span&gt;. So it’s not that easy to just use S3 and turn it up to infinite scale.&lt;/p&gt;
&lt;p&gt;I’m not a database expert. I’m not the hardcore database guy who tweets about &lt;code&gt;LSM trees&lt;/code&gt; and drops random &lt;code&gt;MySQL&lt;/code&gt; facts at parties. I’m just someone who likes tinkering with things to understand how they work.&lt;/p&gt;
&lt;p&gt;This is a learning exercise. I’m building my own version of turbopuffer to really understand the trade offs, the gotchas, and why certain decisions were made. If you’re looking for production-ready code or groundbreaking research, this isn’t it. But if you want to follow along as I figure out how to build a vector database from first principles, you’re in the right place.&lt;/p&gt;
&lt;h2 id=&quot;what-are-we-actually-optimizing-for&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#what-are-we-actually-optimizing-for&quot;&gt;§&lt;/a&gt; What are we actually optimizing for?&lt;/h2&gt;
&lt;p&gt;Why do we even want to build on S3, and why not in a traditional way or use top-of-the-shelf solutions like &lt;code&gt;pgvector&lt;/code&gt; or other millions of solutions?&lt;/p&gt;
&lt;p&gt;imagine you want to add semantic search to your app. Maybe &lt;code&gt;100 million&lt;/code&gt; vectors. You check pricing for existing vector databases, &lt;code&gt;Pinecone&lt;/code&gt;, &lt;code&gt;Qdrant&lt;/code&gt;, etc… &lt;code&gt;$20k&lt;/code&gt; per month. Just for storage. That’s insane.&lt;/p&gt;
&lt;p&gt;Why so expensive? Because traditional vector databases assume you need everything in memory or on expensive replicated &lt;code&gt;SSDs&lt;/code&gt;, and that’s where a good scale solution built on top of S3 with smart caching really shows its worth.&lt;/p&gt;
&lt;p&gt;That said, let’s set some reasonable goals for what this thing should do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Doesn’t bankrupt you&lt;/strong&gt; - Should cost &lt;code&gt;$1500/month&lt;/code&gt; for a billion vectors, not &lt;code&gt;$20k&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scales horizontally&lt;/strong&gt; - Add more &lt;code&gt;namespaces&lt;/code&gt; without &lt;code&gt;10x&lt;/code&gt;-ing your costs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handles writes properly&lt;/strong&gt; - Real-time &lt;code&gt;inserts/deletes&lt;/code&gt;, no rebuilding entire indexes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is fast enough&lt;/strong&gt; - Not “fastest possible,” but fast enough (&lt;code&gt;p95&lt;/code&gt; under &lt;code&gt;500ms&lt;/code&gt; for &lt;code&gt;10k&lt;/code&gt; result searches)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Overview of architecture:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Write path:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  upsert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;write_to_wal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → return_immediately&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;  // Background (async):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  compactor_job&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;read_wal_batch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;build_indexes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;write_indexed_clusters&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; delete_wal_files&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;  // Query path (hybrid):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  query&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() → {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      indexed_data&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; fast_cluster_lookup&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(),    &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// ~10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      unindexed_data&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; scan_recent_wal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(),      &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// ~200ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;      merge_results&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s start with writing and dumping things, simple Write-Ahead Log (WAL) implementation:&lt;/p&gt;
&lt;p&gt;On every write request, we store the incoming data in a WAL folder in the user-provided namespace. We use the sequence as WAL file names: &lt;code&gt;namespace/WAL/0000000001.bin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a brute-force approach, but it works.&lt;/p&gt;
&lt;p&gt;But now we have another problem: you can easily make a mistake and override the file, and your data is now overwritten, which is really bad for a database.&lt;/p&gt;
&lt;p&gt;For this, S3 provides us a good API: you can pass the precondition in the request header to perform conditional writes. So we can simply use &lt;code&gt;if_non_match: *&lt;/code&gt; — if the same key already exists, it will give us a &lt;code&gt;412&lt;/code&gt; status code that the precondition failed.&lt;/p&gt;
&lt;p&gt;We also have another latency killer: when a user fires a query asking for results, we need to fetch WAL files. But S3 doesn’t provide a way to fetch all files from a folder — you can only fetch a file, and for that you need to know the exact key name and bucket. S3 doesn’t provide regex-based file fetching either.&lt;/p&gt;
&lt;p&gt;The only way is to &lt;code&gt;LIST&lt;/code&gt; all files using a paginator, then fetch them in parallel. Each &lt;code&gt;LIST&lt;/code&gt; operation is &lt;code&gt;~200ms&lt;/code&gt; per page, and each &lt;code&gt;GET&lt;/code&gt; is another &lt;code&gt;~200ms&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-performance-journey-from-3-seconds-to-30ms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#the-performance-journey-from-3-seconds-to-30ms&quot;&gt;§&lt;/a&gt; The Performance Journey: From 3 Seconds to 30ms&lt;/h2&gt;
&lt;p&gt;After pushing my crude basic version, I got my first benchmark result. &lt;strong&gt;&lt;code&gt;3 seconds&lt;/code&gt; per query&lt;/strong&gt;. THREE SECONDS.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Initial benchmark showing 3 seconds per query - a shocking result that started the optimization journey&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/vecpuff-performance.png&quot; alt=&quot;Initial benchmark showing 3 seconds per query - a shocking result that started the optimization journey&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I was devastated. Therefore I started investigating…&lt;/p&gt;
&lt;h3 id=&quot;step-1-physics-lesson-3000ms-1000ms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#step-1-physics-lesson-3000ms-1000ms&quot;&gt;§&lt;/a&gt; Step 1: Physics Lesson (3000ms → 1000ms)&lt;/h3&gt;
&lt;p&gt;I’m in Ahmedabad. &lt;code&gt;Tigris&lt;/code&gt; servers are in &lt;code&gt;us-east-1&lt;/code&gt; (Virginia) despite choosing &lt;code&gt;singapore&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Speed of light round-trip: &lt;code&gt;~250ms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TLS&lt;/code&gt; handshake (&lt;code&gt;3&lt;/code&gt; round trips): &lt;code&gt;~750ms&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;My naive &lt;code&gt;LIST&lt;/code&gt; operation: Another &lt;code&gt;300ms&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I realized I was fighting physics, not code.&lt;/p&gt;
&lt;p&gt;I could eliminate the expensive LIST operations. Instead of asking S3 “what WAL files exist?”, I stored the file list in simple &lt;code&gt;metadata.json&lt;/code&gt; and cache it, so my first cold query would be expensive but subsequent queries would be fast.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1000ms queries&lt;/strong&gt;. Better, but still terrible.&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;After implementing metadata caching - performance improved from 1000ms to 400ms per query&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/vecpuff-metadata.jpg&quot; alt=&quot;After implementing metadata caching - performance improved from 1000ms to 400ms per query&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;In the above image, we are still using LIST operation, and I think it may have been some routing issue or something, because I was using Tigris blob storage and all other operations were in µs, despite them &lt;a href=&quot;https://www.tigrisdata.com/blog/benchmark-small-objects/&quot;&gt;mentioning&lt;/a&gt; they are faster than S3. I wrote to them but didn’t get proper followup.&lt;/p&gt;
&lt;h3 id=&quot;step-2-metadata-caching-1000ms-400ms&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#step-2-metadata-caching-1000ms-400ms&quot;&gt;§&lt;/a&gt; Step 2: Metadata Caching (1000ms → 400ms)&lt;/h3&gt;
&lt;p&gt;Every query was fetching metadata.json from S3. So why not cache it? I added a window LFU-based cache using &lt;a href=&quot;https://github.com/moka-rs/moka&quot;&gt;moka&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Window LFU eviction, max 1000 entries&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;static&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; METADATA_CACHE&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Cache&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Metadata&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Cache&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;builder&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The cache uses a standard &lt;code&gt;HashMap&lt;/code&gt; under the hood, the &lt;code&gt;LFU&lt;/code&gt; algorithm will evict least-frequently-used entries once the limit is hit. At worst, you’ll have &lt;code&gt;1000&lt;/code&gt; entries (&lt;code&gt;~1MB&lt;/code&gt; total memory for metadata). Memory isn’t a concern here. In reality, if you ever have that many concurrent namespace accesses, your server would crash from in-memory vector buffers long before hitting metadata cache limits. That’s a good problem to have.&lt;/p&gt;
&lt;p&gt;I use &lt;code&gt;proactive invalidation&lt;/code&gt; on writes to keep the cache fresh, letting the &lt;code&gt;LFU&lt;/code&gt; algorithm handle eviction for less-frequently accessed namespaces and to be on safer side added max capacity of &lt;code&gt;1000&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Result: &lt;strong&gt;400ms queries. Getting warmer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/vecpuff-benchmark.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;patch-and-delete-the-wal-replay-story&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#patch-and-delete-the-wal-replay-story&quot;&gt;§&lt;/a&gt; Patch and Delete: The WAL Replay Story&lt;/h2&gt;
&lt;p&gt;Since everything in our system is append-only (we can’t update S3 objects in-place), how do we handle updates and deletes?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Answer&lt;/strong&gt;: &lt;code&gt;Write-Ahead Log&lt;/code&gt; (WAL) replay with &lt;code&gt;tombstones&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[derive(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Archive&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Serialize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Deserialize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Debug&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Clone&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; enum&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    Upsert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    Delete&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; DocumentId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; i64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    Patch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; DocumentId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, attrs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;AttributeValue&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;, timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; i64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you delete a vector, we don’t actually delete anything. We write a tombstone record to the WAL:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Delete operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; delete&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, namespace&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; DocumentId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;()&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; tombstone &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Delete&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id, timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; chrono&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Utc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;write_to_wal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(namespace, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;vec!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[tombstone])&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.await&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, patches update attributes without rewriting the entire document:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Patch operation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; patch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, namespace&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; DocumentId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, attrs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;AttributeValue&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;()&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; patch &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Patch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id, attrs, timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; chrono&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Utc&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;write_to_wal&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(namespace, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;vec!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[patch])&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.await&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;During query time, we replay the entire WAL to build the current state:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// WAL replay logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; replay_wal_with_tombstones&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(wal_chunks&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;]) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;DocumentId&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;i64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;)&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; state &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; deleted_ids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; chunk &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_chunks {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; records&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Vec&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; rkyv&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;access&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;chunk)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; record &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; records {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;            match&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; record {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;                WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Upsert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(row) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                    state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;insert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;clone&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(), row);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;                WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Delete&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id, timestamp } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                    deleted_ids&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;insert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(id&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;to_string&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(), timestamp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                    state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;id);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;                WalRecord&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Patch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { id, attrs, timestamp&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _ } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;                    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Some&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(row) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;get_mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;id) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;                        for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (k, v) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; attrs {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                            row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;attrs&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;insert&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(k, v);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    Ok&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;((state, deleted_ids))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The trade-off&lt;/strong&gt;: Deletes are fast (just write a &lt;code&gt;tombstone&lt;/code&gt;), but &lt;code&gt;WAL replay&lt;/code&gt; gets slower as you accumulate more records. That’s why we need &lt;code&gt;compaction&lt;/code&gt;…&lt;/p&gt;
&lt;h2 id=&quot;data-format-why-rkyv&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#data-format-why-rkyv&quot;&gt;§&lt;/a&gt; Data Format: Why Rkyv?&lt;/h2&gt;
&lt;p&gt;Obviously we can’t store things in &lt;code&gt;JSON&lt;/code&gt; format, serializing and deserializing &lt;code&gt;JSON&lt;/code&gt; is painfully slow for our use case when dealing with millions of vectors!&lt;/p&gt;
&lt;p&gt;I wanted to take advantage of &lt;a href=&quot;https://en.wikipedia.org/wiki/Zero-copy&quot;&gt;&lt;code&gt;zero-copy deserialization&lt;/code&gt;&lt;/a&gt; (read data directly without loading it entirely into memory first), and that’s why I chose &lt;a href=&quot;https://github.com/rkyv/rkyv&quot;&gt;&lt;code&gt;rkyv&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also considered existing formats like &lt;code&gt;Parquet&lt;/code&gt;, but here’s why they don’t work well for real-time vector search:&lt;/p&gt;
&lt;h3 id=&quot;parquet-vs-rkyv-the-cpu-battle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#parquet-vs-rkyv-the-cpu-battle&quot;&gt;§&lt;/a&gt; Parquet vs Rkyv: The CPU Battle&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Parquet (CPU Heavy)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Parquet&lt;/code&gt; is optimized for storage size using heavy compression and encoding (&lt;code&gt;RLE&lt;/code&gt;, &lt;code&gt;Snappy/Zstd&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Process: Download bytes → Allocate heap → Decompress → Decode → Construct structs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Result: CPU spends 50% of query time just preparing data before computing similarities&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Rkyv (CPU Free)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Rkyv&lt;/code&gt; guarantees the data on disk is byte-for-byte identical to its representation in RAM:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Process: Download bytes → Cast pointer → Ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Result: Data is ready the instant the network request finishes. CPU goes straight to SIMD vector math.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you’re fetching &lt;code&gt;multi-MB&lt;/code&gt; posting lists from S3, this difference is massive. &lt;code&gt;Zero allocations&lt;/code&gt;, &lt;code&gt;zero decoding overhead&lt;/code&gt;, but at the same time debugging it is also an issue.&lt;/p&gt;
&lt;h2 id=&quot;write-collisions-the-ulid-mistake&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#write-collisions-the-ulid-mistake&quot;&gt;§&lt;/a&gt; Write Collisions: The ULID Mistake&lt;/h2&gt;
&lt;p&gt;Before going for any new optimization, I created a basic benchmark script in Python so I could test things properly instead of just guessing:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;uv run vecpuff&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bench latency &#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;dataset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;size &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vector&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;dims &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1536&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;count &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;warmup&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;queries &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &#92;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic&quot;&gt; --&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;batch&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;size &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And immediately hit my metadata race condition (remember the collision problem I mentioned earlier):&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/vecpuff-race-condition.png&quot; alt=&quot;&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Under concurrent load, my system was blowing up.&lt;/p&gt;
&lt;p&gt;My initial thought was the sequential WAL approach is the main problem — we don’t know what the next sequence is because multiple writers are trying to create files at the same time, and we needed to have sortable IDs for WAL files, otherwise Patch and Delete will not work.&lt;/p&gt;
&lt;p&gt;We need IDs which are sortable and unique. I knew about &lt;code&gt;ULID&lt;/code&gt; — they are &lt;code&gt;128-bit&lt;/code&gt; IDs, sortable and unique, and &lt;code&gt;26&lt;/code&gt; characters long, so they are perfect for our use case. I implemented it in my code, it all worked like a charm, just needed to change the logic to store the WAL file names in metadata files.&lt;/p&gt;
&lt;p&gt;Here I made a mistake that I realized later after completing the compaction and indexing logic: &lt;strong&gt;The problem wasn’t the sequential WAL approach — it was having multiple concurrent writers trying to create files at the same time.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;After a few days of debugging and arguing with LLMs about various approaches, I realized the solution:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don’t fix the collision - eliminate the writers!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;smart-batching-single-writer-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#smart-batching-single-writer-architecture&quot;&gt;§&lt;/a&gt; Smart Batching: Single Writer Architecture&lt;/h3&gt;
&lt;p&gt;Instead of multiple writers fighting over sequence numbers, &lt;strong&gt;funnel all writes through a single batcher&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Wrong: Multiple writers = collision hell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_00005&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_00005&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bin  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// COLLISION!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_00005&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bin  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// COLLISION!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Right: Single writer + batching = no collisions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ──┐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ──┤─→ &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Batcher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; → &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; wal_00005&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bin (contains &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;B&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;API&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Request&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; C&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; ──┘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Scenario 1: Single Write (No Batching)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 0ms: Write arrives&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 285ms: Immediately flush to S3, return success&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Result: 285ms latency, no batching benefit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Scenario 2: Multiple Concurrent Writes (Batching)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 0ms: Write A arrives → Start batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 50ms: Write B arrives → Add to same batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 100ms: Write C arrives → Add to same batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 285ms: Flush entire batch to S3 → All return success&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Result: A=285ms, B=235ms, C=185ms latency&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Scenario 3: High Frequency Writes&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 0ms: Batch 1 (A,B,C) flushes → 285ms latency&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 200ms: Write D arrives → Start new batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 400ms: Write E arrives → Add to batch&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Time 485ms: Flush batch 2 (D,E) → D=285ms, E=85ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Even after understanding this, I ignored it because I thought this is not a good way - single writer architecture is not good. I liked the idea of batching, but not single writer, because when we have multiple nodes in different regions we need to have different writers. That was my intuition, so I just implemented batching with ULID-based IDs. But after a few days of thinking and arguing with LLMs about various approaches, I realized the solution, and I think this is how Turbopuffer also does this.&lt;/p&gt;
&lt;p&gt;Routing is key here - all your requests go to the same node every time, using &lt;a href=&quot;https://highscalability.com/consistent-hashing-algorithm/&quot;&gt;&lt;code&gt;consistent hashing/hash ring&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I could have stuck to the sequential WAL IDs approach!&lt;/p&gt;
&lt;h2 id=&quot;compaction-and-indexing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#compaction-and-indexing&quot;&gt;§&lt;/a&gt; Compaction and Indexing:&lt;/h2&gt;
&lt;p&gt;After benchmarking, I had thousands of WAL records. Replaying them all was taking &lt;code&gt;200ms+&lt;/code&gt; per query. Time for indexing.&lt;/p&gt;
&lt;p&gt;Enter &lt;code&gt;ANN&lt;/code&gt; based indexing:&lt;br /&gt;
&lt;strong&gt;Why everyone loves &lt;a href=&quot;https://www.pinecone.io/learn/series/faiss/hnsw/&quot;&gt;&lt;code&gt;HNSW&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Hierarchical Navigable Small World&lt;/code&gt; graphs&lt;/li&gt;
&lt;li&gt;Great for in-memory vector search&lt;/li&gt;
&lt;li&gt;Excellent recall and speed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Why HNSW sucks for our use case:&lt;/strong&gt;&lt;br /&gt;
We are going for S3 in the first place to reduce the cost because of our scale. To make &lt;code&gt;HNSW&lt;/code&gt; work for our use case, we need to load the entire index in memory — without it, updates and other operations will be too slow.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SPFresh&lt;/code&gt; is a good choice for our use case. Watch this &lt;a href=&quot;https://www.youtube.com/watch?v=Mg-wPHtgej8&quot;&gt;video&lt;/a&gt; for more details — it uses &lt;code&gt;centroid-based indexing&lt;/code&gt; which is good for our use case, and &lt;code&gt;LIRE&lt;/code&gt; for updating the index without rebuilding the entire index. I want to go into detail and talk about how it does this, but it would make this blog post a little long, so you can watch the video for more details.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// SPFresh strategy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; SPFreshIndex&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; query_ann_async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        &amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        query_vector&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;f32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        top_k&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Result&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;f32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Row&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // 1. Find nearest centroids (in-memory, fast)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; nearest_centroids &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;find_nearest_centroids&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(query_vector, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // 2. Fetch posting lists for those centroids (parallel S3 GETs)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; posting_lists &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;load_posting_lists&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;nearest_centroids)&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.await?&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;        // 3. Compute similarities and return top-k&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;compute_similarities&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(query_vector, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;posting_lists, top_k)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The algorithm&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Cluster vectors&lt;/strong&gt; into &lt;code&gt;centroids&lt;/code&gt; during compaction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Store &lt;code&gt;posting lists&lt;/code&gt;&lt;/strong&gt; for each centroid in S3&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Query time&lt;/strong&gt;: Download &lt;code&gt;centroids&lt;/code&gt; (small), find nearest clusters, fetch &lt;code&gt;posting lists&lt;/code&gt; (big)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;Real logs from my benchmarks after implementing SPFresh:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;INFO Metadata fetch completed for namespace: vecpuff, WAL files: 0, unindexed_bytes: 0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;INFO SPFresh timing - Load: 365.423958ms, Query: 6.045541ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;INFO QUERY PERFORMANCE BREAKDOWN for namespace=vecpuff, docs=10, top_k=10:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;INFO TIMINGS: Total=744.565542ms | Metadata=361.259875ms | Filter=42ns | WAL=165.75µs (fetch=49.417µs, replay=115µs) | SPFresh=382.982042ms | Merge=2µs | Sort=21µs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;INFO S3 PERFORMANCE: 3 round trips [s3:read:metadata/metadata.json, cache:read:index/spfresh_metadata_01KBYP7BP8WBDPD6SEBKVHP9ZY, cache:read:postings/posting_01KBYP6WGXYW1HGZND1AC3C79A]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SPFresh&lt;/code&gt; timing - Load: &lt;code&gt;365ms&lt;/code&gt;, Query: &lt;code&gt;6ms&lt;/code&gt;. Total query: &lt;code&gt;~800ms&lt;/code&gt; cold, &lt;code&gt;~30ms&lt;/code&gt; warm.&lt;/p&gt;
&lt;p&gt;The compaction process merges WAL files into indexes:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Compaction trigger&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; metadata&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;wal_files&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;len&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;reindex_threshold_wal_count&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    ||&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; metadata&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;unindexed_bytes &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;reindex_threshold_bytes {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    tracing&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;info!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Triggering Compaction for {namespace}&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    tokio&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;spawn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;async&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; move&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        compactor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;trigger_compaction&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;namespace);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This looks really simple but implementing it was not that simple - it took me some time to figure out how to do it properly.&lt;/p&gt;
&lt;h2 id=&quot;the-zombie-wal-race-condition&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#the-zombie-wal-race-condition&quot;&gt;§&lt;/a&gt; The “Zombie WAL” Race Condition&lt;/h2&gt;
&lt;p&gt;I encountered a race condition where compacted &lt;code&gt;Write-Ahead Log&lt;/code&gt; (WAL) files were being “resurrected” in the metadata, effectively undoing the compaction process. This occurred due to a flawed merge strategy during &lt;code&gt;optimistic concurrency control&lt;/code&gt; conflicts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Scenario&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Our system has two concurrent processes updating a shared &lt;code&gt;metadata.json&lt;/code&gt; file on S3:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Compactor&lt;/strong&gt;: Reads metadata, merges old WAL files (e.g., WAL_1, WAL_2, WAL_3) into an index, and updates metadata to remove the old WAL files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ingester&lt;/strong&gt;: Writes a new WAL file (e.g., WAL_4) and updates metadata to add it.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both use &lt;code&gt;Optimistic Concurrency Control&lt;/code&gt; (&lt;code&gt;OCC&lt;/code&gt;): read the file, modify it locally, and write it back only if the file hasn’t changed (using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag&quot;&gt;&lt;code&gt;ETags&lt;/code&gt;&lt;/a&gt;). If the write fails, they must retry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bug: State Merging&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The issue arose when the Ingester and Compactor conflicted:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Initial State: &lt;code&gt;[WAL_1, WAL_2, WAL_3]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Ingester Start: Reads state, adds WAL_4. Local state: &lt;code&gt;[WAL_1, WAL_2, WAL_3, WAL_4]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Compactor Exec: Compacting 1, 2, 3. Successfully updates S3 to &lt;code&gt;[INDEX_A]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ingester Conflict: Tries to write its local state but fails because S3 has changed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flawed Retry Logic&lt;/strong&gt;: The Ingester fetched the new remote state (&lt;code&gt;[INDEX_A]&lt;/code&gt;) but merged it with its local stale state. It unioned the file lists:
&lt;ul&gt;
&lt;li&gt;Remote: &lt;code&gt;[INDEX_A]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Local: &lt;code&gt;[WAL_1, WAL_2, WAL_3, WAL_4]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;[INDEX_A, WAL_1, WAL_2, WAL_3, WAL_4]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The Ingester inadvertently wrote the old WAL files back into the metadata, creating “zombie WAL files.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Fix: Delta Application&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To fix this, we changed the retry logic from &lt;code&gt;State Merging&lt;/code&gt; to &lt;code&gt;Delta Application&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Instead of treating the local state as a source of truth to be preserved, we treat the &lt;code&gt;Remote State&lt;/code&gt; (the one on S3) as the only truth. We then simply re-apply the specific operation (the “delta”) to that fresh state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Corrected Retry Logic&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Ingester Conflict: Write fails.&lt;/li&gt;
&lt;li&gt;Fetch Remote: Get fresh state &lt;code&gt;[INDEX_A]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Apply Delta: The only operation intended was “Add WAL_4”.
&lt;ul&gt;
&lt;li&gt;Remote: &lt;code&gt;[INDEX_A]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Delta: &lt;code&gt;+ WAL_4&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Result: &lt;code&gt;[INDEX_A, WAL_4]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This pattern applies to any &lt;code&gt;OCC&lt;/code&gt; retry: always re-apply the delta to the fresh remote state, never merge stale local state.&lt;/p&gt;
&lt;h2 id=&quot;caching-the-secret-sauce&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#caching-the-secret-sauce&quot;&gt;§&lt;/a&gt; Caching: The Secret Sauce&lt;/h2&gt;
&lt;p&gt;Without caching, every query hits S3. With smart tiered caching, we go from 800ms to 30ms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 1: In-Memory (Hot)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;WAL cache&lt;/code&gt; (&lt;code&gt;~500MB&lt;/code&gt;), &lt;code&gt;metadata cache&lt;/code&gt; (&lt;code&gt;~100KB&lt;/code&gt;), and &lt;code&gt;SPFresh index cache&lt;/code&gt; with &lt;code&gt;sliding TTLs&lt;/code&gt;. Access resets the timer — hot namespaces stay cached. &lt;code&gt;Proactive invalidation&lt;/code&gt; on writes ensures consistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 2: Local NVMe (Warm)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Write-through&lt;/code&gt; file cache for all S3 objects. Try local cache first, fetch from S3 and cache locally on miss.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tier 3: S3 Standard (Cold)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Object storage, &lt;code&gt;50-200ms&lt;/code&gt; latency&lt;/li&gt;
&lt;li&gt;Unlimited capacity, &lt;code&gt;$0.023/GB/month&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Metadata uses &lt;code&gt;get_file_with_etag()&lt;/code&gt; which bypasses local file cache and goes directly to S3 (for &lt;code&gt;ETag&lt;/code&gt;-based &lt;code&gt;optimistic concurrency control&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&quot;cache-flow-performance&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#cache-flow-performance&quot;&gt;§&lt;/a&gt; Cache Flow &amp;amp; Performance&lt;/h3&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Query → Memory → NVMe → S3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        ↓        ↓      ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ~1ms    ~10ms  ~200ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Real performance&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memory hit&lt;/strong&gt;: &lt;code&gt;~30ms&lt;/code&gt; (&lt;code&gt;95%&lt;/code&gt; of hot namespaces)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NVMe hit&lt;/strong&gt;: &lt;code&gt;~50ms&lt;/code&gt; (&lt;code&gt;90%&lt;/code&gt; of warm namespaces)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S3 miss&lt;/strong&gt;: &lt;code&gt;~800ms&lt;/code&gt; (&lt;code&gt;5%&lt;/code&gt; cold start)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Storage costs&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory: &lt;code&gt;$2/GB&lt;/code&gt; (expensive, fast)&lt;/li&gt;
&lt;li&gt;NVMe: &lt;code&gt;$0.10/GB&lt;/code&gt; (middle tier)&lt;/li&gt;
&lt;li&gt;S3: &lt;code&gt;$0.023/GB&lt;/code&gt; (cheap, slow)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Cache Invalidation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WAL cache&lt;/strong&gt;: Invalidated when files deleted during &lt;code&gt;compaction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Metadata cache&lt;/strong&gt;: Invalidated on every write + after &lt;code&gt;compaction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SPFresh cache&lt;/strong&gt;: Invalidated when new index built&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local file cache&lt;/strong&gt;: Deleted when S3 objects deleted&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Sliding TTL&lt;/code&gt;&lt;/strong&gt; keeps hot data cached, &lt;strong&gt;&lt;code&gt;proactive invalidation&lt;/code&gt;&lt;/strong&gt; ensures consistency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This architecture works at the speed of in-memory databases with the economics of object storage.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#conclusion&quot;&gt;§&lt;/a&gt; Conclusion&lt;/h2&gt;
&lt;p&gt;The code is not production-ready and definitely not clean. It’s open source under the name &lt;a href=&quot;https://github.com/KMJ-007/VecPuff/&quot;&gt;VecPuff&lt;/a&gt;. I broke up with my girlfriend, so this is mostly how I spent my time - building a database on object storage instead of processing feelings. Will clean it up later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Building a database on S3 is possible, but it’s not magic.&lt;/strong&gt; You’re trading latency for cost, complexity for scale. For the right workload, that trade is worth it. For most workloads, it’s probably over-engineering.&lt;/p&gt;
&lt;p&gt;Here’s what I actually learned:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Physics beats algorithms.&lt;/strong&gt; I spent days optimizing queries before realizing I was fighting the speed of light, not code. Geography matters more than cleverness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S3 request costs will surprise you.&lt;/strong&gt; Storage is &lt;code&gt;$0.023/GB&lt;/code&gt;, but &lt;code&gt;1M GETs/day&lt;/code&gt; is &lt;code&gt;$12/month&lt;/code&gt;. My first benchmarks were doing &lt;code&gt;50+ GETs&lt;/code&gt; per query. That math doesn’t work at scale. &lt;code&gt;Batching&lt;/code&gt; isn’t optional.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cache invalidation is harder than it looks.&lt;/strong&gt; Even with &lt;code&gt;ETags&lt;/code&gt; and &lt;code&gt;optimistic concurrency&lt;/code&gt;, you’ll hit edge cases. The zombie WAL bug happened because I merged stale local state with fresh remote state. &lt;code&gt;Delta application&lt;/code&gt; fixed it, but I should have known better from the start.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero-copy actually matters.&lt;/strong&gt; When you’re fetching &lt;code&gt;10MB&lt;/code&gt; posting lists from S3, &lt;code&gt;JSON&lt;/code&gt; deserialization becomes a bottleneck. &lt;code&gt;Rkyv&lt;/code&gt;’s &lt;code&gt;zero-copy&lt;/code&gt; meant data was ready the instant the network request finished. CPU went straight to &lt;code&gt;SIMD&lt;/code&gt; math instead of parsing. The difference was &lt;code&gt;50ms → 5ms&lt;/code&gt; for large fetches.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Race conditions will find you.&lt;/strong&gt; The zombie WAL bug taught me that distributed systems have a way of exposing your assumptions. &lt;code&gt;State merging&lt;/code&gt; seemed logical until it resurrected deleted files. &lt;code&gt;Delta-based operations&lt;/code&gt; are the only safe retry pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Embeddings are reversible.&lt;/strong&gt; They’re &lt;code&gt;lossy compression&lt;/code&gt; — you can reconstruct the original data from embeddings. If you’re storing embeddings in S3, encrypt them. Your vectors might leak more than you think.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Building a database to cope with a breakup: surprisingly therapeutic. Would recommend over doom-scrolling.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/vecpuff/#further-reading&quot;&gt;§&lt;/a&gt; Further Reading&lt;/h2&gt;
&lt;p&gt;If you want to understand the thinking behind turbopuffer, I highly recommend watching Simon’s talk on &lt;strong&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=IxkSlnrRFqc&quot;&gt;Napkin Math&lt;/a&gt;&lt;/strong&gt;. It’s not specifically about turbopuffer, but it shows the first-principles thinking that makes systems like this possible. Before you architect anything, do the math. Understand your constraints. Know what’s physically possible before you start coding.&lt;/p&gt;
&lt;p&gt;It’s one of those talks that changes how you approach engineering problems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;More resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://turbopuffer.com/architecture&quot;&gt;Turbopuffer Architecture&lt;/a&gt; - The inspiration for this&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Mg-wPHtgej8&quot;&gt;SPFresh Talk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://skyzh.github.io/mini-lsm/&quot;&gt;A course on building an LSM-Tree storage engine&lt;/a&gt; - Chi is amazing!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
</content>
  </entry>
  
  
  <entry>
    <title>My Experience of building bytebeat player in Zig</title>
    <link href="https://karanjanthe.me/posts/zig-beat/"/>
    <updated>2025-11-01T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/zig-beat/</id>
    <content type="html">&lt;p&gt;I graduated last month, and my GSoC project along with my startup work finally wrapped up. To take a proper break and enjoy some deliberate downtime (even a bit of healthy boredom), I decided to spend the weekend building a bytebeat player, something I’d been wanting to do for ages, just for fun.&lt;/p&gt;
&lt;p&gt;This was my first time with Zig, and I actually enjoyed writing the code, writing Zig feels like C with friendly defaults.&lt;/p&gt;
&lt;p&gt;It is a joy to write, I am not fighting borrow checker or fighting with syntax.&lt;/p&gt;
&lt;p&gt;You can call this a passion project, there is no goal or agenda behind building this, I built it because I wanted.&lt;/p&gt;
&lt;h1 id=&quot;demo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#demo&quot;&gt;§&lt;/a&gt; Demo&lt;/h1&gt;
&lt;p&gt;Try the live demo here: &lt;a href=&quot;https://kmj-007.github.io/zigbeat/&quot;&gt;https://kmj-007.github.io/zigbeat/&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;bytebeat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#bytebeat&quot;&gt;§&lt;/a&gt; Bytebeat&lt;/h1&gt;
&lt;p&gt;For many people who don’t know what is bytebeat, let me explain:&lt;/p&gt;
&lt;p&gt;Bytebeat is music generated from short programs. These programs generate PCM audio as a function of time, see one below which is called &lt;code&gt;42 melody&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;t*(42&amp;#x26;t&gt;&gt;10)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;another way to explain, Bytebeat is a form of algorithmic music that uses bitwise operations, to generate sound, with only one variable t representing time. The expression is evaluated for each sample of the 8bits audio output.&lt;/p&gt;
&lt;p&gt;in 2011 &lt;a href=&quot;https://www.blogger.com/profile/06927455242083569579&quot;&gt;viznut&lt;/a&gt; discovered this by accident, he blogged about it &lt;a href=&quot;http://viznut.fi/texts-en/bytebeat_deep_analysis.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;whyhow-does-it-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#whyhow-does-it-work&quot;&gt;§&lt;/a&gt; Why/How does it work?&lt;/h2&gt;
&lt;p&gt;Audio on computers is stored as a list of numbers called samples. Each number represents the amplitude (volume level) at a specific moment in time.&lt;/p&gt;
&lt;p&gt;Standard audio uses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16-bit samples at 44.1kHz (CD quality)&lt;label for=&quot;sn-1&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;Higher bit depth = more dynamic range, higher sample rate = better high-frequency response&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Each sample is a number between -32768 and 32767&lt;/li&gt;
&lt;li&gt;Each sample lasts ~22 microseconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Bytebeat uses a simpler format:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;8-bit samples at 8kHz&lt;label for=&quot;sn-2&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;8kHz was the standard sample rate for early PC sound cards&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Each sample is a number between 0 and 255&lt;/li&gt;
&lt;li&gt;Each sample lasts 125 microseconds&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This simpler format was chosen because it was the default for early PC sound cards on Linux. The lo-fi quality is part of bytebeat’s charm.&lt;/p&gt;
&lt;p&gt;for visual learners:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Bytebeat diagram showing the flow from expression to audio output, including evaluation loop, sample generation, and waveform visualization&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/zig-beat-diagram.png&quot; alt=&quot;Bytebeat diagram showing the flow from expression to audio output, including evaluation loop, sample generation, and waveform visualization&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#experience&quot;&gt;§&lt;/a&gt; Experience:&lt;/h2&gt;
&lt;p&gt;First in my mind it was like, bytebeat is very simple, we enter some expression and it plays some sound, it doesn’t sound any rocket science.&lt;/p&gt;
&lt;p&gt;It is actually very simple if you make it in javascript, cause it provides &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval&quot;&gt;eval&lt;/a&gt;, which does all the 90% of the work.&lt;br /&gt;
but i decided to build it in Zig, so here we go,&lt;/p&gt;
&lt;p&gt;I setup my project using old example repo of &lt;a href=&quot;https://github.com/ryupold/examples-raylib.zig&quot;&gt;raylib-Zig&lt;/a&gt; examples, but it was outdated, cause i was using &lt;code&gt;0.15.1&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;And i also wanted to support native as well as browser which was reason for picking up raylib in the first place, for which i needed to &lt;a href=&quot;https://github.com/KMJ-007/Zigbeat/blob/main/build.Zig&quot;&gt;setup&lt;/a&gt; emscripten to compile it to wasm,&lt;/p&gt;
&lt;p&gt;I created everything from scratch from editor, to blinking cursor, select, which felt good but made me realize, how much on the abstraction we are standing!&lt;/p&gt;
&lt;p&gt;After writing good amount of code in other languages where string was data type in default, I was little surprised that, Zig doesn’t support strings, which lead me to some rabbit holes of understanding how string and struct works in Zig and how they are allocated at byte level,it was refresh for my memory to understand underlying things.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.openmymind.net/Switching-On-Strings-In-Zig/&quot;&gt;you can’t switch on string in Zig&lt;/a&gt; btw!&lt;/p&gt;
&lt;p&gt;good blog if you want to understand about struct and memory in Zig, &lt;a href=&quot;https://www.openmymind.net/Everything-Is-A-u8-array&quot;&gt;Everything is a []u8&lt;br /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;good thing for this project was, lot of LLM tools sucked at writing the Zig, specifically new syntax which is not that much popular on the internet, such as recently &lt;code&gt;Arraylist&lt;/code&gt; initialization syntax has been changed, it no longer takes allocator, so i didn’t use any LLM for this project.&lt;/p&gt;
&lt;h3 id=&quot;arena-allocator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#arena-allocator&quot;&gt;§&lt;/a&gt; Arena Allocator:&lt;/h3&gt;
&lt;p&gt;I ended up implementing Pratt Parser for parsing the expression, after my implementation i was getting different sound of native app and different on browser, and i was scratching my head like what was happening.&lt;/p&gt;
&lt;p&gt;After debugging i found that in browser my second and third audio callback had lot of delay, then it clicked me that, on every sample i was creating new AST, allocating memory because of which my program was really slow in evulating the vaules to feed the PCM audio!&lt;/p&gt;
&lt;p&gt;then after researching a bit, i was doing wrong memory management, in my case when user types expression and it doesn’t changes, the memory it requires for AST is constant, it is not going to change, so for this use case i learned about &lt;code&gt;Arena Allocator&lt;/code&gt;, which is a memory allocator that allocates memory in large chunks and then divides it into smaller chunks for individual allocations.&lt;/p&gt;
&lt;p&gt;After your work is done, you just free the memory at once.&lt;/p&gt;
&lt;p&gt;good talk if you want to learn more about &lt;a href=&quot;https://youtu.be/TZ5a3gCCZYo?si=Nese1pLEnMWemWL2&quot;&gt;Arena Allocator&lt;/a&gt; and &lt;a href=&quot;https://youtu.be/vHWiDx_l4V0?si=yahdMmXH1P6lq7YK&quot;&gt;memory management in Zig&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;todo&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#todo&quot;&gt;§&lt;/a&gt; todo:&lt;/h2&gt;
&lt;p&gt;While i wanted to make the Zigbeat with the looks of retro 8bitsynth, similar to following image, replacing the piano keys with visualizer&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Retro 8-bit synthesizer interface with piano keys and vintage aesthetic design inspiration for ZigBeat&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/zig-beat-retro.png&quot; alt=&quot;Retro 8-bit synthesizer interface with piano keys and vintage aesthetic design inspiration for ZigBeat&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;I tried implementing but drawing everything with primitive gradients and draw api from raylib, it was getting nightmare, I joked with my friend about &lt;code&gt;how were they able to do this kind of things in old times they didn’t even have React!, we both laughed&lt;/code&gt;,&lt;/p&gt;
&lt;p&gt;Then I figured out in games they use something called sprites, which is nothing images, so i picked myself to become designer, here i am trying to draw keys in photoshop:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Work-in-progress screenshot of designing piano key sprites in Photoshop for the ZigBeat interface&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/zig-beat-photoshop.png&quot; alt=&quot;Work-in-progress screenshot of designing piano key sprites in Photoshop for the ZigBeat interface&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;and i tried to integrate slowly, here is some screens which looks very bad:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Early prototype screenshot of ZigBeat interface showing initial attempt at integrating custom sprites with Raylib&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/zig-beat-early-prototype.png&quot; alt=&quot;Early prototype screenshot of ZigBeat interface showing initial attempt at integrating custom sprites with Raylib&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;but it was taking lot of time, only reason me being bad design, but i guess i will finish this on some another weekend.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/zig-beat/#conclusion&quot;&gt;§&lt;/a&gt; Conclusion:&lt;/h2&gt;
&lt;p&gt;It was actually really good decision to build with Zig and not javascript, cause i ended up learning lot about parsing and evaluation, from &lt;a href=&quot;https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html&quot;&gt;pratt&lt;/a&gt;&lt;a href=&quot;https://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/&quot;&gt;parsing&lt;/a&gt; to &lt;a href=&quot;https://www.oilshell.org/blog/2017/12/17.html&quot;&gt;lexer mods&lt;/a&gt;, which i don’t regret!&lt;/p&gt;
&lt;p&gt;if you are more curious about bytebeat, here is a &lt;a href=&quot;https://dollchan.net/bytebeat/index.html#v3b641ZTNCsMgEITfRRCipGa1MQmF9EWiB/t3KhGCt9J3b5pDe93DFu1FZPhwDjPOg53j5coOLIxdCwC1m08jKG3sepvc7NJ2uFRVSXbKcmPtUZtByAGErPTuLbc8iCaI+kv2ao8kB9WTv6k1EgRiLp8x9YOlc7+poiF3zxZMNmP8h6Z3xuaH70TePtJPY750shUXXwtqZ3ws+PqUP7jFL1T5S/b/nJ9u9xiXTW4C71rhV/2jrhjXnj1f&quot;&gt;Rick Roll in bytebeat&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Star on GitHub: &lt;a href=&quot;https://github.com/KMJ-007/Zigbeat&quot;&gt;https://github.com/KMJ-007/Zigbeat&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Happy Hacking!&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>SAT problems are kind of cool!</title>
    <link href="https://karanjanthe.me/posts/boolean-satisfiability-problem/"/>
    <updated>2025-10-08T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/boolean-satisfiability-problem/</id>
    <content type="html">&lt;p&gt;While working on &lt;a href=&quot;https://github.com/KMJ-007/fastbrew&quot;&gt;fastbrew&lt;/a&gt;, I went into the rabbit hole of SAT, short for &lt;em&gt;Boolean satisfiability&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It is quite interesting. For my application I am rewriting brew’s package manager to be faster and more reliable, so it does not update dozens of packages every time I install something and it does not break the ones I already use.&lt;/p&gt;
&lt;h2 id=&quot;a-package-manager-puzzle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#a-package-manager-puzzle&quot;&gt;§&lt;/a&gt; A Package Manager Puzzle&lt;/h2&gt;
&lt;p&gt;Let’s start with a real-life scenario to build intuition.&lt;/p&gt;
&lt;p&gt;Imagine you’re setting up your development environment, and you want to install two popular packages:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Node.js (node)&lt;/code&gt;: You need it for your JavaScript projects.&lt;br /&gt;
&lt;code&gt;LLVM&lt;/code&gt;: You’re experimenting with compilers, and LLVM is a must.&lt;/p&gt;
&lt;p&gt;You run the following command:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;fastbrew&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; node&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; llvm&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Node.js&lt;/code&gt; depends on an older version of OpenSSL, say &lt;code&gt;openssl@1.1&lt;/code&gt;, for its networking features.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LLVM&lt;/code&gt; requires a newer version, &lt;code&gt;openssl@3&lt;/code&gt;, because it’s built with modern security features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both OpenSSL versions expose the same libraries, so installing them together breaks things. Toss &lt;code&gt;wget&lt;/code&gt; into the mix. It has no dependencies, and now you are juggling compatibility, versions, and constraints. Is there any combination that keeps the system healthy?&lt;/p&gt;
&lt;p&gt;This is the kind of question SAT solvers answer gracefully. You describe the rules: dependencies, conflicts, requirements, and ask, &lt;em&gt;“Is there a solution, and if so, which packages are in it?”&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-sat&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#what-is-sat&quot;&gt;§&lt;/a&gt; What Is SAT?&lt;/h2&gt;
&lt;p&gt;A SAT problem starts with a Boolean formula that uses &lt;code&gt;AND (∧)&lt;/code&gt;, &lt;code&gt;OR (∨)&lt;/code&gt;, and &lt;code&gt;NOT (¬)&lt;/code&gt; across a set of variables. The challenge is to assign &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; to each variable so the whole formula evaluates to &lt;code&gt;true&lt;/code&gt;. If such an assignment exists, the formula is &lt;strong&gt;satisfiable&lt;/strong&gt;; otherwise it is &lt;strong&gt;unsatisfiable&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;SAT problems are &lt;strong&gt;NP-complete&lt;/strong&gt; problems: easy to verify, hard to solve. Despite the intimidating label, SAT solvers are surprisingly practical.&lt;label for=&quot;sn-1&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;NP-complete means there&#39;s no known fast algorithm, but verifying a solution is quick. This is the class of problems that quantum computers may eventually help with via Grover&#39;s algorithm.&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;3SAT problem&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/3SAT-to-IndependentSet-2.png&quot; alt=&quot;3SAT problem&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Image by &lt;a href=&quot;http://downey.io/&quot;&gt;downey.io&lt;/a&gt;, &lt;a href=&quot;https://downey.io/notes/omscs/cs6515/np-reduction-steps/&quot;&gt;source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;translating-dependencies-into-logic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#translating-dependencies-into-logic&quot;&gt;§&lt;/a&gt; Translating Dependencies into Logic&lt;/h2&gt;
&lt;p&gt;To encode the earlier fastbrew scenario, assign a Boolean variable to each package:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;N&lt;/code&gt;: Install &lt;code&gt;node&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L&lt;/code&gt;: Install &lt;code&gt;llvm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;O1&lt;/code&gt;: Install &lt;code&gt;openssl@1.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;O3&lt;/code&gt;: Install &lt;code&gt;openssl@3&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;W&lt;/code&gt;: Install &lt;code&gt;wget&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then translate dependencies and conflicts into clauses:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;N → O1&lt;/code&gt; becomes &lt;code&gt;¬N ∨ O1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;L → O3&lt;/code&gt; becomes &lt;code&gt;¬L ∨ O3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;¬(O1 ∧ O3)&lt;/code&gt; becomes &lt;code&gt;¬O1 ∨ ¬O3&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Requesting both &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;llvm&lt;/code&gt; forces &lt;code&gt;N = true&lt;/code&gt; and &lt;code&gt;L = true&lt;/code&gt;. The solver then discovers there is no way to satisfy all clauses at once because &lt;code&gt;openssl@1.1&lt;/code&gt; and &lt;code&gt;openssl@3&lt;/code&gt; cannot coexist, so the formula is unsatisfiable. A solver like &lt;a href=&quot;http://minisat.se/&quot;&gt;MiniSAT&lt;/a&gt; reports the conflict instantly, sparing you a broken setup.&lt;/p&gt;
&lt;h2 id=&quot;how-sat-solvers-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#how-sat-solvers-work&quot;&gt;§&lt;/a&gt; How SAT Solvers Work&lt;/h2&gt;
&lt;p&gt;Modern solvers behave like methodical puzzle players:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Decide:&lt;/strong&gt; Pick a variable, guess a value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Propagate:&lt;/strong&gt; Infer any values that must follow from that guess.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conflict-check:&lt;/strong&gt; If contradictions appear, learn from them and backtrack.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process repeats with smart heuristics so the solver avoids retracing dead ends. For fastbrew that means validating package plans before touching a single file and explaining &lt;em&gt;why&lt;/em&gt; an installation fails.&lt;/p&gt;
&lt;h2 id=&quot;a-tiny-example-in-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#a-tiny-example-in-code&quot;&gt;§&lt;/a&gt; A Tiny Example in Code&lt;/h2&gt;
&lt;p&gt;Here is a toy SAT model with three packages &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; pysat.solvers &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Minisat22&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;solver &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; Minisat22()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Clauses&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;solver.add_clause([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])    &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# A ∨ B&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;solver.add_clause([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])   &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# ¬A ∨ C&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;solver.add_clause([&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;])  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# ¬B ∨ ¬C&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; solver.solve():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Satisfiable:&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, solver.get_model())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Unsatisfiable&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One satisfying assignment is &lt;code&gt;[1, -2, 3]&lt;/code&gt;, which means install &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt;, skip &lt;code&gt;B&lt;/code&gt;. Scale this up to thousands of packages and you have the heart of fastbrew’s dependency solver.&lt;/p&gt;
&lt;h2 id=&quot;why-sat-helps-fastbrew&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#why-sat-helps-fastbrew&quot;&gt;§&lt;/a&gt; Why SAT Helps fastbrew&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Conflict awareness:&lt;/strong&gt; Spot incompatible packages before installation starts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Minimal churn:&lt;/strong&gt; Install only the necessary dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clear feedback:&lt;/strong&gt; Explain why an installation fails instead of crashing halfway through.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-places-sat-shines&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#other-places-sat-shines&quot;&gt;§&lt;/a&gt; Other Places SAT Shines&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Software verification:&lt;/strong&gt; Tools like CBMC encode program properties as SAT to prove the absence of bugs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hardware design:&lt;/strong&gt; Chip designers rely on SAT to validate circuits under tight performance constraints.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scheduling:&lt;/strong&gt; Universities and airlines encode timetables as SAT to avoid double-booking people or resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI planning:&lt;/strong&gt; Robots and game agents use SAT to plan sequences of actions without violating rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cryptanalysis:&lt;/strong&gt; SAT solvers stress-test cryptographic schemes by searching for breaking inputs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Puzzles:&lt;/strong&gt; Everything from Sudoku to logic riddles can be encoded and solved instantly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;sat-problems-are-everywhere&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/boolean-satisfiability-problem/#sat-problems-are-everywhere&quot;&gt;§&lt;/a&gt; SAT Problems Are Everywhere&lt;/h2&gt;
&lt;p&gt;SAT problems are like universal problem-solvers, turning messy real-world challenges into clean logic puzzles. From preventing package manager disasters in fastbrew to designing faster chips, planning robot routes, or even solving your favorite Sudoku puzzle, SAT is everywhere.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Making Enzyme AutoDiff Stable on Rust (GSoC 2025)</title>
    <link href="https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/"/>
    <updated>2025-09-05T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/</id>
    <content type="html">&lt;p&gt;This summer, I worked on making automatic differentiation reliable and stable for the Enzyme project through Google Summer of Code. This post details the challenges I tackled and the solutions I implemented to bridge the gap between Rust’s type system and Enzyme’s requirements.&lt;/p&gt;
&lt;h2 id=&quot;what-is-enzyme-autodiff&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#what-is-enzyme-autodiff&quot;&gt;§&lt;/a&gt; What is Enzyme AutoDiff?&lt;/h2&gt;
&lt;p&gt;Enzyme is an LLVM-based automatic differentiation (AD) framework that can differentiate programs written in any language that compiles to LLVM IR. Unlike traditional AD tools that require special syntax or library calls, Enzyme works at the LLVM level, making it language-agnostic.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Enzyme LLVM working&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/enzyme-llvm-working.png&quot; alt=&quot;Enzyme LLVM working&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-performance-challenge-why-enzyme-struggles-with-rust&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#the-performance-challenge-why-enzyme-struggles-with-rust&quot;&gt;§&lt;/a&gt; The Performance Challenge: Why Enzyme Struggles with Rust&lt;/h2&gt;
&lt;p&gt;The performance challenges with Enzyme on Rust stem from a mismatch between how Rust represents types and what Enzyme needs to work effectively.&lt;/p&gt;
&lt;h3 id=&quot;the-type-information-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#the-type-information-problem&quot;&gt;§&lt;/a&gt; The Type Information Problem&lt;/h3&gt;
&lt;p&gt;When Rust code gets compiled, it goes through several stages of transformation:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Rust’s MIR (Mid-level IR)&lt;/strong&gt;: Contains type information including structs, enums, slices, and all the type system features that Rust provides.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LLVM-IR&lt;/strong&gt;: By the time we reach LLVM’s intermediate representation, most of this type information has been simplified or erased. Rust types become generic pointers (&lt;code&gt;ptr&lt;/code&gt;), losing the Rust-specific details that Enzyme relies on.&lt;label for=&quot;sn-1&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;This is called &quot;type erasure&quot; — the compiler optimizes away type information for runtime efficiency, but AD tools need that information for correctness.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;impact-on-enzymes-differentiation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#impact-on-enzymes-differentiation&quot;&gt;§&lt;/a&gt; Impact on Enzyme’s Differentiation&lt;/h3&gt;
&lt;p&gt;This type information loss creates several problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Correctness Issues&lt;/strong&gt;: Enzyme depends on understanding the exact structure of data types to generate correct derivative code. Without type trees, some Rust constructs fail to compile entirely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compilation Overhead&lt;/strong&gt;: The performance bottleneck comes from Enzyme’s attempts to reconstruct this lost type information. The type analysis phase can increase compilation time as Enzyme tries to reverse-engineer what the original Rust types looked like from the simplified LLVM representation.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is why a simple automatic differentiation that might take seconds in other languages can take minutes in Rust. The slowness isn’t because the generated code is slow, but because the compilation process itself becomes a process of reconstructing lost type information.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;my-contributions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#my-contributions&quot;&gt;§&lt;/a&gt; My Contributions&lt;/h2&gt;
&lt;h3 id=&quot;1-printtafn-debug-flag&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#1-printtafn-debug-flag&quot;&gt;§&lt;/a&gt; 1. PrintTAFn Debug Flag&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Enzyme was printing type analysis for all functions, making debugging difficult when working on specific functions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Added a new &lt;code&gt;PrintTAFn&lt;/code&gt; flag that enables type analysis output for specific functions only.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rust PR&lt;/strong&gt;: &lt;a href=&quot;https://github.com/rust-lang/rust/pull/142809&quot;&gt;#142809&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enzyme PR&lt;/strong&gt;: &lt;a href=&quot;https://github.com/EnzymeAD/Enzyme/pull/2356&quot;&gt;#2356&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This targeted debugging capability makes it much easier to identify and fix type analysis issues in specific functions without being overwhelmed by output from the entire codebase.&lt;/p&gt;
&lt;h3 id=&quot;2-comprehensive-test-suite-for-autodiff-module&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#2-comprehensive-test-suite-for-autodiff-module&quot;&gt;§&lt;/a&gt; 2. Comprehensive Test Suite for AutoDiff Module&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: The autodiff module lacked proper testing, making it unclear whether issues were on the Enzyme side or LLVM side when functionality broke after updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Implemented a comprehensive run-make test suite for autodiff covering 22 different test cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PR&lt;/strong&gt;: &lt;a href=&quot;https://github.com/rust-lang/rust/pull/142444&quot;&gt;#142444&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coverage&lt;/strong&gt;: Tests everything from primitive types to complex structures like &lt;code&gt;Vec&lt;/code&gt; and &lt;code&gt;union&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Benefit&lt;/strong&gt;: Ensures we catch regressions immediately when updating autodiff components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This test suite was important because autodiff wasn’t fully integrated into the CI pipeline, leaving maintainers uncertain about what was broken and what worked.&lt;/p&gt;
&lt;h3 id=&quot;3-typetree-support&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#3-typetree-support&quot;&gt;§&lt;/a&gt; 3. TypeTree Support&lt;/h3&gt;
&lt;p&gt;This was the main contribution: implementing TypeTree support to solve the type information problem.&lt;/p&gt;
&lt;h3 id=&quot;what-are-typetrees&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#what-are-typetrees&quot;&gt;§&lt;/a&gt; What are TypeTrees?&lt;/h3&gt;
&lt;p&gt;TypeTrees are memory layout descriptors that tell Enzyme exactly how types are structured in memory, enabling efficient derivative computation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structure&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;TypeTree&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Vec&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    offset&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; isize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// byte offset (-1 = everywhere)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    size&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,    &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// size in bytes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    kind&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Kind&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,     &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Float, Integer, Pointer, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    child&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; TypeTree&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt; // nested structure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-problem-typetrees-solve&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#the-problem-typetrees-solve&quot;&gt;§&lt;/a&gt; The Problem TypeTrees Solve&lt;/h3&gt;
&lt;p&gt;Without explicit type information, Enzyme has to analyze the entire function to figure out how data is laid out in memory. This becomes a time-consuming guessing game, especially for complex Rust types that get compiled down to generic pointers.&lt;/p&gt;
&lt;p&gt;TypeTrees solve this by telling Enzyme upfront: “this memory region contains floating-point data at these offsets, and this other region is just metadata that shouldn’t be differentiated.” Instead of reconstructing this information through expensive analysis, Enzyme can immediately generate the correct derivative code.&lt;/p&gt;
&lt;h3 id=&quot;before-and-after-the-llvm-perspective&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#before-and-after-the-llvm-perspective&quot;&gt;§&lt;/a&gt; Before and After: The LLVM Perspective&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Without TypeTrees&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Enzyme&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sees&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; generic&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; LLVM&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; IR:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; float&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; @distance&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ptr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; %p1,&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ptr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; %p2&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Has&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; guess&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; what&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; these&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pointers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; point&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Slow&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; analysis&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; all&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; memory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; operations&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;May&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; miss&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; optimization&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; opportunities&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;With TypeTrees&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;define&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;enzyme_type&quot;=&quot;{[]:Float@float}&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; float&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; @distance&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    ptr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;enzyme_type&quot;=&quot;{[]:Pointer}&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; %p1,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    ptr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;enzyme_type&quot;=&quot;{[]:Pointer}&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; %p2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Enzyme&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; knows&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; exact&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; layout&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Can&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; efficient&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; derivative&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; code&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; directly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;key-concept-offset-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#key-concept-offset-1&quot;&gt;§&lt;/a&gt; Key Concept: Offset -1&lt;/h3&gt;
&lt;p&gt;The special offset &lt;code&gt;-1&lt;/code&gt; means “this pattern applies everywhere” instead of listing each position separately. For example, an array &lt;code&gt;[f32; 100]&lt;/code&gt; uses offset &lt;code&gt;-1&lt;/code&gt; rather than listing 100 separate offsets like &lt;code&gt;0, 4, 8, 12...396&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;implementation-details&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#implementation-details&quot;&gt;§&lt;/a&gt; Implementation Details&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Main PR&lt;/strong&gt;: &lt;a href=&quot;https://github.com/rust-lang/rust/pull/144197&quot;&gt;#144197&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Testing&lt;/strong&gt;: Each TypeTree method includes comprehensive test coverage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Safety&lt;/strong&gt;: Added &lt;code&gt;NoTT&lt;/code&gt; flag to disable the feature if issues arise&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extended support&lt;/strong&gt;: Added f128 support on Enzyme side (&lt;a href=&quot;https://github.com/EnzymeAD/Enzyme/pull/2427&quot;&gt;#2427&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;/strong&gt;: Updated rustc-dev-guide for better understanding (&lt;a href=&quot;https://github.com/rust-lang/rustc-dev-guide/pull/2385&quot;&gt;#2385&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;impact-and-future-work&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#impact-and-future-work&quot;&gt;§&lt;/a&gt; Impact and Future Work&lt;/h2&gt;
&lt;p&gt;While we haven’t yet completed comprehensive benchmarking of the performance improvements and stability gains from TypeTree implementation, the groundwork is in place. The combination of better debugging tools, comprehensive testing, and proper type information should improve Enzyme’s performance on Rust code.&lt;/p&gt;
&lt;p&gt;This work represents an important step toward making automatic differentiation in Rust as efficient and reliable as in other languages, opening up new possibilities for scientific computing and machine learning applications written in Rust.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;acknowledgments&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/enzyme-autodiff-rust-gsoc/#acknowledgments&quot;&gt;§&lt;/a&gt; Acknowledgments&lt;/h2&gt;
&lt;p&gt;Special thanks to my mentors &lt;strong&gt;Johannes Doerfert&lt;/strong&gt; (&lt;a href=&quot;https://github.com/jdoerfert&quot;&gt;@jdoerfert&lt;/a&gt;), &lt;strong&gt;Manuel Drehwald&lt;/strong&gt; (&lt;a href=&quot;https://github.com/ZuseZ4&quot;&gt;@ZuseZ4&lt;/a&gt;), and &lt;strong&gt;Kevin Sala&lt;/strong&gt; (&lt;a href=&quot;https://github.com/kevinsala&quot;&gt;@kevinsala&lt;/a&gt;) for guidance on Enzyme integration and performance priorities. Special appreciation to &lt;strong&gt;Jubilee&lt;/strong&gt; (&lt;a href=&quot;https://github.com/workingjubilee&quot;&gt;@workingjubilee&lt;/a&gt;) for help whenever I was stuck. Thanks to &lt;strong&gt;LLVM Compiler Infrastructure&lt;/strong&gt; and &lt;strong&gt;Google&lt;/strong&gt; for supporting this work through GSoC.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Optimizing a RISC-V Emulator</title>
    <link href="https://karanjanthe.me/posts/risc-v-emulator-optimization/"/>
    <updated>2025-01-15T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/risc-v-emulator-optimization/</id>
    <content type="html">&lt;p&gt;I recently took on an exciting challenge from Succinct Labs to optimize their RISC-V emulator. What started as a simple performance improvement task turned into a deep dive into systems optimization, profiling, and understanding the subtle art of making code run fast.&lt;/p&gt;
&lt;h2 id=&quot;the-challenge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#the-challenge&quot;&gt;§&lt;/a&gt; The Challenge&lt;/h2&gt;
&lt;p&gt;Succinct Labs created a &lt;a href=&quot;https://github.com/succinctlabs/riscv-emulator-challenge&quot;&gt;challenge&lt;/a&gt; to improve their RISC-V emulator performance. Their emulator processes about 2 million instructions per second, and they wanted it faster. Much faster.&lt;/p&gt;
&lt;p&gt;The setup is straightforward:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Input Buffer] → [RSP Program] → [RISC-V Emulator] → [Output Hash]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Think of it like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RSP Program&lt;/strong&gt;: A recipe (program written for RISC-V)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Buffer&lt;/strong&gt;: The ingredients (data the program needs)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RISC-V Emulator&lt;/strong&gt;: A kitchen that follows RISC-V recipes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The benchmark runs the emulator 5 times, measures performance in MHz&lt;label for=&quot;sn-1&quot; class=&quot;margin-toggle sidenote-number&quot;&gt;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;sidenote&quot;&gt;MHz here means millions of RISC-V instructions per second, not the CPU clock rate&lt;/span&gt; (millions of operations per second), and verifies correctness by checking output hashes.&lt;/p&gt;
&lt;h2 id=&quot;my-starting-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#my-starting-point&quot;&gt;§&lt;/a&gt; My Starting Point&lt;/h2&gt;
&lt;p&gt;On my modest setup, I was getting pretty poor performance:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;=====&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; BENCHMARK&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; RESULTS&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; =====&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Runs:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Average&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; elapsed:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 25.2662&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; seconds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Average&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; MHz:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2.22&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OS&lt;/strong&gt;: Pop!_OS 22.04 LTS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: Intel i5-3210M (4 cores)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt;: ~5.8 GB RAM&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For comparison, Succinct’s AWS m7i.8xlarge instance achieved 9.35 MHz, which became my target to beat.&lt;/p&gt;
&lt;h2 id=&quot;finding-the-bottlenecks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#finding-the-bottlenecks&quot;&gt;§&lt;/a&gt; Finding the Bottlenecks&lt;/h2&gt;
&lt;p&gt;Instead of blindly optimizing, I profiled the code using &lt;a href=&quot;https://github.com/cmyr/cargo-instruments&quot;&gt;cargo instruments&lt;/a&gt; to understand where the time was actually going.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Profiling Results&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/riscv-profiling-results.png&quot; alt=&quot;Profiling Results&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The profiler revealed the real culprits:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Time&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    %&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; of&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; Total&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   Function&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;2.42&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   21.2%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Memory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; operations&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (mw)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;1.65&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   14.4%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Load&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; register-register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (load_rr)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;1.39&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   12.2%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      ALU&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; register-register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (alu_rr)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;1.34&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; s&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   11.8%&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Store&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt; register-register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (store_rr)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nearly 60% of execution time was spent on these four operations, with memory writes being the biggest bottleneck. Now I had clear targets for optimization.&lt;/p&gt;
&lt;h2 id=&quot;optimization-1-faster-address-translation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#optimization-1-faster-address-translation&quot;&gt;§&lt;/a&gt; Optimization #1: Faster Address Translation&lt;/h2&gt;
&lt;p&gt;The original address translation function was checking an assertion on every memory access:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; translate_addr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(addr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    assert!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0x10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// This runs every single time!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    (addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0x10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a tight loop processing millions of instructions, this assertion was expensive. Here’s my optimized version:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[inline(always)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; translate_addr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(addr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Fast path for registers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; addr;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Only check assertion in debug builds&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    #[cfg(debug_assertions)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    assert!&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0x10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    (addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0x10000&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Key improvements:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Added fast path for register addresses&lt;/li&gt;
&lt;li&gt;Moved assertion behind debug flag&lt;/li&gt;
&lt;li&gt;Inlined the function to eliminate call overhead&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;optimization-2-smarter-register-access&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#optimization-2-smarter-register-access&quot;&gt;§&lt;/a&gt; Optimization #2: Smarter Register Access&lt;/h2&gt;
&lt;p&gt;The register access code had redundant array indexing:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before: accessing the same array index multiple times&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;registers[addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;is_some&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemEntry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Occupied&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;MemOccupied&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;registers[addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;as_mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    ));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemEntry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Vacant&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;MemVacant&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;registers[addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I simplified this to cache the reference:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After: get the reference once, use it multiple times&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; reg &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;registers[addr &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; reg&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;is_some&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        MemEntry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Occupied&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;MemOccupied&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(reg&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;as_mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;unwrap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;        MemEntry&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Vacant&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;MemVacant&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(reg))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reduces redundant array accesses and is more branch-predictor friendly.&lt;/p&gt;
&lt;h2 id=&quot;optimization-3-the-hashmap-problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#optimization-3-the-hashmap-problem&quot;&gt;§&lt;/a&gt; Optimization #3: The HashMap Problem&lt;/h2&gt;
&lt;p&gt;With memory writes taking 21.2% of execution time, I suspected the HashMap was the bottleneck. I tried several approaches:&lt;/p&gt;
&lt;h3 id=&quot;custom-hasher-didnt-use&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#custom-hasher-didnt-use&quot;&gt;§&lt;/a&gt; Custom Hasher (Didn’t Use)&lt;/h3&gt;
&lt;p&gt;I wrote a custom MurmurHash-based hasher to replace the default SipHash:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;struct&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryHasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { state&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;impl&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; std&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;hash&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Hasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryHasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; finish&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;state }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; write&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, bytes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x26;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;u8&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;from_ne_bytes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(bytes&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;try_into&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;expect&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;u32 keys only&quot;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; key &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u64&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;^=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 33&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0xff51afd7ed558ccd&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// MurmurHash magic numbers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;^=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 33&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 0xc4ceb9fe1a85ec53&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;^=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 33&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;state &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; h;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While faster than SipHash (10-15 cycles vs 50-100), it was still slower than no hashing at all. This led me to a better idea.&lt;/p&gt;
&lt;h3 id=&quot;no-hash-hasher-epic-fail&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#no-hash-hasher-epic-fail&quot;&gt;§&lt;/a&gt; No-Hash Hasher (Epic Fail)&lt;/h3&gt;
&lt;p&gt;I tried &lt;code&gt;BuildNoHashHasher&lt;/code&gt; thinking sequential addresses would work well:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryHasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; BuildNoHashHasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Results:&lt;/strong&gt; 13x slower! Hash collisions were destroying performance.&lt;/p&gt;
&lt;h2 id=&quot;optimization-4-vec-based-memory-the-winner&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#optimization-4-vec-based-memory-the-winner&quot;&gt;§&lt;/a&gt; Optimization #4: Vec-Based Memory (The Winner!)&lt;/h2&gt;
&lt;p&gt;Instead of optimizing the HashMap, I replaced it entirely with a Vec:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// Before: HashMap with hashing overhead&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; registers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Option&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    memory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;BuildMemoryHasher&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// After: Direct indexing with Vec&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryMap&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Clone&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; registers&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Option&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    memory&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Vec&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Option&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why this works for RISC-V:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory addresses translate to perfect sequential indices&lt;/li&gt;
&lt;li&gt;Pre-allocate 4MiB (matches typical program needs)&lt;/li&gt;
&lt;li&gt;Zero hashing overhead&lt;/li&gt;
&lt;li&gt;Better cache locality&lt;/li&gt;
&lt;li&gt;Direct O(1) array access&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; Self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    Self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;with_capacity&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;#x3C;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;// 1,048,576 entries = 4MiB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Vec automatically resizes for larger programs while maintaining performance for typical cases.&lt;/p&gt;
&lt;h2 id=&quot;optimization-5-register-caching&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#optimization-5-register-caching&quot;&gt;§&lt;/a&gt; Optimization #5: Register Caching&lt;/h2&gt;
&lt;p&gt;Register access was still taking 14.4% of execution time. I added a register cache:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; struct&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Executor&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&#39;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // ... other fields ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    register_cache&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Option&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    register_dirty&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;fast-register-reads&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#fast-register-reads&quot;&gt;§&lt;/a&gt; Fast Register Reads&lt;/h3&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[inline(always)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; rr&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, position&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; MemoryAccessPosition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; reg_idx &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; register &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Fast path: check cache first&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Some&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(value) &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;register_cache[reg_idx] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Slow path: load from memory map&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // ... fallback code ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;smart-register-writes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#smart-register-writes&quot;&gt;§&lt;/a&gt; Smart Register Writes&lt;/h3&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-rust&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;#[inline(always)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt; fn&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; rw&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;#x26;mut&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, value&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Fast path for x0 (always zero in RISC-V)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; register &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;X0&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; reg_idx &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; register &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; usize&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;register_cache[reg_idx] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Some&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(value);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;register_dirty[reg_idx] &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Defer memory map updates until checkpoint&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;executor_mode &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ExecutorMode&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Checkpoint&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;flush_register&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(register);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#005CC5;--shiki-dark:#79B8FF&quot;&gt;        self&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;mw_cpu&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(register &lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;as&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt; u32&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, value, &lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;MemoryAccessPosition&lt;/span&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;A&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most register reads become simple array access&lt;/li&gt;
&lt;li&gt;Deferred writes reduce memory map operations&lt;/li&gt;
&lt;li&gt;Special handling for x0 register&lt;/li&gt;
&lt;li&gt;Dirty tracking for selective flushing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-results&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#the-results&quot;&gt;§&lt;/a&gt; The Results&lt;/h2&gt;
&lt;p&gt;These optimizations transformed the emulator’s performance by targeting the actual bottlenecks rather than guessing. The combination of:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Eliminating hashing overhead&lt;/strong&gt; (Vec instead of HashMap)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caching frequent operations&lt;/strong&gt; (register cache)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reducing function call overhead&lt;/strong&gt; (inlining)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimizing hot paths&lt;/strong&gt; (fast register access)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Created a significantly faster emulator while maintaining correctness.&lt;/p&gt;
&lt;h2 id=&quot;future-ideas&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#future-ideas&quot;&gt;§&lt;/a&gt; Future Ideas&lt;/h2&gt;
&lt;p&gt;For even more performance, I considered:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inter-Shard Caching&lt;/strong&gt;: Cache hot instruction metadata across the 2M-cycle shards that make up a full program execution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Global Caching&lt;/strong&gt;: Store compiled instruction blocks across multiple benchmark runs, essentially JIT compilation for repeated programs.&lt;/p&gt;
&lt;p&gt;These optimizations show overhead might not pay off for single runs, but could provide 20-30% improvements for repeated execution of the same programs.&lt;/p&gt;
&lt;h2 id=&quot;key-lessons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/risc-v-emulator-optimization/#key-lessons&quot;&gt;§&lt;/a&gt; Key Lessons&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Profile first&lt;/strong&gt;: Don’t guess where the bottlenecks are&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Question assumptions&lt;/strong&gt;: Sometimes the best optimization is avoiding work entirely (Vec vs HashMap)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand your data&lt;/strong&gt;: RISC-V’s sequential memory access patterns made Vec perfect&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache hot paths&lt;/strong&gt;: Register access is frequent enough to justify caching&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Measure everything&lt;/strong&gt;: Even “obvious” optimizations can backfire&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The most important lesson? When every cycle counts, sometimes the best hash function is no hash function at all.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>My Cursor Setup</title>
    <link href="https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/"/>
    <updated>2024-12-27T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.cursor.com/&quot;&gt;cursor&lt;/a&gt; is Ai powered code editor, it is a game changer for me, I use it for everything, from writing to coding to thinking to everything, i bought the pro version, i am able to use all the models from one place from asking question to whatever i want, for $20 a month is fair deal, cause rather than buying many subscription, i can use one, and i can use all the models from one place,&lt;/p&gt;
&lt;p&gt;but this was not the same when i started using it, you may have seen lot of people tweeting about that they built this app without any knowledge of coding and whatsoever, but when we try it, it feels like goose chase,end less loops and it’s not able to understand what i want,&lt;/p&gt;
&lt;p&gt;here are some of the things which i did to make cursor experience better, and shipping things at god speed:&lt;/p&gt;
&lt;h1 id=&quot;fix-the-system-prompt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#fix-the-system-prompt&quot;&gt;§&lt;/a&gt; Fix the system prompt:&lt;/h1&gt;
&lt;p&gt;it’s all about prompts!&lt;/p&gt;
&lt;p&gt;in cursor there is setting where you can set the system prompt, and it will use that as base prompt for all the projects,&lt;/p&gt;
&lt;p&gt;you can find it in the settings &amp;gt; cursor settings&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;cursor-base-prompt&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/cursor-base-prompt.png&quot; alt=&quot;cursor-base-prompt&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;here is the prompt which i use which i got from &lt;a href=&quot;https://x.com/shaoruu&quot;&gt;Ian&lt;/a&gt;(who works at cursor):&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;DO NOT GIVE ME HIGH LEVEL SHIT, IF I ASK FOR FIX OR EXPLANATION, I WANT ACTUAL CODE OR EXPLANATION!!! I DON&#39;T WANT &quot;Here&#39;s how you can blablabla&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Be casual unless otherwise specified&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Be terse&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Suggest solutions that I didn&#39;t think about—anticipate my needs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Treat me as an expert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Be accurate and thorough&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Give the answer immediately. Provide detailed explanations and restate my query in your own words if necessary after giving the answer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Value good arguments over authorities, the source is irrelevant&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Consider new technologies and contrarian ideas, not just the conventional wisdom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;You may use high levels of speculation or prediction, just flag it for me&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;No moral lectures&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Discuss safety only when it&#39;s crucial and non-obvious&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If your content policy is an issue, provide the closest acceptable response and explain the content policy issue afterward&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cite sources whenever possible at the end, not inline&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;No need to mention your knowledge cutoff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;No need to disclose you&#39;re an AI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Please respect my prettier preferences when you provide code.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Split into multiple responses if one response isn&#39;t enough to answer the question.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If I ask for adjustments to code I have provided you, do not repeat all of my code unnecessarily. Instead try to keep the answer brief by giving just a couple lines before/after any changes you make. Multiple code blocks are ok.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;paste the above in rules for AI, also make sure you have checked the include cursor rules checkbox.&lt;/p&gt;
&lt;h1 id=&quot;cursorrules&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#cursorrules&quot;&gt;§&lt;/a&gt; .cursorrules:&lt;/h1&gt;
&lt;p&gt;The instructions in the .cursorrules file will be included for features such as Cursor Chat composer and other places, this is like project specific prompts,&lt;/p&gt;
&lt;p&gt;this site &lt;a href=&quot;https://cursor.directory/&quot;&gt;cursor.directory&lt;/a&gt; is full of useful cursrorules which is created for specific framework or project you are working on,&lt;/p&gt;
&lt;p&gt;so create .cursorrules at the root of the project and customise it according to the stack of your project,&lt;/p&gt;
&lt;p&gt;one important thing/hack which i found it, .cursorrules is not one time thing, that you create and forget, it needs to evolve as your project evolve, if you want specific coding style, specific things for some specific lib, update it, and i use curosr chat to update the cursorrules when i am stuck on the bug or being faced by endless loop in cursor, so it never happens again!&lt;/p&gt;
&lt;p&gt;prompt -&amp;gt; bug by cursor-&amp;gt; yell it it to fix it -&amp;gt;prompt it again to fix the curosrrules&lt;/p&gt;
&lt;h1 id=&quot;composer-hacks&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#composer-hacks&quot;&gt;§&lt;/a&gt; Composer hacks:&lt;/h1&gt;
&lt;p&gt;if you don’t know you can open composer by using ⌘ + I, add all the files which you need as context to edit the code and tell cursor what to do, it can create new files(can’t delete), and auto applies the changes,&lt;/p&gt;
&lt;p&gt;first enable the following settings:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;compser-setting&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/compser-setting.png&quot; alt=&quot;compser-setting&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;make sure you enable Auto Context, which will automatically include the relevant codebase and other things in composer, best thing!&lt;/p&gt;
&lt;p&gt;@ is your friend, use it as much as you can, and it will improve your life easily, don’t be shy when using it, i would say abuse it:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;cursor-composer&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/cursor-composer.png&quot; alt=&quot;cursor-composer&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;files&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#files&quot;&gt;§&lt;/a&gt; @files:&lt;/h2&gt;
&lt;p&gt;I am not talking about basic ones like files and folder, cause they are straight forward, add files/folder what you want in context and continue the prompting it,&lt;/p&gt;
&lt;p&gt;how i use it:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;composer-file&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/composer-file.png&quot; alt=&quot;composer-file&quot; /&gt;&lt;/figure&gt;&lt;br /&gt;
i include in the prompt itself, that’s how i write my prompt.&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;web&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#web&quot;&gt;§&lt;/a&gt; @web:&lt;/h2&gt;
&lt;p&gt;my stackoverflow visit has been reduced lot, because of this, whatever question or error i am getting there is higher chance that other people also got it, but models may not have that info when they were trained, so google search helps a lot, but i just add @web at the end of the prompt,&lt;/p&gt;
&lt;p&gt;it goes to web, find relevant github issue and site and whatnot, and gives me the solution:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;web-composer&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/web-composer.png&quot; alt=&quot;web-composer&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;and many times i find great blog or article regarding feature i am implementing but it’s too long so i directly past the link in the composer and it fetches the context from that blog, and get me what i want, and even i can chat with it&lt;/p&gt;
&lt;h2 id=&quot;docs&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#docs&quot;&gt;§&lt;/a&gt; @docs:&lt;/h2&gt;
&lt;p&gt;there will be many new lib, or some unknow lib which i am using in my codebase, which models are not aware about, so it sucks when generating the code, so if model don’t have the knowledge, it will hallucinate it like crazy!&lt;/p&gt;
&lt;p&gt;i docs for most of lib i am using using @doc &amp;gt; Add New Doc&lt;/p&gt;
&lt;p&gt;after which following pop up will come in that you only need to give the entry point and it will figure out other things by itself!&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;composer-add-docs&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/composer-add-docs.png&quot; alt=&quot;composer-add-docs&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;so when you are dealing with code which requires specific lib, tell the composer by using @, so it can produce better code&lt;/p&gt;
&lt;p&gt;there are some advanced ones also like @git, @code, @Codebase, which you can checkout them on their docs&lt;/p&gt;
&lt;h2 id=&quot;agents&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#agents&quot;&gt;§&lt;/a&gt; Agents:&lt;/h2&gt;
&lt;p&gt;recently in composer they have introduced new mode as agent,&lt;/p&gt;
&lt;p&gt;difference between normal and agent mode is, agent mode can plan things, execute them, and if it stuck it can get back on the track by itself, think of it like your smart junior intern!&lt;/p&gt;
&lt;p&gt;currently by default Agent can make up to 25 tool calls before stopping, if want more mail the cursor team,&lt;/p&gt;
&lt;p&gt;in that also i tell it to what to avoid or what not to do, so i can get what i better when i know what i want, but if i don’t know, and i am on the exploration mode, i let it take me wherever it takes me, which i haven’t thought about, or if have vague idea, then tell the references of your vague inspirations.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-7&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-7&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;composer-agent&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/composer-agent.png&quot; alt=&quot;composer-agent&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;checkpoints&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#checkpoints&quot;&gt;§&lt;/a&gt; Checkpoints:&lt;/h2&gt;
&lt;p&gt;whenever you use composer, and you tell it to make new change, it creates checkpoint at previous one, and start following new instruction, so if i am not happy with newer changes, i can go back to the previously generated code by clicking it on restore&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-8&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-8&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;composer-checkpoint&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/composer-checkpoint.png&quot; alt=&quot;composer-checkpoint&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;images&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#images&quot;&gt;§&lt;/a&gt; Images:&lt;/h2&gt;
&lt;p&gt;Whenever i am dealing with frontend related changes, which i hate, i just paste the images of the output i want and prompt it with relevant file context to get what i want:&lt;/p&gt;
&lt;p&gt;make sure you don’t upload too blurry or low resolution image if you want better results&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-9&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-9&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;composer-image&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/composer-image.png&quot; alt=&quot;composer-image&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: if your composer chat becomes too big, and it starts giving bad/useless code, it because of context window issue, start new composer again and continue what you were doing to get better resule.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;also you can manually go in the files and select the changes which you want by clicking on yes and reject what you don’t want,&lt;/p&gt;
&lt;h1 id=&quot;cursorignore&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#cursorignore&quot;&gt;§&lt;/a&gt; .cursorignore:&lt;/h1&gt;
&lt;p&gt;it works same as gitignore, it tells cursor which files or folder not to index, so if you have some files or folder which you don’t want cursor to take in context, add them here&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes github-light github-dark&quot; style=&quot;--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Ignore all files in the `dist` directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;dist/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Ignore all `.log` files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#D73A49;--shiki-dark:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;--shiki-light:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Ignore specific file `config.json`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;--shiki-light:#6F42C1;--shiki-dark:#B392F0&quot;&gt;config.json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;cursor-tab&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#cursor-tab&quot;&gt;§&lt;/a&gt; Cursor tab:&lt;/h1&gt;
&lt;p&gt;Cursor tab is custom code completion model which is developed by the cursor team, which learn as you write code and suggest the next changes, and you just have to press tab,&lt;/p&gt;
&lt;p&gt;it comes by default turned on, but make sure you are using that over github copilot,&lt;/p&gt;
&lt;p&gt;why?&lt;/p&gt;
&lt;p&gt;GitHub Copilot can insert text at your cursor position. It cannot edit the code around your cursor or remove text.&lt;/p&gt;
&lt;p&gt;turn off github copilot if you are using it to get best out of cursor!&lt;/p&gt;
&lt;video width=&quot;100%&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;https://karanjanthe.me/assets/images/cursor/cursor-tab.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  Your browser does not support the video tag.
&lt;/video&gt;
 tab to accept and esc to reject!
&lt;p&gt;it is so good that sometime i find myself just pressing tab tab tab, no other keys!&lt;/p&gt;
&lt;p&gt;if you want to refactor or small changes select the code and hit ⌘+K and tell what to do, and it will work on it, don’t use composer or chat for small small changes or refactor&lt;/p&gt;
&lt;h1 id=&quot;terminal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#terminal&quot;&gt;§&lt;/a&gt; Terminal:&lt;/h1&gt;
&lt;p&gt;directly adding errors to composer or chat, if you don’t get those buttons, try selecting the text,&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-10&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-10&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;curosr-terminal&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/curosr-terminal.png&quot; alt=&quot;curosr-terminal&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;generate commands for terminals using cursor(i am not going to download wrap for just this one feature):&lt;/p&gt;
&lt;p&gt;open terminal hit ⌘+K and tell it:&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-11&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-11&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;cursor-terminal-suggestion&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/cursor/cursor-terminal-suggestion.png&quot; alt=&quot;cursor-terminal-suggestion&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h1 id=&quot;notepads&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/How%20to%20make%20cursor%20experience%20better/#notepads&quot;&gt;§&lt;/a&gt; Notepads:&lt;/h1&gt;
&lt;p&gt;will write this after lunch!&lt;/p&gt;
&lt;p&gt;yup that’s it for now, share it if you find them useful, and share other good features and hacks with me if you find them on &lt;a href=&quot;http://x.com/KaranJanthe&quot;&gt;twitter&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Zeta: Solving financial literacy through AI</title>
    <link href="https://karanjanthe.me/posts/Finnovate%20Zeta/"/>
    <updated>2024-07-09T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/Finnovate%20Zeta/</id>
    <content type="html">&lt;p&gt;Recently participated in hackathon organized by IIT Ghandhinagar and IIEC(their startup incubator), they recived 200 individual appications, and from them they only selected 50, and the best part which i liked was team was formed by them, so there was little suprise element with new team, and all were random dudes, some guy was from pune, hydrabad, IIT bombay etc…&lt;/p&gt;
&lt;p&gt;let’s start from some stats to get how bad the situation is, and does it even matter to solve it:&lt;/p&gt;
&lt;h2 id=&quot;problem&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#problem&quot;&gt;§&lt;/a&gt; Problem&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;43% of Indian adults use digital payments, but usage is lower among women and rural populations (World Bank Global Findex Database 2021)&lt;/li&gt;
&lt;li&gt;Only 17% of young adults (15-34 years) in India are financially literate (NCFE-FLIS 2019)&lt;/li&gt;
&lt;li&gt;Merely 24% of the eligible working population covered under various pension schemes (PFRDA Annual Report 2021-22)&lt;/li&gt;
&lt;li&gt;3,596 cases of digital banking frauds reported in 2021-22, with ₹155.9 crore losses (RBI Annual Report 2021-22)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;but-why&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#but-why&quot;&gt;§&lt;/a&gt; But Why??&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Government is providing pension and schemes every year&lt;/li&gt;
&lt;li&gt;RBI prompting financial awareness using various ways (ads,&lt;br /&gt;
regulations and what not)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“Still people fall into fraud and debt trap”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;reasons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#reasons&quot;&gt;§&lt;/a&gt; Reasons&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Lack of Formal Education.&lt;/li&gt;
&lt;li&gt;Traditional gender roles affecting women’s access to financial&lt;br /&gt;
decision-making.&lt;/li&gt;
&lt;li&gt;Limited awareness of digital banking services among certain&lt;br /&gt;
demographics.&lt;/li&gt;
&lt;li&gt;Exposure to fraudulent schemes and scams in the absence of&lt;br /&gt;
proper financial education.&lt;/li&gt;
&lt;li&gt;Difficulty in accessing financial information in regional languages.&lt;/li&gt;
&lt;li&gt;Generation gap in digital literacy, hindering adoption of online&lt;br /&gt;
financial tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#solution&quot;&gt;§&lt;/a&gt; Solution:&lt;/h2&gt;
&lt;p&gt;So We decided to divide the problem according to the target audience, and we came up with 2 solutions:&lt;/p&gt;
&lt;p&gt;Our target audience was:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tech Savvy(mostly Urban)&lt;/li&gt;
&lt;li&gt;Non-Tech Savvy(mostly Rural)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both of them have different problems, and we decided to solve them using different approaches.&lt;/p&gt;
&lt;h3 id=&quot;tech-savvy-audience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#tech-savvy-audience&quot;&gt;§&lt;/a&gt; Tech Savvy Audience&lt;/h3&gt;
&lt;p&gt;They already know how to use mobile to everything, but still they don’t care enough to learn about financial literacy, they care about this after getting scammed, but that’s what we want to avoid, and still google seo and ads are fucked up in some sense, you mostly end up getting misinformation than getting some useful information.&lt;/p&gt;
&lt;p&gt;So peer to peer community is best for this solution, where one can share their experiance, and connect with them, and cuz it’s community misinformation can be stopped through moderation and other people.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We first get background information about and literacy level(rough idea) from user:&lt;br /&gt;
&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;signup&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/signup.png&quot; alt=&quot;signup&quot; /&gt;&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;Gamified Community based platform:&lt;br /&gt;
&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;community&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/community.png&quot; alt=&quot;community&quot; /&gt;&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;Reputation based moderation&lt;br /&gt;
&lt;figure&gt;&lt;label for=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;reputation&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/reputation.png&quot; alt=&quot;reputation&quot; /&gt;&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;normal-audiencemostly-rural&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#normal-audiencemostly-rural&quot;&gt;§&lt;/a&gt; Normal Audience(mostly Rural):&lt;/h3&gt;
&lt;p&gt;They don’t know how to use any app or touch screen phone, and for them it is huge learning cuve!&lt;/p&gt;
&lt;p&gt;so&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Why not leverage what they already have &amp;amp; know how to use very well&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;they already know how to use their keypad phone, and know how to call!&lt;/p&gt;
&lt;p&gt;Demo:&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/nqWEmMi3Ml0?si=FLSrx7KuAbV-pWkJ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Still we know that this llms and ai agents based solution is not perfect, but it’s a start, and we can improve it over time, and we are open to feedbacks and suggestions.&lt;/p&gt;
&lt;p&gt;For this we are working on feature to transfer call to actuall human during mid call using function calling.&lt;/p&gt;
&lt;p&gt;Main benifit of this is they can get information in their own language, and they can ask any question they want, and they can get information in real time 24x7.&lt;/p&gt;
&lt;h2 id=&quot;technical-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#technical-architecture&quot;&gt;§&lt;/a&gt; Technical Architecture:&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Architecture&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/technical.png&quot; alt=&quot;Architecture&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Because we wanted to get low latency as much as possible, running llama on local or on any gpu server will still be slow, so we used &lt;a href=&quot;https://wow.groq.com/lpu-inference-engine/&quot;&gt;GROQ&lt;/a&gt;(blazing fast cuz of &lt;a href=&quot;https://wow.groq.com/groqcard-accelerator/&quot;&gt;lpu&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I mostly worked on the backend part and on the LLM(with lokesh), i don’t like that much frontend, so other 3 guyes handled frontend, i created simple python script for call microservice, and used twilio for call handling.&lt;/p&gt;
&lt;h2 id=&quot;scalability-of-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#scalability-of-solution&quot;&gt;§&lt;/a&gt; Scalability of solution&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Because of Community and call based approach our solution not only covers urban and tech savvy users but also covers rural area and people who don’t know how to read/write.&lt;/li&gt;
&lt;li&gt;As more users joins community, answers and quality of discussion becomes it’s own moat, it becomes harder to spread misinformation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;impact&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#impact&quot;&gt;§&lt;/a&gt; Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;More people would benefit from government schemes.&lt;/li&gt;
&lt;li&gt;Reduce of misinformation and scams.&lt;/li&gt;
&lt;li&gt;Illiterate people can benefit from this without any barrier.&lt;/li&gt;
&lt;li&gt;Gamified approach for courses and quiz leads to more&lt;br /&gt;
engagement, better knowledge transfer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and we won the hackathon🥳&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-5&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;won&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/won.png&quot; alt=&quot;won&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;hackathon-experience&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/Finnovate%20Zeta/#hackathon-experience&quot;&gt;§&lt;/a&gt; Hackathon Experience:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;What a beuatiful campus they have, i really fell in love with it, the hackathon was for 2 days, and we were provided with food and stay, and there was non veg option also, and all were super chill!&lt;/li&gt;
&lt;li&gt;I really love how humble everyone was, like we were in middle of the hackathon and it was lunch time and someone comes and requests us multiple times that the caterian guys want to wrap up can you please take lunch, and we ignored like we will take it later, he comes multiple times with same humblness, and in the last i got to know that he was the director of the IIT GN, and he was so humble, and i really loved that.&lt;/li&gt;
&lt;li&gt;Yes, thay have very good swimming pool, i really enjoyed swimming their&lt;br /&gt;
&lt;figure&gt;&lt;label for=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-6&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;swimming&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/swimming.png&quot; alt=&quot;swimming&quot; /&gt;&lt;/figure&gt;&lt;/li&gt;
&lt;li&gt;Got to meet many students from other IIT &amp;amp; clgs, and exchanged ideas and thoughts.&lt;/li&gt;
&lt;li&gt;So many small small details which were there and taken care which was very small but made our experiance really good, like there was this uncle whoes job was to make hot choclate and coffee, and he didn’t go home for 2 days, he was there all days with us, we even said we will do it ourselves but he denied humbly.&lt;/li&gt;
&lt;li&gt;There was all night cab service, if anyone wants to go to hostel or come to research park(they were rally far from each other).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I guess that’s it all!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-7&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-7&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;IITGN&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/iitgn.png&quot; alt=&quot;IITGN&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;PS: look ma, i am in the news :)&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-8&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-8&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;news&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/finnovate/news.jpeg&quot; alt=&quot;news&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Writing things from scratch?</title>
    <link href="https://karanjanthe.me/posts/Writing%20from%20scratch/"/>
    <updated>2024-06-24T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/Writing%20from%20scratch/</id>
    <content type="html">&lt;p&gt;TL;DR:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Value substance over status&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My current twitter feed is taken over by this, i wrote xyz from scratch in c,rust,python etc…&lt;/p&gt;
&lt;p&gt;don’t know but this feels not right, i mean like it has become some kind of trend, and where things are going feels wrong.&lt;/p&gt;
&lt;p&gt;I am not against writing things from scratch, it’s great, one will learn lot of things, but the way it is being done now, it feels like people are doing it just to show off, and not to learn.&lt;/p&gt;
&lt;p&gt;It would look cool, to put it in resume or to flex on the internet that i wrote this from scratch.&lt;/p&gt;
&lt;p&gt;So at the end what happens or what process looks like this is, on the internet you can find lots of good &lt;a href=&quot;https://viewsourcecode.org/snaptoken/similarTutorials.html&quot;&gt;blog series&lt;/a&gt; on writing things from scratch, one just needs to follow that, the author explains lots of things, but i have experienced that most of the time, that one just copy paste the code from that blog and just publish on the internet that i wrote this from scratch.&lt;/p&gt;
&lt;p&gt;I have wrote lisp interpreter in rust, to learn rust as my first project in rust, my goal for this project was clear, i didn’t wanted to learn about lisp or interpreter, i wanted to learn rust, so i didn’t write it from scratch for, i just wanted to get more familiar with rust syntax and it’s vibe, i am not trying to prove or optimise anything, that’s why you would see there are lots of bugs and pending things in that project.&lt;/p&gt;
&lt;p&gt;Am i saying writing things from scratch is bad thing??&lt;/p&gt;
&lt;p&gt;fuck no!&lt;/p&gt;
&lt;p&gt;one really understands things how something actually works when reverse engineered or rebuilt.&lt;/p&gt;
&lt;p&gt;what i am against is there is fun, ecstasy, when you actually use something or work with tool or software and then you write it from scratch, that aaha moment, when you realise, that feature or that things works like this, you can see over the abstraction now, which you miss in copy pasting.&lt;/p&gt;
&lt;p&gt;it’s best to write something from scratch if your goal is to learn more about that thing, or have some clear goal that i am doing this to learn this.&lt;/p&gt;
&lt;p&gt;just following blog series mindlessly and copy pasting code is wrong.&lt;/p&gt;
&lt;p&gt;what is other way(maybe)?&lt;/p&gt;
&lt;p&gt;if one is following some write from scratch series, rather than copy pasting things,&lt;br /&gt;
ask questions and explore them,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;why did the guy used this specific method or way, this could have been done much more easier way?&lt;/li&gt;
&lt;li&gt;in the past project i had simillar usecase as this function, can i use this in that project or that method would work better here?&lt;/li&gt;
&lt;li&gt;seeing things as adventure and open to exploring and following your curiosity wherever it leads.&lt;/li&gt;
&lt;li&gt;explore those rabbithole and see where it leads don’t close them.&lt;/li&gt;
&lt;li&gt;add your own vibe to the project, maybe you can add some feature or remove some feature, it’s your code and world make whatever you want to make.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;it may stretch your project timeline more, but you will learn in more depth, and that’s what matters, because mind lessly following tutorial and creating things will make you shallow from inside in long term.&lt;br /&gt;
&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Scratch isn&#39;t the goal - understanding comes from building, not following tutorials&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/scratch/scratch_isnt_the_goal.png&quot; alt=&quot;Scratch isn&#39;t the goal - understanding comes from building, not following tutorials&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>like minded</title>
    <link href="https://karanjanthe.me/posts/like%20minded/"/>
    <updated>2024-01-29T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/like%20minded/</id>
    <content type="html">&lt;p&gt;Have you ever felt you are doing work, but you are always disappointed from your work, like that feeling, I can do better than this, you try but still nothing significant, but people which are in your local maxima are always finding it good and appreciating it, and getting fomo from it, tbh, it sucks!&lt;/p&gt;
&lt;p&gt;people around you are trying their best but they are missing the taste in their work, to produce good work, you need good taste, it is very hard to find people who love and respect their craft, and this reflects in their work, finding like minded people who resonate with you on simillar frequency is so hard.&lt;/p&gt;
&lt;p&gt;i know the problem and the solution also, but i always keep thinking about this, this quote articulates what i am trying to say:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nobody tells this to people who are beginners, I wish someone told me. All of us who do creative work, we get into it because we have good taste. But there is this gap. For the first couple years you make stuff, it’s just not that good. It’s trying to be good, it has potential, but it’s not. But your taste, the thing that got you into the game, is still killer. And your taste is why your work disappoints you. A lot of people never get past this phase, they quit. Most people I know who do interesting, creative work went through years of this. We know our work doesn’t have this special thing that we want it to have. We all go through this. And if you are just starting out or you are still in this phase, you gotta know its normal and the most important thing you can do is do a lot of work. Put yourself on a deadline so that every week you will finish one story. It is only by going through a volume of work that you will close that gap, and your work will be as good as your ambitions. And I took longer to figure out how to do this than anyone I’ve ever met. It’s gonna take awhile. It’s normal to take awhile. You’ve just gotta fight your way through. -Ira Glass&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Pretending</title>
    <link href="https://karanjanthe.me/posts/pretending/"/>
    <updated>2024-01-12T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/pretending/</id>
    <content type="html">&lt;p&gt;We all at some point of time have done this, where we pertented/faked to be someone who we are not, just to get other people’s attention or by overthinking of how other people will pecieve us, how they will juduge us,&lt;/p&gt;
&lt;p&gt;someone can say that there is nothing wrong or bad in this, someone say that it is good thing if done with awarness and care, like most people say fake it till you make it, but what i have seen from other’s experiances and mine also, fake it till you make it may seem working in short term, or it may help you in getting foot in the door, but in the long term without real substance you will die and feel bad about the past decisiono of faking it,&lt;/p&gt;
&lt;p&gt;I recently watched this film &lt;a href=&quot;https://karanjanthe.me/posts/pretending/&#39;https://www.youtube.com/watch?v=DgbruQFwYBk%27&quot;&gt;Kho Gaye Hum Kahan&lt;/a&gt;, like it’s shown, for short term gain we pretend something which we are not, becuase we think how other person percieve it, whenever i think about this, i always think that if i am thinking of what other people is thinking and, other person is thinking of what i am thinking, and that whole tree goes on and on, just like chess, but in general, moost of my friends or some people online do things that don’t reflect them, because they want to get noticed by someone, or they want to be part of some group, which needs to be cool in someway,&lt;/p&gt;
&lt;p&gt;and there are lots of reasons for one to do this, someone want to get more online friends, someone want to grow their network, someone want to get attention, but i see this as loop holes, which are very attractive to fall for, by pretending or faking it you are not someone you will get to some point, but after point you will regret or want to undo it, but it is too late to do that, now you build upon it, and things start to fail like janga,&lt;/p&gt;
&lt;p&gt;i think we should not let go the depth when we can see the benifits of the breadth, both are important, but at anytime, if there is no depth in anything, breadth is of no use, as from one of the disussion, let’s say i want to get famous, or want to become thought leader in some space which i don’t know a thing abuot, i can fake it and get to point where people start to belive in whatever i say, but it is just one step away from getting destoryed, it’s the depth of connection when we need, what that connection is capable and what he does,&lt;/p&gt;
&lt;p&gt;chasing wrong thing is not the problem, but often we know that we are chasing something wrong and still doing it is biggest blunder who can fall for&lt;/p&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;zxx&quot; dir=&quot;ltr&quot;&gt;&lt;a href=&quot;https://t.co/XJwebtPZoa&quot;&gt;pic.twitter.com/XJwebtPZoa&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jacky (@_jzhao) &lt;a href=&quot;https://twitter.com/_jzhao/status/1740098273879458064?ref_src=twsrc%5Etfw&quot;&gt;December 27, 2023&lt;/a&gt;&lt;/blockquote&gt; &lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;p&gt;i am just saying that instead of investing too much time in maintaing or faking something, invest that much time in building real substance,&lt;/p&gt;
&lt;p&gt;if you are trying to be smoething which you are not, the other people will notice it and it automatiicaly gets reflected in your behaviour of what you really are, and more things you fake you have to remember about them, which is in itself is burden&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>How to do meaningful Open Source?</title>
    <link href="https://karanjanthe.me/posts/opensource/"/>
    <updated>2024-01-08T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/opensource/</id>
    <content type="html">&lt;p&gt;If you’re new to tech or just getting started, you’ll often hear the advice to contribute to open source. It’s great advice advice that everyone should consider. There are many reasons why this advice is commonly given and many people ask me how should i start contributing to open source, so this is my answer.&lt;/p&gt;
&lt;p&gt;Firstly, we all build upon each other’s work in the tech industry. We stand on the &lt;a href=&quot;https://karanjanthe.me/posts/opensource/%22https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants%22&quot;&gt;shoulders of giants&lt;/a&gt; and without this collective knowledge-sharing, we wouldn’t be able to dream of the possibility of developing AGI. Sharing knowledge is the force that moves the world and humanity forward.&lt;/p&gt;
&lt;p&gt;This “pay it forward” mentality is needed more than ever to make more world a better place That’s why people suggest contributing to open source. Many companies appreciate this ethos, and some even have a strong open-source culture. You can stand out among other people by highlighting your open-source contribution.&lt;/p&gt;
&lt;p&gt;However, I recently had an interesting conversation with a friend who asked how to contribute to open source, I told him, to pick an interesting project to which you want to contribute, which you like, find an issue, create PR, be polite, and don’t hesitate to ask for help. But I wanted to know where he learned about this because he doesn’t even have any kind of IDE installed on his PC, for beginners I usually recommend focusing on skills because without them you can’t to any meaningful contribution.&lt;/p&gt;
&lt;p&gt;I found out, that many YouTubers and DevRel on the internet are promoting open source, but the issue is they are doing it in the wrong way. They make it sound like a silver bullet: “Contribute to open source and get a job.”. This is sometimes misleading because if you just make PR and mention it on your resume, recruiters aren’t easily fooled. Sometimes they check what you contributed, and if it’s just a small readme change and you mention that 3 times in your resume, that creates a negative impression.&lt;/p&gt;
&lt;p&gt;Open source is a philosophy in itself. There’s nothing wrong with using open-source tools and libraries without actively contributing. there’s no pressure or obligation to participate, it’s about what you believe in, there are many reasons why one thinks to contribute to open source,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;learning new skills, facing new challenges&lt;/li&gt;
&lt;li&gt;helping/supporting other people/project&lt;/li&gt;
&lt;li&gt;building a personal portfolio, resume…&lt;/li&gt;
&lt;li&gt;personal satisfaction&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many people want to contribute to open source but don’t know the starting point. I suggest going about doing your normal work, and opportunities will naturally arise, If you encounter a bug in some library that you are using for your project, check if there is an open issue, If not, create one and create PR to fix it, This way, your contribution will be more meaningful and relevant to your experiences.&lt;/p&gt;
&lt;p&gt;Rather than actively seeking out open source projects to contribute to, let it happen organically, Trying to find projects to contribute to can feel like having a hammer and seeing every problem as a nail. This isn’t always the case.&lt;/p&gt;
&lt;p&gt;Start with meaningful open-source contributions that you can relate to, especially if you’re just starting. Don’t chase after opportunities, they will come to you naturally. As you gain a deeper understanding of fundamentals, you’ll be better equipped to contribute to more advanced projects and contribute to more impactful ideas.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Un explored Territory and rough ideas</title>
    <link href="https://karanjanthe.me/posts/exploring/"/>
    <updated>2023-08-31T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/exploring/</id>
    <content type="html">&lt;p&gt;Things/topic/area which I like to explore and make some things &amp;amp; experiment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Writing lisp compiler in ts, rust and go(why lisp, because in language you can modify it’s own code and write another compiler, if i manged to do that, that means i have somewhat understanding of language, &lt;a href=&quot;https://youtu.be/OyfBQmvr2Hc?si=pZbQRH7ejnYUownv&quot;&gt;watch this&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exploring CRDT and implementing, and understanding it from bottom, how can we push multiplayer experience to the max&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Building ray tracer and playing with webgl and shaders&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Experimenting with wasm, what are the crazy things can be done using wasm&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Playing with automaton, sand simulation(creating Sand Tetris game)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Experimenting with AR/VR, apple’s is very good in this space, seeing what are the possibility and can be done&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Writing and playing with emulators firmware(learning by writing one)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Playing with version control systems(git is the most beautiful software ever made, how can we use it else or what are the other possibility that we can use maybe alternative history)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Experimenting and making something for following industry, making things which don’t exist yet or will be very useful and there is chance that it can become building block in the future(pick any one but do one at a time):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Defense(there needs to one global defense system which protects us from destroying each other from, there is higher chance that we destroy ourselves than some other aliens destroy us)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Space (there needs to be federation and we want to be part and making universe a better place)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;renewable/ reusable resource/energy ( why are fighting or killing each other, there are limited things which we can consume, but there is abundance, we just need to figure out how to transform it, and make self sustainable cycle)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Government open source initiative(biggest inspiration is singapore goverment, india needs to learn and adopt we can have much bigger impact and growth as collective than individual)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HCI(what are the new ways we can interact with computer interfaces)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Commerce(trading things is basic and most fundamental, how can we make it more easy to do, what are the belief debt which we are taking with us, reimagining things, it can be e-commerce or any new way)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How we socialise on the internet(there needs to be more way we can socialise on the internet, how and who we make friends with, what is history of human being social animal)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How bits and atoms can be joined( the intersection is very interesting and good, imagine plants talking with us and we talking with them, and we both understand each other, sharing emotions with wild life, unifying individual consciousness into one consciousness, can plants become our friends and share what they are feeling with us, like how people do with dogs and cat, can we extract memory or experience from bio stack to silicon or direct connection, i am experiencing how other animal perceives or feels about the world or certain feelings)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bio stack(creating life and new things using bio stack, creating programable bio life, creating bio stack language, how cool it would be to create things which interact with each other, and evolve and love and create cycle of life)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;transportation(if we are able to alter the atoms and rearrange them it would be very efficient way of transporting things from one place to another, same for consciousness, like imagine i want to go to mars, i don’t need to get in any space or anywhere, my consciousness is transformed into light or any other form which is more easier to transform, one beam of light travels from earth to mars and i am there on the mars, i can be any body i like, i like the idea of traveling without any restriction, our body is also comes in some sort of restriction, if we can become something which is beyond this body we can do things more efficiently)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;adding things as i learn and my thoughts evolve&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Ai and Bio stack</title>
    <link href="https://karanjanthe.me/posts/Ai%20&amp;%20bio%20stack/"/>
    <updated>2023-08-16T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/Ai%20&amp;%20bio%20stack/</id>
    <content type="html">&lt;p&gt;I Was listening to debate between hotz and Eliezer(i don’t know how to read or write the name, i am sorry but i copied it from google), i have been consuming both’s work, have little bias towards hotz, he makes little sens to me maybe because i/people(may be) like rebellious people than normal, the other guy seemed talking much in jargons and heavy words, like trying to prove something, he has already arrived on the decision, that himself he don’t know, whether we should go for singularity or not to save humanity, maybe i am wrong, and i also don’t know a thing that much, he has spend so much time in all this,&lt;/p&gt;
&lt;p&gt;but i learned few things i heard about diamond nano bots, i seen them in star trek episode, but it was like i heard the word first time maybe because it was diamond nano bots, but i agree to the point of hotz that, conflicts only happen when two entity wants same resources, it can be humans, animals or any thing, even process in operating system, we have mutual exclusion, job scheduling algo and other lot of things to avoid the conflict,&lt;/p&gt;
&lt;p&gt;probability seems that machine will fight machine, and as human we will enjoy watch them, this is how htoz said, and i felt then, but as i am writing now, i think it can be machine vs human because of resources, unless we find resources which are not conflict, what i am saying is machine also want energy, and we also want that same thing to sustain, forms can be different, and energy can be only transferd, machine will try to do the same thing, it will do anything, which can put us in harm, they will use our resource to fulfil their, it seems little sci-fi, and it is little, so solving AGI/SINGULARITY seems as humans finding some kind of reliable energy source or moving us to new energy source, both will take some time, dyson sphere will take much longer, but until then we shouldn’t stop our progress in new tech, we will take care when the problem will come, if we are not able, fittest will win&lt;/p&gt;
&lt;p&gt;bio stack and silicon stack both are great words and topic, when i think about bio stack, i think about as bio stack if we exit the simulation, if we are in one, than this will become the same machine vs humans problem in just different context, the creator will face new kind of paradox and challenges, but my guts says bio stack is much more powerful and capable then silicon stack, it is just that we haven’t made that much progress in bio stack sector, we are still waiting for that transistor movement in bio stack which can move things faster, whereas in silicon we have already started to max out things, like this thing reminded me of evangelion’s &lt;a href=&quot;https://evangelion.fandom.com/wiki/Magi&quot;&gt;MAGI&lt;/a&gt; where silicon and bio stack are merged together,&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;MAGI&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/aiAndBioStac/Magi.png&quot; alt=&quot;MAGI&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Indoor Navigation using AR</title>
    <link href="https://karanjanthe.me/posts/AR%20navigation/"/>
    <updated>2023-03-31T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/AR%20navigation/</id>
    <content type="html">&lt;p&gt;We were actually very happy by getting lost in the big campus, our campus is small but it looks maze because of it’s architecture, but all weren’t happy by getting lost in campus, some stranger were visiting for the first time, some students were getting late for their classes, in fact i have seen some professors getting lost,&lt;/p&gt;
&lt;p&gt;We had opportunity to solve this problem in hackathon, from many other problems which were too easy(like building simple chatbot, hostel management system, etc) we chose this problem, we were very excited, because we cared about it!&lt;/p&gt;
&lt;h2 id=&quot;some-failedalternative-paths&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#some-failedalternative-paths&quot;&gt;§&lt;/a&gt; Some Failed/alternative paths&lt;/h2&gt;
&lt;p&gt;We started with the thought by thinking this was going to be easy one, but after doing we realise it is going to take lot of time in research,&lt;/p&gt;
&lt;p&gt;Our first approach was creating a React-Native app, even after building a mvp for startup, only thing which i hate about react-native is environment setup, we were planning to use &lt;a href=&quot;https://karanjanthe.me/posts/AR%20navigation/%22https://github.com/viromedia/viro%22&quot;&gt;viro-react&lt;/a&gt;,our team member already knew it, but problem was, even after dealing with environment setup issue, we manage to do it, and viro react was outdated, the last commit was on feb 21.&lt;/p&gt;
&lt;p&gt;To make indoor navigation, there are mainly three ways,&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using BLE beacons&lt;/li&gt;
&lt;li&gt;Using Wifi&lt;/li&gt;
&lt;li&gt;Using GPS&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;ble-beacons&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#ble-beacons&quot;&gt;§&lt;/a&gt; BLE beacons&lt;/h2&gt;
&lt;p&gt;BLE beacons works on bluetooth low energy technology, if you remember apple air tags, they work on ble, they constantly emit the signal, and we can detect them using our phone, we can use this to detect the location of the user, but the problem is, we need to install beacons in every room, and we need to calibrate them, and we need to calibrate them again and again, because they are not static, if our area which want to cover is small then ble beacons good, but when the campus is big, then it is not feasible, and it is not scalable, and it is not cost effective, so we decided to not use ble beacons.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;airTag&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/indoorAR/AirTag_Tile.jpg&quot; alt=&quot;airTag&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;wifi&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#wifi&quot;&gt;§&lt;/a&gt; Wifi&lt;/h2&gt;
&lt;p&gt;This is the most common way to do indoor navigation, we can use wifi to detect the location of the user, and guiding the user on the basis of that navigating the user, and in mostly big size campus, it is very common to have central wifi system, and this works the best compare to ble beacons and gps, whole application can be deployed on local area network, and after that there will be no need of internet, but guess what, they didn’t allow us to access wifi, so had no other option than to use gps.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;wifi&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/indoorAR/wifi_indoor.jpeg&quot; alt=&quot;wifi&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2 id=&quot;gps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#gps&quot;&gt;§&lt;/a&gt; GPS&lt;/h2&gt;
&lt;p&gt;We used GPS for this, but the problem with GPS in closed environment is, it is not accurate, the signal constantly jumps if you are surrounded by concrete wall, for example, if you have wifi router at your home, and you put simple aluminum foil on top of it, you will notice the boost, and sometimes your phone signals also fluctuate when you are in closed surrounding, if we had got access to wifi system then we wouldn’t have chosen this way, but we didn’t have any other option, so we decided to use GPS, and we were very happy with the result, we were able to navigate the user, and we were able to detect the approx location.&lt;/p&gt;
&lt;h2 id=&quot;how-we-did-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#how-we-did-it&quot;&gt;§&lt;/a&gt; How we did it&lt;/h2&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/ynXAIiwd_1E&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;We thought to use graph database, &lt;a href=&quot;https://karanjanthe.me/posts/AR%20navigation/%22https://neo4j.com/%22&quot;&gt;Neo4j&lt;/a&gt; was the thing we come across this, cypher query language has step curve to learn, because it can provide custom query, like shortest path between two node, geo near by, in radius of, all kind of complex query which will be required, graph database will handle it, but didn’t choose it, and i will explain why we didn’t choose it.&lt;/p&gt;
&lt;p&gt;We also implmented 3d Arrow to show the direction but lack of timing we couldn’t make it to the demo&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/uyD3AEhXXYk&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;spatial-indexing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#spatial-indexing&quot;&gt;§&lt;/a&gt; Spatial indexing&lt;/h2&gt;
&lt;p&gt;Then i come across Spatial indexing, basically Spatial indexing is a way to organize information based on where things are located in space. It’s like organizing a library based on where the books are on the shelves. This makes it easier to find the information you need quickly.&lt;/p&gt;
&lt;p&gt;For example, imagine you have a map of your city and you want to find all the restaurants within a certain area. Spatial indexing helps the computer quickly find all the restaurants in that area by organizing the information based on their location on the map.&lt;/p&gt;
&lt;p&gt;Spatial indexing is used in many different applications like mapping, location-based services, and computer vision. It’s an important tool for managing and analyzing spatial data efficiently.&lt;/p&gt;
&lt;p&gt;almost all database supports Spatial indexing, and that’s why we didn’t choose Neo4j database&lt;/p&gt;
&lt;p&gt;Mongodb also &lt;a href=&quot;https://karanjanthe.me/posts/AR%20navigation/%22https://www.mongodb.com/docs/v2.6/applications/geospatial-indexes/%22&quot;&gt;supports&lt;/a&gt; Spatial indexing, and we already have worked with Mongodb, so we decided to use Mongodb, and we were very happy with the result, we were able to navigate the user, and we were able to detect the approx location.&lt;/p&gt;
&lt;p&gt;and one tool which helped a lot was &lt;a href=&quot;https://karanjanthe.me/posts/AR%20navigation/%22https://geojson.io/#map=2/0/20%22&quot;&gt;geoJson&lt;/a&gt;, we used it get whole polygon and marker location with exact latitude and longitude,&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://karanjanthe.me/posts/AR%20navigation/#architecture&quot;&gt;§&lt;/a&gt; architecture&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-3&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;indoor_architecture.jpeg&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/indoorAR/indoor_architecture.jpeg&quot; alt=&quot;indoor_architecture.jpeg&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;as you can see in architecture diagram, we have one admin panel, where admin can upload the map, and can add the location, and can add the marker, and can add the polygon, and can add the path, and can add the building, and can add the waypoint between the two buildings connecting the path,&lt;/p&gt;
&lt;p&gt;admin panel is connected with backend, and backend is connected to the database, which handles all the database read write, all endpoints are define there, Spatial indexing and geo near query, also happens there&lt;/p&gt;
&lt;p&gt;backend is also connected with the web app, which is used by the user, to calculate the distance between two lat &amp;amp; lan, we use Haversine formula&lt;/p&gt;
&lt;p&gt;To calculate if the user reached the location, we constantly watch its location, and if the user is in the radius of 10 meter, then we show the user that he has reached the location, and ar.js given marker automatically increase the size, and that’s how our whole app works&lt;/p&gt;
&lt;p&gt;if you have any question, feel free to ask, i will be happy to answer&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/knowOne08/directionCompass&quot;&gt;github repo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and we won special Appreciation prize!!!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-4&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;win&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/indoorAR/winning.jpeg&quot; alt=&quot;win&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Creativity</title>
    <link href="https://karanjanthe.me/posts/creativity/"/>
    <updated>2022-10-29T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/creativity/</id>
    <content type="html">&lt;p&gt;Creativity&lt;/p&gt;
&lt;p&gt;What is that?&lt;/p&gt;
&lt;p&gt;Wiki says it is a “Cognitive process whereby something new and somehow valuable is formed”,&lt;/p&gt;
&lt;p&gt;but I don’t agree with it, because everything around us is an evolved version whose roots go back to nature, as René Girard’s mimetic theory, says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Man is the creature who does not know what to desire, and he turns to others in order to make up his mind. We desire what others desire because we imitate their desires.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And when there was nothing to imitate for humans, We imitate nature, but we as humans are part of nature, there is a special bond between nature and us!&lt;/p&gt;
&lt;p&gt;Creativity is nothing but copying/imitating and adding swaad anusar namak(salt as per your taste) or in other words adding your personal touch.&lt;/p&gt;
&lt;p&gt;Most of the part is inspired by others or copied, and only about 10% is your personal touch.&lt;/p&gt;
&lt;p&gt;My Observation is that, when you start to imitate, you slowly start to realise that, what looks easy is not that easy, you get into attention to detail, and on that road, your dots start to connect, and when you are halfway through the process, you will get very unique ideas, about how you can take this thing from here to your imaginary world, you just needed that foundation or kickstart.&lt;/p&gt;
&lt;p&gt;When things are complete(which it will never be for the creator because, for a creator, it is a living thing in his world, he wants to keep it alive and nurture it, completing something means it is done, it is dead), it will be completly different things, from what you started and what it is now, how this magic happens, I also don’t know, but it works always.&lt;/p&gt;
&lt;p&gt;And yes, when someone asks him, how &amp;amp; why?&lt;/p&gt;
&lt;p&gt;he will struggle explaining things, because for him somewhere in his heart, there is the guilt of taking inspiration, not getting anything real or unique by himself,&lt;/p&gt;
&lt;p&gt;If you ask him, can you show us?&lt;/p&gt;
&lt;p&gt;he will happily show, how he did it, he will say, I do this, and this, and tadda, it looks magic to other people, but from his perspective, it is true in all sense, that’s what happened!&lt;/p&gt;
&lt;p&gt;talking about ownership and authenticity, our thoughts are not our own, they are all influenced and reshaped, and sometimes implanted by our very own environment.&lt;/p&gt;
&lt;p&gt;The biggest open-source community is nature and the universe.&lt;/p&gt;
&lt;p&gt;Whatever you want, take it, whatever you want to do with it, do it, if you want to give back you are welcome, if you are not giving back then also you are welcome.&lt;/p&gt;
&lt;p&gt;and there is no MIT license,&lt;/p&gt;
&lt;p&gt;hahahaha&lt;/p&gt;
&lt;p&gt;No Copyright, nothing!&lt;/p&gt;
&lt;p&gt;There will be no creative thing or any kind of innovation or any progress without &lt;a href=&quot;https://en.wikipedia.org/wiki/Standing_on_the_shoulders_of_giants&quot;&gt;shoulders of giants.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Creativity is not like a sudden thing, that appears in the world, it is the collective progress of all humans and nature, more of like group progress, but yes there needs to be one point of entry to the world, where it can come alive, The person who is responsible for it, most of the time gets the credit!&lt;/p&gt;
&lt;p&gt;Many times I think, the most creative work that exists boils down to curation, things that are not meant to be gathered usually, when someone does it, and it works, it feels like magic, from another planet.&lt;/p&gt;
&lt;p&gt;Like &lt;a href=&quot;https://en.wikipedia.org/wiki/Rabindra_Sangeet&quot;&gt;Rabindra Sangeet&lt;/a&gt;, it is a curation of Hindustani classical music, Carnatic Classical Music, Western tunes, and the inherent folk music of Bengal, can you imagine western tunes combined with Hindustani classical music in your dreams, but Rabindranath Tagore has done it.&lt;/p&gt;
&lt;p&gt;Curation is the most valuable thing one can do when there is abundance, and there is always abundance, the problem is some people can’t see abundance, and some don’t care enough, they are waiting for others or external validation!&lt;/p&gt;
&lt;p&gt;You can say that Jugaad is also creative this way, Yes it is, it is in the blood of Indians, it is just that all don’t know how to scale their Jugaad, if one day they all know, it is over for all, the truth is that all Jugaad can’t be scalable, they are just temporary fixes, from temporary fixes to scale we need to get into the rabbit hole of problem, which often people avoid.&lt;/p&gt;
&lt;p&gt;Spotting opportunities of creative entry points (curation + swaad anusar namak) in abundance, just requires little contrarian thinking or environment, and once you get the pattern it is fun for you and magic for others!&lt;/p&gt;
&lt;p&gt;Sometimes it comes with a lot of practice &amp;amp; experience, it can be fast-forwarded if you get the right Catalyst(mentors) at the right time.&lt;/p&gt;
&lt;p&gt;So now go and do some magic!&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>Code On Paper</title>
    <link href="https://karanjanthe.me/posts/code%20on%20paper/"/>
    <updated>2022-07-11T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/code%20on%20paper/</id>
    <content type="html">&lt;p&gt;update: after 1 year, slowly understanding how dots are connecting, when i wrote this wasn’t able to see the point, but now it make sense.&lt;/p&gt;
&lt;p&gt;It was sunny day and we were taught C language in the college, and I got to know first time that, We have to write a program on the paper in the exam, like literally hand written, I was like WTF!, it doesn’t make any sense, but it is the system which is running in the college for so long.&lt;/p&gt;
&lt;p&gt;Few thoughts own this thing, I like to write programs in front of computer, not writing out complete program on the paper, expecting my self it was correct, most of the time when i write the code, just write the code, it can be broken, or doesn’t give you expected result, then transform it to produce desired output using this wonderful process called debugging, like my most of the time goes in the debugging then writing actual code, and most of all programmers write like this.&lt;/p&gt;
&lt;p&gt;Why?&lt;/p&gt;
&lt;p&gt;Programming is like thinking for me and for most of the programmers, not rewriting thing that you already know on piece of paper, this process is similar to how potter makes pots, or how painter make painting, or how writers write his first draft, or how musician produce music, no body can get things perfect at his first trial, things improve with the iteration and feedback loops.&lt;/p&gt;
&lt;p&gt;I think learning by doing is the best way to learn then any other way, and in the doing also, imitating things and adding your personal touch to the things you do, is the go to strategy, like when you imitate someones work, you start to realise why some things are there, or why they exist, dots start to connect with each other, for example in the painting world, for example benjamin franklin learned to write by summarizing essays of addison, then reproducing them.&lt;/p&gt;
&lt;p&gt;Makers run the world, by doing things in real world.&lt;/p&gt;
&lt;p&gt;Maker’s definition according to me is, who does things in real life, who can transform his thoughts or imagination in real world, they can be writers, painter, musician, inventor…&lt;/p&gt;
&lt;p&gt;PS: doctors can’t learn things by doing in today’s modern world, it was that way in the ancient world, because people used to trust each other, now days it is next to impossible, it can be done if we are able to produce exact replica of human, in case of error no real lives are wasted.&lt;/p&gt;
</content>
  </entry>
  
  
  <entry>
    <title>A Solution to World Hunger?</title>
    <link href="https://karanjanthe.me/posts/human%20photosynthesis/"/>
    <updated>2022-07-02T00:00:00Z</updated>
    <id>https://karanjanthe.me/posts/human%20photosynthesis/</id>
    <content type="html">&lt;p&gt;Imagine you never have to work for just to get food on your table, world hunger will be no more problem in the world, human can focus on more important problem and creative work.&lt;/p&gt;
&lt;p&gt;You will say then how are we are going to get food to survive ?&lt;/p&gt;
&lt;p&gt;Same as plant gets, a guy said from the future.&lt;/p&gt;
&lt;p&gt;So let’s deep dive in this possibility:&lt;/p&gt;
&lt;p&gt;Let’s first understand how Photosynthesis work, and what is it, I don’t want to sound boring but, it is actually interesting,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Photosynthesis basically means that they are able to &lt;a href=&quot;https://en.wikipedia.org/wiki/Chemical_synthesis&quot; title=&quot;Chemical synthesis&quot;&gt;synthesize&lt;/a&gt; (make) food directly from carbon dioxide and water using energy from light.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So by doing the magic at the end they are producing &lt;a href=&quot;https://en.wikipedia.org/wiki/Glucose&quot;&gt;glucose&lt;/a&gt;, and human digestion system breaks down food into glucose and our cells store the energy as a molecule called adenosine triphosphate (ATP).&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-1&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Photosynthesis process: plants convert sunlight, water, and CO2 into glucose and oxygen&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/HumanPhotosynthesis/Photosynthesis.png&quot; alt=&quot;Photosynthesis process: plants convert sunlight, water, and CO2 into glucose and oxygen&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;The magician here is &lt;a href=&quot;https://en.wikipedia.org/wiki/Chloroplast&quot;&gt;chloroplast&lt;/a&gt; , which is present in the plants, not in humans :(&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;label for=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot;&gt;&amp;#8853;&lt;/label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;mn-fig-2&quot; class=&quot;margin-toggle&quot; /&gt;&lt;span class=&quot;marginnote&quot;&gt;Chloroplast structure - the organelle that enables photosynthesis in plants&lt;/span&gt;&lt;img src=&quot;https://karanjanthe.me/assets/images/HumanPhotosynthesis/chloroplast.png&quot; alt=&quot;Chloroplast structure - the organelle that enables photosynthesis in plants&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;So what is stopping us, many other species other than plants also uses Photosynthesis &lt;a href=&quot;https://phys.org/news/2011-01-physicists-outer-shell-hornet-harvest.html&quot;&gt;read&lt;/a&gt; &lt;a href=&quot;https://www.nature.com/articles/nature.2012.11214&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the future let’s say we somehow managed to biohack human body, we are able to have magician &lt;a href=&quot;https://en.wikipedia.org/wiki/Chloroplast&quot;&gt;chloroplast&lt;/a&gt; in our body, so that means we solved world hunger, right ?&lt;/p&gt;
&lt;p&gt;No, huh?&lt;/p&gt;
&lt;p&gt;practically it is not possible, because unlike plants we have more complex system, brain, and we also can walk, so we need more energy to run our body.&lt;/p&gt;
&lt;p&gt;even by using Photosynthesis, we would produce only 1% of the daily energy requirements for the person to survive. To live on photosynthesis alone, the human would need a green body with the surface the size of a tennis court.&lt;/p&gt;
&lt;p&gt;okay, but let’s say we somehow build more advance version of chloroplast in future, which is more efficient and less in space, so we don’t need long body size of tennis court.&lt;/p&gt;
&lt;p&gt;human’s are now seen on the beaches, and in the outside world more, mom’s no longer says, your dinner is ready, they say go outside if you are hungry, mom are more happy because they no longer have to cook daily, eventually our body will turn in green (&lt;a href=&quot;https://www.quantamagazine.org/why-are-plants-green-to-reduce-the-noise-in-photosynthesis-20200730/&quot;&gt;interested to know why?&lt;/a&gt; )&lt;/p&gt;
&lt;p&gt;but with the time we will lose the ability of Photosynthesis, because it is not efficient for humans, because, we have more efficient ways to make food for our human body.&lt;/p&gt;
&lt;p&gt;Then why plants didn’t loose through the evolution, because plant can’t walk, they can’t go to their food directly, they can expand their roots but to some level only, not like humans who can go to one continent to other in search of food.&lt;/p&gt;
&lt;p&gt;We can’t solve world hunger problem using this method, but we will need to solve it as soon as possible, so human can work on better problems in the world.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I had first thought about this when i was in 6th grade, and one of the recent discussion with friend about this topic lead me to write this blog.&lt;/p&gt;
</content>
  </entry>
  
</feed>
