<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Lieu Zheng Hong</title>
  <subtitle>The website of Lieu Zheng Hong</subtitle>
  <link href="https://lieuzhenghong.com/feed.xml" rel="self"/>
  <link href="https://lieuzhenghong.com/"/>
  <updated>2026-08-30T00:00:00Z</updated>
  <id>https://lieuzhenghong.com/</id>
  <author><name>Lieu Zheng Hong</name></author>
  <entry>
    <title>My reading journey</title>
    <link href="https://lieuzhenghong.com/my_reading_journey/"/>
    <updated>2026-08-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/my_reading_journey/</id>
    <content type="html"></content>
  </entry>
  <entry>
    <title>My experience with aristocratic tutoring</title>
    <link href="https://lieuzhenghong.com/my_experience_with_aristocratic_tutoring/"/>
    <updated>2026-08-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/my_experience_with_aristocratic_tutoring/</id>
    <content type="html"></content>
  </entry>
  <entry>
    <title>One simple trick to have good dates</title>
    <link href="https://lieuzhenghong.com/2026-08-30-one-simple-trick-for-dates/"/>
    <updated>2026-08-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2026-08-30-one-simple-trick-for-dates/</id>
    <content type="html">&lt;p&gt;I think men (maybe both men and women, but I can only speak for men) stress too much about how to go on a date.&lt;/p&gt;
&lt;p&gt;I know a friend who has a &amp;quot;playbook&amp;quot; for dates: he&#39;s optimised the exact restaurant to bring the girl (same restaurant every time), walk the same route after back home etc. Yeah, if you do that, you&#39;re going to hate dating, obviously.&lt;/p&gt;
&lt;p&gt;Here&#39;s one simple trick that helped me a lot:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Instead of thinking of a date as an audition, where you think &amp;quot;what would she like to do&amp;quot;, think, &amp;quot;what would &lt;em&gt;I&lt;/em&gt; like to do&amp;quot;, and invite her along!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go to a restaurant that YOU want to go. Do an activity that YOU want to do. And then just invite her along!&lt;/p&gt;
&lt;p&gt;OK, some caveats are in order here: to be clear, it&#39;s probably not a good idea to bring her to your weekly FNM (the smell can be quite something). But you contain multitudes, right? Go do something that you&#39;ve always wanted to try but never did.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Scattered thoughts and changes on turning 30</title>
    <link href="https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/"/>
    <updated>2026-08-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#what-has-changed&quot;&gt;What has changed&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#i&#39;m-more-zen-and-more-chill&quot;&gt;I&amp;#39;m more zen and more chill&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#i-kind-of-automatically-stopped-playing-computer-games&quot;&gt;I kind of automatically stopped playing computer games&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#i&#39;m-kinder-to-myself-now&quot;&gt;I&amp;#39;m kinder to myself now&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#what-i&#39;ve-learned&quot;&gt;What I&amp;#39;ve learned&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#not-blundering-and-not-giving-up-is-90%25-of-success&quot;&gt;Not blundering and not giving up is 90% of success&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#sometimes-people-look-way-more-impressive-than-they-actually-are&quot;&gt;Sometimes people look way more impressive than they actually are&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#we-really-underestimate-the-power-of-consistent-compounding&quot;&gt;We really underestimate the power of consistent compounding&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#women-will-naturally-like-you&quot;&gt;Women will naturally like you&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#you-should-not-always-%22maximise-optionality%22&quot;&gt;You should not always &amp;quot;maximise optionality&amp;quot;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#think-about-what-success-looks-like-and-whether-or-not-you-want-it&quot;&gt;Think about what success looks like and whether or not you want it&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#what-has-not-changed&quot;&gt;What has not changed&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2026-08-03-what-changed-turning-30/#wanting-to-build-things-that-matter&quot;&gt;Wanting to build things that matter&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h1 id=&quot;what-has-changed&quot; tabindex=&quot;-1&quot;&gt;What has changed&lt;/h1&gt;
&lt;h2 id=&quot;i&#39;m-more-zen-and-more-chill&quot; tabindex=&quot;-1&quot;&gt;I&#39;m more zen and more chill&lt;/h2&gt;
&lt;p&gt;Perspective&lt;/p&gt;
&lt;p&gt;And I don&#39;t think this is something that can be speedrun or something that can change just reading advice. I&#39;ve always been a bit of an anxious person&lt;/p&gt;
&lt;p&gt;Less obsessed about &amp;quot;productivity &amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;i-kind-of-automatically-stopped-playing-computer-games&quot; tabindex=&quot;-1&quot;&gt;I kind of automatically stopped playing computer games&lt;/h2&gt;
&lt;h2 id=&quot;i&#39;m-kinder-to-myself-now&quot; tabindex=&quot;-1&quot;&gt;I&#39;m kinder to myself now&lt;/h2&gt;
&lt;h1 id=&quot;what-i&#39;ve-learned&quot; tabindex=&quot;-1&quot;&gt;What I&#39;ve learned&lt;/h1&gt;
&lt;h2 id=&quot;not-blundering-and-not-giving-up-is-90%25-of-success&quot; tabindex=&quot;-1&quot;&gt;Not blundering and not giving up is 90% of success&lt;/h2&gt;
&lt;p&gt;In my field of highly competitive startups, i see a lot of people just give up or implode, ...&lt;/p&gt;
&lt;p&gt;The corollary is &lt;em&gt;not to blunder&lt;/em&gt;. As I write in &lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/&quot;&gt;Advice for finalists&lt;/a&gt;, the body affects the mind, and:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;when your judgement is affected, the first thing to go is the ability to judge that your judgement is affected. Learn to listen to your body, because it really, really affects the mind.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and yeah, I&#39;d echo that&lt;/p&gt;
&lt;h2 id=&quot;sometimes-people-look-way-more-impressive-than-they-actually-are&quot; tabindex=&quot;-1&quot;&gt;Sometimes people look way more impressive than they actually are&lt;/h2&gt;
&lt;p&gt;People project success&lt;/p&gt;
&lt;p&gt;People&#39;s external state have little bearing with their internal conviction and I find it is difficult to ascertain who &amp;quot;got that dawg in them&amp;quot;. The people who are sounding extremely outwardly confident may not be the ones with the intestinal fortitude to push through and succeed down the line.&lt;/p&gt;
&lt;p&gt;I remember&lt;/p&gt;
&lt;h2 id=&quot;we-really-underestimate-the-power-of-consistent-compounding&quot; tabindex=&quot;-1&quot;&gt;We really underestimate the power of consistent compounding&lt;/h2&gt;
&lt;p&gt;Fitness, relationships, language learning, skill acquisition, all of these benefit&lt;/p&gt;
&lt;p&gt;put in the work every day&lt;/p&gt;
&lt;h2 id=&quot;women-will-naturally-like-you&quot; tabindex=&quot;-1&quot;&gt;Women will naturally like you&lt;/h2&gt;
&lt;p&gt;this one is a big change&lt;/p&gt;
&lt;h2 id=&quot;you-should-not-always-%22maximise-optionality%22&quot; tabindex=&quot;-1&quot;&gt;You should not always &amp;quot;maximise optionality&amp;quot;&lt;/h2&gt;
&lt;p&gt;The advice to young people is often &amp;quot;maximise optionality&amp;quot;; I actually think this is retarded advice, sorry; or rather, it&#39;s not bad advice per se, but it&#39;s misused to gaslight young people to take up soul-sucking jobs at McKinsey or Bain and co.&lt;/p&gt;
&lt;p&gt;In 2022 I came off a post-Covid bender, and fresh off raising money for my startup, started living the life of a  &amp;quot;digital nomad&amp;quot;. In the space of five months I was in Darmstadt, Geneva, Glasgow, Reykjavik, Brussels, Croatia, London, then Oxford.&lt;/p&gt;
&lt;p&gt;There are certain things you can only do if you commit and compound. I&#39;ll give an example. If you look at all the startup literature out there, the YC stuff, they all primarily focus on the early stage finding PMF part. And the kind of implicit assumption is, by elision, that once you find PMF, the rest is like easy. And to be clear, finding PMF is the hardest and most critical part, without a product people will pay for, you have nothing. But I&#39;ve realised now, with the benefits of already having found PMF, that there are yet more challenges to overcome. The challenges are different and more interesting and I enjoy my job now more (five years in) than when I started. If you do a startup for two years and exit and restart, you never get the chance to face and tackle these types of &amp;quot;scaling&amp;quot; or &amp;quot;post-PMF&amp;quot; problems. So that is an example of something that only happens when you commit and compound for a long time.&lt;/p&gt;
&lt;h2 id=&quot;think-about-what-success-looks-like-and-whether-or-not-you-want-it&quot; tabindex=&quot;-1&quot;&gt;Think about what success looks like and whether or not you want it&lt;/h2&gt;
&lt;p&gt;Here&#39;s something that&#39;s happened quite a few times: a bright young founder asks me whether they should start a startup that does XYZ, where XYZ is the hot new thing (at time of writing, AI, prediction markets). And I tell them:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Things always take longer than they should; so before you start something, try to visualise what success looks like, and make sure you want it! If you succeed, you&#39;ll be stuck doing that thing for a long time, so make sure that that&#39;s something you actually want to be doing. The worst thing is to wake up and be trapped doing something you hate, even (especially) if it&#39;s going well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You might be stuck in a good business doing bad and that will come at the price of your soul.&lt;/p&gt;
&lt;h1 id=&quot;what-has-not-changed&quot; tabindex=&quot;-1&quot;&gt;What has not changed&lt;/h1&gt;
&lt;h2 id=&quot;wanting-to-build-things-that-matter&quot; tabindex=&quot;-1&quot;&gt;Wanting to build things that matter&lt;/h2&gt;
&lt;p&gt;Sometime in 2019 I started saying that I wanted to do &amp;quot;difficult, interesting, and impactful work&amp;quot;. Reason being, if it&#39;s not interesting, I can&#39;t bring myself to do it. If it&#39;s not impactful, what&#39;s the point of doing it. And if it&#39;s not difficult, let someone else do it.&lt;/p&gt;
&lt;p&gt;With age, I have changed my view: not that I don&#39;t think &amp;quot;difficult, impactful and interesting&amp;quot; is correct, but rather, I think the most important thing, bar none, is focus on &amp;quot;impactful&amp;quot;.&lt;/p&gt;
&lt;p&gt;Why is that? Because I realise that everything in this world is more difficult that it seems. The skill ceiling is very high. And if it&#39;s difficult and impactful, then it will naturally become very interesting to you. You will go into a flow state&lt;/p&gt;
&lt;p&gt;What makes work impactful for me, is to work on something I know is positive-sum, building on solid foundations, unharried, sustainable growth over the months and years. See the above: think about what success looks like and whether or not you want it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>songs I like</title>
    <link href="https://lieuzhenghong.com/songs/"/>
    <updated>2026-05-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/songs/</id>
    <content type="html">&lt;h2 id=&quot;songs-from-cds&quot; tabindex=&quot;-1&quot;&gt;songs from CDs&lt;/h2&gt;
&lt;h2 id=&quot;things-i-heard-on-the-radio&quot; tabindex=&quot;-1&quot;&gt;things I heard on the radio&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=nM8kdKSSL3E&quot;&gt;不是花火呀 - 霜雪千年&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=LgDBbAatuic&quot;&gt;柯柯柯啊 - 女孩別哭泣&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=S0w_au421tg&quot;&gt;杨树人 - 江南烟雨色&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;我的新衣&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;can-sing-ok&quot; tabindex=&quot;-1&quot;&gt;can sing OK&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;借&lt;/li&gt;
&lt;li&gt;淒美地&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;good-for-practice-(in-this-weird-intermediate-range)&quot; tabindex=&quot;-1&quot;&gt;good for practice (in this weird intermediate range)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;大魚&lt;/li&gt;
&lt;li&gt;奉勸&lt;/li&gt;
&lt;li&gt;如果你也聽說&lt;/li&gt;
&lt;li&gt;我走後 － en&lt;/li&gt;
&lt;li&gt;歌謠&lt;/li&gt;
&lt;li&gt;如果雨之後&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Pixel Art on NFC cards</title>
    <link href="https://lieuzhenghong.com/nfc_pixel_art/"/>
    <updated>2026-05-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/nfc_pixel_art/</id>
    <content type="html">&lt;p&gt;I think NFC tags are really cool! I like how physical and embodied they are: a boon in these hyperdigital times. They&#39;re a lot more tactile and easy to use (you just tap them) compared to a QR code, where you have to open up your camera app, line it up with the QR code, wait a while for the QR code to be detected, then click the link.&lt;/p&gt;
&lt;p&gt;NFC tags can store anywhere between 100 bytes to 8KB but the ones I bought have 888 bytes capacity. They cost around $2.50 per card from SGBotics but I&#39;m sure you could get them cheaper. 888 bytes is not a lot of space: it&#39;s just enough for a long tweet or very short letter. We decided on pixel art! I built a very simple pixel art &lt;a href=&quot;https://lieu.gg/nfc_pixel/editor&quot;&gt;editor&lt;/a&gt; and &lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer&quot;&gt;viewer&lt;/a&gt; that lets you create your own tiny (20x32) pixel art and store it in the NFC card. This way, you have &amp;quot;art on a card&amp;quot;.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example:
&lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#CgNhIGNsZWFyaW5nZWJic5znOc5znOc5znOc5znOe5z3Oc5znOc5znOe5znOc57nOc9znOc57nuc9z3Oc5znOc5zzuc9z3ie9z3Ocd7nOc573O25z3Pc5znOc97nPe5z3Pc57nPe5znO29znuc9z3Oc9znPe973Pe9z9ue9z3vcB73Pe573Pe573vA973uc573vc973ve5z3ve5z37ed73vA97nPA973ge973Pe9z3Oe5z3ve94Hve9z3vc573ve4DnPe97wPftz3ge973Pc97tve9z3ve973ve973ve573ve973vO973vA973ve953ve973ve973ve973ve9z3ve973vfx73ve97nPe973ve_R-Pe973Oc973ve9BzjOd73vc6rnve96UJ0fT3ve51aue9761SOp61e9z3VdV1avrWo61rWrnurWrqvrWta1HWtaudWr6ue5761rWr61rV1a1rV1XOfWrq1dVz61rWtauq51avrVznurWr61rWrnuc5zq1dV9a1fWta1c9zq1c5zq1rWtavq-ta1fV1a1rWtQ&quot;&gt;ebb&#39;s &amp;quot;a clearing&amp;quot;&lt;/a&gt;
&lt;img src=&quot;https://lieuzhenghong.com/nfc_pixel/out/54d336bd_ebb_a_clearing.png&quot; alt=&quot;54d336bd_ebb_a_clearing&quot;&gt;&lt;/p&gt;
&lt;p&gt;How does this work? Well, first of all, the image (and title/artist) are encoded into bytes, which can be represented as a string. The image above is equivalent to the following string, also called a &lt;em&gt;fragment&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CgNhIGNsZWFyaW5nZWJic5znOc5znOc5znOc5znOe5z3Oc5znOc5znOe5znOc57nOc9znOc57nuc9z3Oc5znOc5zzuc9z3ie9z3Ocd7nOc573O25z3Pc5znOc97nPe5z3Pc57nPe5znO29znuc9z3Oc9znPe973Pe9z9ue9z3vcB73Pe573Pe573vA973uc573vc973ve5z3ve5z37ed73vA97nPA973ge973Pe9z3Oe5z3ve94Hve9z3vc573ve4DnPe97wPftz3ge973Pc97tve9z3ve973ve973ve573ve973vO973vA973ve953ve973ve973ve973ve9z3ve973vfx73ve97nPe973ve_R-Pe973Oc973ve9BzjOd73vc6rnve96UJ0fT3ve51aue9761SOp61e9z3VdV1avrWo61rWrnurWrqvrWta1HWtaudWr6ue5761rWr61rV1a1rV1XOfWrq1dVz61rWtauq51avrVznurWr61rWrnuc5zq1dV9a1fWta1c9zq1c5zq1rWtavq-ta1fV1a1rWtQ&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We add this to my editor or viewer which can then read the fragment and display it in the browser.&lt;/p&gt;
&lt;p&gt;The full URL looks like this: &lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#CgNhIGNsZWFyaW5nZWJic5znOc5znOc5znOc5znOe5z3Oc5znOc5znOe5znOc57nOc9znOc57nuc9z3Oc5znOc5zzuc9z3ie9z3Ocd7nOc573O25z3Pc5znOc97nPe5z3Pc57nPe5znO29znuc9z3Oc9znPe973Pe9z9ue9z3vcB73Pe573Pe573vA973uc573vc973ve5z3ve5z37ed73vA97nPA973ge973Pe9z3Oe5z3ve94Hve9z3vc573ve4DnPe97wPftz3ge973Pc97tve9z3ve973ve973ve573ve973vO973vA973ve953ve973ve973ve973ve9z3ve973vfx73ve97nPe973ve_R-Pe973Oc973ve9BzjOd73vc6rnve96UJ0fT3ve51aue9761SOp61e9z3VdV1avrWo61rWrnurWrqvrWta1HWtaudWr6ue5761rWr61rV1a1rV1XOfWrq1dVz61rWtauq51avrVznurWr61rWrnuc5zq1dV9a1fWta1c9zq1c5zq1rWtavq-ta1fV1a1rWtQ&quot;&gt;https://lieu.gg/nfc_pixel/viewer/#CgNhIGNsZWFyaW5nZWJic5znOc5znOc5znOc5znOe5z3Oc5znOc5znOe5znOc57nOc9znOc57nuc9z3Oc5znOc5zzuc9z3ie9z3Ocd7nOc573O25z3Pc5znOc97nPe5z3Pc57nPe5znO29znuc9z3Oc9znPe973Pe9z9ue9z3vcB73Pe573Pe573vA973uc573vc973ve5z3ve5z37ed73vA97nPA973ge973Pe9z3Oe5z3ve94Hve9z3vc573ve4DnPe97wPftz3ge973Pc97tve9z3ve973ve973ve573ve973vO973vA973ve953ve973ve973ve973ve9z3ve973vfx73ve97nPe973ve_R-Pe973Oc973ve9BzjOd73vc6rnve96UJ0fT3ve51aue9761SOp61e9z3VdV1avrWo61rWrnurWrqvrWta1HWtaudWr6ue5761rWr61rV1a1rV1XOfWrq1dVz61rWtauq51avrVznurWr61rWrnuc5zq1dV9a1fWta1c9zq1c5zq1rWtavq-ta1fV1a1rWtQ&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But where does NFC come in?&lt;/p&gt;
&lt;p&gt;The next step is to write the URL to the NFC card. Modern smartphones can read and write to NFC cards for free! We use an app called &amp;quot;NFC Tools&amp;quot; to do that. It takes about two seconds to write that URL (which is 579 bytes or so) to the NFC card.&lt;/p&gt;
&lt;p&gt;If the data loaded on the NFC card is a URL, both Android and iOS devices will automatically open it in the browser by default. So when the user taps the NFC card on their phone, it takes them directly to the image! You now have art-on-a-card.&lt;/p&gt;
&lt;p&gt;Last Saturday, Shashvat and I gave an interactive workshop called &amp;quot;Pixel Art Jam&amp;quot; to try out these concepts. We got them to download the app, make some art, write them onto their NFC cards, then share them with other attendees -- all in ten minutes. Here are some of the folks&#39; works from TWC:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#DgZDYXcgQ2F3IFdpemFyZENsb3RobwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHpQAAAAAAAAAAAAABShwAAAAAAAAAAAAClKUAAAAAAAAAAAAFKHpQAAAAAAAAAAAN73ShwAAAAAAoelKUPTe6UAAAAAAClKUpSlKU3QAAABAAAUCEIQ0pTewAAAEIQgEIQhDSh6bAAAAAhCEAhtMIaUpQAAAhCEIBCG1ghpSlKAAAAAACEIQhCE9KHoAAAAAEIQhCEIaUpQAAAAAIQhCGAQhBSgAAAAAAhCEMIBCEAAAAAAAACEIYBCEIQgAAAAAAAIQhgEIQhCEAAAAAAAhCGEAhCEIQAAAAAAAEIQwgEIQhCAAAAAAAAhCGEIBCEIAAAAAAAAEIQhhCAQhAAAAAAAEAhCEIYQgEAAAAAAIACEMAhCGEAgAAEIQgAAAwCEIQhCAAAABCAAABAIQhCEIAAACEIAAAEAAAAAAAAAAAAAAAIQgAAAAAAAAAAAAIQhCEAAAAAAAAAAAAAAEAQgAAAAAAAAAAAAAQAAAAAAA&quot;&gt;Clotho&#39;s &amp;quot;caw caw wizard&amp;quot;&lt;/a&gt;
&lt;img src=&quot;https://lieuzhenghong.com/nfc_pixel/out/799b4c47_Clotho_Caw_Caw_Wizard.png&quot; alt=&quot;799b4c47_Clotho_Caw_Caw_Wizard&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#CwVTdW5ueSB0cmVlc0NhbGVkxjC1rWta1qUpa1rUvGFrWtazrWta1KWtS9YWta1rOhCFnOta1KxjEpHWtCEIOc51rUrGJFlI50IKg5zmMdasYlIpZSkhCEHMYx1rxiUpFKWSEIQcxzGWrEpSlKSEIQhBznMZasSkc5zoQhBUHWcxlLxjB1rOgqEIQdZjGWvGMLWs6EIQhB1mMZSsYwtaznQhBzrWY51LxjGFrWc5znOtZjnUvWMYWta1rOtazHOtS8YMpa1rWs61rOc61LxjClrWta1rWc5zrUvGMLWta1rWsxznWta8awta1rWtZjHOtalrxjC1rWtazGOda1qUvGNLWta1mMc61rWpS8awta1rMY51rOc61LxjC1rWtZzrWcxjnUrGMOW5zlrOtZzmMdStYctzqOcs51nWYx1LcsY0Oc5yzLWtZjHUvDhoGOjnLMc61mOdSxjGMaHOWsxjHOY61KGMY0Dc5blnMYxjrUrDqOc5znLWtaznWtSsOctzqOc5a1rWta1KxpznOc5a1rWta1rUpa1rWty1rWtalKUtSg&quot;&gt;Caleb&#39;s &amp;quot;sunny trees&amp;quot;&lt;/a&gt;
&lt;img src=&quot;https://lieuzhenghong.com/nfc_pixel/out/add0268e_Caled_Sunny_trees.png&quot; alt=&quot;add0268e_Caled_Sunny_trees&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#CAl1bnRpdGxlZGFub255bW91cwAABa1rWta1rWtYAAWAAALWta1gAta1rABawAWta1gAAAFrWta1rWta1rWsAAAAta1rWta1rWta1rABa1rABa1rWta1rWta1rWAAFoQhCELWta1rWsAAAQghEYQta1rIRa1rABGCERhCEIQghELWta0YxhGEIQhCEYQta1rQhGMEIghMIRhC1rWtGEIwQiCEwjCELWta0YwjCMYxjCCEQta1rQjGMIRjGEIIRC1rWtBCYRhCMIxhCELWta0EJhBCIxjCEIQta1rRhGEEJjCMYwQi1rWtGEYRjGEIwhBCLWta0IxjCMYQjGEIWta1rQjGEIwhGMEIha1rWtBCYRjGMYQQi1rWta1kJjGCEQhC1rWta1rWhCMYIRBCLWsxjLWta1rxha1kIta1mOs61rWvGFrWta1rWY5zrWta8YWta1rWtbWnOha1rxha1rWta1tQhCFrWvGFrWtCFrQ1qEIWta8YWtCEIQhCEIQhaEIxhaEIQhCEIQhCEIQhCEIQhCEIQhCEIQhCEIQhCEIQhCEIQg&quot;&gt;anonymous&#39;s &amp;quot;untitled&amp;quot;&lt;/a&gt;
&lt;img src=&quot;https://lieuzhenghong.com/nfc_pixel/out/de2cd1c4_anonymous_untitled.png&quot; alt=&quot;de2cd1c4_anonymous_untitled&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lieu.gg/nfc_pixel/viewer/#CgNhIGNsZWFyaW5nZWJic5znOc5znOc5znOc5znOe5z3Oc5znOc5znOe5znOc57nOc9znOc57nuc9z3Oc5znOc5zzuc9z3ie9z3Ocd7nOc573O25z3Pc5znOc97nPe5z3Pc57nPe5znO29znuc9z3Oc9znPe973Pe9z9ue9z3vcB73Pe573Pe573vA973uc573vc973ve5z3ve5z37ed73vA97nPA973ge973Pe9z3Oe5z3ve94Hve9z3vc573ve4DnPe97wPftz3ge973Pc97tve9z3ve973ve973ve573ve973vO973vA973ve953ve973ve973ve973ve9z3ve973vfx73ve97nPe973ve_R-Pe973Oc973ve9BzjOd73vc6rnve96UJ0fT3ve51aue9761SOp61e9z3VdV1avrWo61rWrnurWrqvrWta1HWtaudWr6ue5761rWr61rV1a1rV1XOfWrq1dVz61rWtauq51avrVznurWr61rWrnuc5zq1dV9a1fWta1c9zq1c5zq1rWtavq-ta1fV1a1rWtQ&quot;&gt;ebb&#39;s &amp;quot;a clearing&amp;quot;&lt;/a&gt;
&lt;img src=&quot;https://lieuzhenghong.com/nfc_pixel/out/54d336bd_ebb_a_clearing.png&quot; alt=&quot;54d336bd_ebb_a_clearing&quot;&gt;&lt;/p&gt;
&lt;p&gt;I am very, very impressed by how awesome these works are and how much people could do in just 5 minutes! These are awesome, truly.&lt;/p&gt;
&lt;h2 id=&quot;future-work&quot; tabindex=&quot;-1&quot;&gt;Future work&lt;/h2&gt;
&lt;p&gt;I don&#39;t know if this could be done in 888 bytes, but I think it would be really cool to build the editor and viewer (or at least the viewer) in the URL itself, so the card could work completely offline.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Growing up in the 90s</title>
    <link href="https://lieuzhenghong.com/90s_kids/"/>
    <updated>2026-05-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/90s_kids/</id>
    <content type="html">&lt;p&gt;Sourced from /r/Singapore &lt;a href=&quot;https://www.reddit.com/r/singapore/comments/hu1ni1/dating_in_singapore_optimistic_version/fylrpwt/&quot;&gt;(permalink)&lt;/a&gt;. made me feel something&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only 90s kid will remember, dating 90s ah lians is the best thing ever. Always look very chio in their rebond hair and heavy eyeliner. I like it when they move their head and the hair move around like plastic. Always wear FBT shorts, because she say she tomboy and 女强人, but both of you know its anything but that. Like to wear halter top and/or crop top, very skinny, chicken rice $2 only eat half the plate. Quite easy to stead, and very fast can do a lot liao. Initially also very exciting, move jin fast, she always call you 老公 and talk about marriage like 2 weeks in. Must buy ring from 77th street, wear around like engagement ring, jin romantic. Go clubbing together at sparks disco, see her 摇头 and her plastic rebond hair flying everywhere, jin wild, look like a primal goddess, and hear her shout the 369 chant to crazy baby jin fierce. Must have warning, because all her 乾哥 will be after her, and if she turn cold after about a month in, expect that within a few days, she will break up with you and stead her 乾哥. That was my experience with ah lians, all 3 start and end exactly the same, machiam photocopy, but I had a very good time, 10/10.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You a 90s kid sia. I program 眉飞色舞 and para para for her 3310 ringtone. Buy her phone charm some more to hang on the phone, one was a heart, other one forgot liao, I think got a slam dunk one. Their phone charm is larger than their phone and take like half their bag&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Actually neoprint is one of the best things you can do in the 90s, once you close the curtain, can do anything in there. beyond all the 变态 things, actually do with friends is very fun, I still got a lot of the old neoprints with friends, some sausage fest, some with the girls I used to like, all the stupid hair and fashion, everything. If you look at it, you can remember the exact event you took the photo. Damn ex. somemore, I remember starting is like $6, and you want the very power one have to spend up to $12 also got. Remember always have to wait for someone to cut it out and divide among friends. Now you just selfie, forget to post, cos not glam enough, then lose the memory when you change the phone.&lt;/p&gt;
&lt;p&gt;Dunno is it nostalgia lens or what, 90s seem to be the best era, everything also got, and not so digital, have to talk face to face. Now can laugh laugh at it, but remember last time you jio the ah lian, she say yes, also feel very very happy. Before you say the 你要做我的 stead 吗? feel jin nervous. Got some say no, then feel very sad, but ok, go pak some KOF in arcade, then feel good liao. Feel sian, spend a bit go eat zhi char at kopi tiam, then go kai kai, a lot of shops, very bright lights, as long as you got your friends everything also stready. Before go out, must make hair nice nice, put the sharp comb, if the group got the girl you like, then even more exciting, got chance talk to her, other ppl walk in front, you talk to her and slow down your pace until you all last, or even better, your buddies purposely lose both of you. Even go bookshop also fun, that time the books all more colourful and exciting, everything you want to learn must buy one, cannot find on the internet. Even when bored, still must go out kai kai. Still remember me and my best friend go kai kai at the old bayshore there, because too bored, the lights everything super romantic, but its just 2 guys walking, feel very romantic, but look at him feel very err xin, haha.&lt;/p&gt;
&lt;p&gt;Now whole day worry mortgage, worry children, worry job, worry COVID, si bei sian. Everyday stress, everyday bored, not even in the same country as my 兄弟. Last time I went back all uncle liao, I talk about these things they laugh at me ask me I how old liao. After that even go back also never jio them, feel like everyone change, and feel like only I cherish these kind of childish things&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>video games are IQ shredders</title>
    <link href="https://lieuzhenghong.com/video_games/"/>
    <updated>2025-07-09T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/video_games/</id>
    <content type="html">&lt;blockquote&gt;
&lt;p&gt;Tetris was invented in 1985, it came out on the NES in &lt;a href=&quot;https://en.wikipedia.org/wiki/Tetris_(NES_video_game)&quot;&gt;1989&lt;/a&gt;, but the best way to play was only discovered in &lt;a href=&quot;https://www.ign.com/articles/tetris-players-are-using-a-special-technique-called-rolling-to-set-new-world-records&quot;&gt;2021&lt;/a&gt;.&lt;a href=&quot;https://www.experimental-history.com/p/#_&quot;&gt;1&lt;/a&gt; Previously, players would just try to tap the buttons really fast (“hypertapping”), until a 15-year-old named Christopher “CheeZ” Martinez realized that you could actually press the buttons faster if you roll your fingers across the &lt;em&gt;back&lt;/em&gt; of the controller (“&lt;a href=&quot;https://kotaku.com/nes-tetris-players-call-it-rolling-and-theyre-setting-1846767518&quot;&gt;rolling&lt;/a&gt;”). CheeZ went on to &lt;a href=&quot;https://www.youtube.com/watch?v=f2xCQT0BUcw&quot;&gt;set world records&lt;/a&gt; using his &lt;a href=&quot;https://www.youtube.com/watch?v=n-BZ5-Q48lE&amp;amp;t=212s&quot;&gt;technique&lt;/a&gt;, but he wasn’t on top for long. Other players soon perfected their rolls, and CheeZ &lt;a href=&quot;https://liquipedia.net/tetris/CheeZ&quot;&gt;lost&lt;/a&gt; in a first-round upset at the 2022 Classic Tetris World Championship to another “roller”, a 48th-seed named BirbWizard.&lt;/p&gt;
&lt;p&gt;I love this because it shows how low-hanging discoveries can just sit there for decades without anyone seeing them, even when thousands of dollars are on the line. (Seriously—the first place finisher in the 2024 championships won &lt;a href=&quot;https://liquipedia.net/tetris/CTWC/2024&quot;&gt;$10k&lt;/a&gt;.) People spent 40 years trying to tap buttons faster without ever realizing they should be tapping the other side of the controller instead.&lt;/p&gt;
&lt;p&gt;But I also hate this, because:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/2025-07-09T09-12-22_Pasted_image_20250709171221.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;What&#39;s the problem with this?&lt;/p&gt;
&lt;p&gt;Why are Roger Federer and Christiano Ronaldo uber-cool, Magnus Carlsen somewhat cool, and &amp;quot;CheeZ&amp;quot; and &amp;quot;BirbWizard&amp;quot; not cool at all?&lt;/p&gt;
&lt;p&gt;[09/07, 16:57] lieu: here’s a possible synthesis of my worldview, why I think it’s great to be good at “physical” sport but a big waste to be good at mind sport or esport, and why that Twitter screenshot resonates with me.&lt;/p&gt;
&lt;p&gt;in our world, you can either have a good brain or you can have a good body (or both of course). Modern society (let’s leave the upcoming AI-apocalypse aside for now) gives great returns to having a good brain, near zero returns to having a good body (since we have mechanisation, industrialisation, what have you). And hence if you’re one of those with a good body, the only way you can take advantage of that talent in our modern world is to do those sport things: running fast in straight line, basketball, etc.&lt;/p&gt;
&lt;p&gt;Whereas people who are good at chess and NES Tetris are obviously “good brainers”, they have so many more options to do something actually “useful” and “productive” with their talents. The ones that are being oneshot by video games or nerd games are bad because the counterfactual potentially is that they start some brainy startup or do a PhD or whatever, and instead they do this stuff&lt;/p&gt;
&lt;p&gt;[09/07, 17:03] lieu: A type I IQ shredder was defined by Spandrell:&lt;/p&gt;
&lt;p&gt;How many bright Indians and bright Chinese are there, Harry? Surely they are not infinite. And what will they do in Singapore? Well, engage in the finance and marketing rat-race and depress their fertility to 0.78, wasting valuable genes just so your property prices don&#39;t go down. Singapore is an IQ shredder.&lt;/p&gt;
&lt;p&gt;Type I IQ shredders shred intelligence genes. They are very dangerous for the long term because they decrease the overall intelligence of the next generation. Type II IQ shredders destroy intellectual output now by distracting high IQ people from real pursuits, or via other means.&lt;/p&gt;
&lt;p&gt;Tlon is a good example of a type II IQ shredder. If Tlon worship doesn’t effect high IQ reproduction, then it is only a type II IQ shredder, because it grinds actual intellectual output to a halt by distracting everyone intelligent. Likewise, if everyone went to San Francisco or Singapore to improve human knowledge, but they didn’t reproduce due to housing prices, density, liberal culture, etc, then San Francisco and Singapore would only be type I IQ shredders, because they adequately use the intelligence they are given, but deprive it from the next generation.&lt;/p&gt;
&lt;p&gt;In reality, Singapore, San Francisco, et al. are both type I and type II IQ shredders, because not only do the people who go there suffer from reduced fertility — they also spend all day interacting with the intellectual Matrix, the Tlon that are computers.&lt;/p&gt;
&lt;p&gt;[09/07, 17:07] lieu: &amp;gt;  Type II IQ shredders destroy intellectual output now by distracting high IQ people from real pursuits, or via other means. Tlon is a good example of a type II IQ shredder. If Tlon worship doesn’t effect high IQ reproduction, then it is only a type II IQ shredder, because it grinds actual intellectual output to a halt by distracting everyone intelligent. Likewise, if everyone went to San Francisco or Singapore to improve human knowledge, but they didn’t reproduce due to housing prices, density, liberal culture, etc, then San Francisco and Singapore would only be type I IQ shredders, because they adequately use the intelligence they are given, but deprive it from the next generation.&lt;/p&gt;
&lt;p&gt;[09/07, 17:07] lieu: the point is that video games are a type 2 IQ shredder&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: if you devote your time to speedrunning super mario bros 2 or whatever&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: that’s a huge shredder&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: actually i think this concept is nontrivial, i should write about it&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: like “why is sports cool, why is vidya lame&amp;quot;&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: not just lame but why is it a waste&lt;/p&gt;
&lt;p&gt;[09/07, 17:08] lieu: because of the counterfactual&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>improving the site (2025)</title>
    <link href="https://lieuzhenghong.com/2025_site_redesign/"/>
    <updated>2025-07-06T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2025_site_redesign/</id>
    <content type="html">&lt;p&gt;previous posts in this entry:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/&quot;&gt;Improving the site (2023)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/site_redesign_2022/&quot;&gt;Recontextualising my site (2022)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/&quot;&gt;Rebuilding this website (2020)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This year, I made two large architectural changes, things I&#39;ve wanted to do for a long time.&lt;/p&gt;
&lt;h2 id=&quot;content-presentation-separation&quot; tabindex=&quot;-1&quot;&gt;content-presentation separation&lt;/h2&gt;
&lt;p&gt;The largest architectural change is a clear separation between content and presentation. When I first started this website it was a Jekyll static site, then Eleventy. Down the line I wanted to make it a Obsidian vault as well, and I did, but due to all of this historical baggage it was never quite done right, many vestigial files, etc.&lt;/p&gt;
&lt;p&gt;I refactored the Github repo to have a very clear structure: on the root level we have &lt;code&gt;vault&lt;/code&gt; and &lt;code&gt;views&lt;/code&gt;, where &lt;code&gt;vault&lt;/code&gt; is the Obsidian vault (content layer), while &lt;code&gt;views&lt;/code&gt; is the presentation layer.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;lieu/
├── vault/                           # 📁 CONTENT LAYER
└── views/                           # 🎨 PRESENTATION LAYER
	└── eleventy/                    # Eleventy SSG implementation
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conceptually, I want the vault to be &amp;quot;pure&amp;quot;: it has all my notes and thoughts, and doesn&#39;t concern itself with presentation. The website is one of many potential views over my vault. Completely separating content and presentation lets me change or add new views if I see fit -- if e.g. Eleventy stops being supported, or I want to build a server-side rendered second brain with full text search over my private posts -- without having to change anything about the vault.&lt;/p&gt;
&lt;p&gt;The other advantage is it also lets me back up my Obsidian vault with Obsidian Sync, which means that I can read and draft posts on my phone with the Obsidian app.&lt;/p&gt;
&lt;h2 id=&quot;persistent%2C-global-blob-storage&quot; tabindex=&quot;-1&quot;&gt;persistent, global blob storage&lt;/h2&gt;
&lt;p&gt;I want my second brain to store not just my written thoughts, but also my memories in the form of PDFs, images, videos, etc. I started putting all these files in a folder called &lt;code&gt;/img&lt;/code&gt; inside the root folder, and backing it all up on Git. Of course, this is a bad idea, and very soon I had to explore alternative solutions.&lt;/p&gt;
&lt;p&gt;For the past few years I used Git LFS, and maybe it&#39;s a skill issue on my part, but it&#39;s entirely horrible. I&#39;ve tried many times to make it work, it just sucks, it&#39;s so painful, I eventually decided to rip it out entirely (losing all my old commit history).&lt;/p&gt;
&lt;p&gt;So I decided to build a global blob storage service that&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stores all my data (videos, photos, PDFs, ...)&lt;/li&gt;
&lt;li&gt;serves it up at a persistent global URL (e.g. &lt;a href=&quot;https://files.lieu.gg/img/group_testing/queue.png&quot;&gt;files.lieu.gg/img/group_testing/queue.png&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;allows me to upload data (from &lt;a href=&quot;https://blob-service.lieu.gg/&quot;&gt;blob-service.lieu.gg&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;automatically captures new data from my phone and desktop (e.g phone screenshots or screen recordings, desktop screenshots, pasted images..)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first three points are done with Cloudflare R2 and a Cloudflare worker, pretty much all done by Claude. That all works very well.
The last one is a work in progress, and requires a bunch of different scripts: for example, Obsidian stores all pasted images in the local folder, so I had to write a hook that intercepts that paste, move the file to a temporary folder, upload it to the R2 bucket, delete the file, etc. For the phone I use Tasker.&lt;/p&gt;
&lt;h2 id=&quot;downstream-cleanups&quot; tabindex=&quot;-1&quot;&gt;downstream cleanups&lt;/h2&gt;
&lt;p&gt;Lots of smaller cleanups needed, some of which were downstream of the infra change. The collections system / system of filters I had used to categorise posts on the website was simplified and rewritten. I needed to remove &lt;code&gt;layout:base&lt;/code&gt; from the front matter of all my Markdown files (because &lt;code&gt;layout:base&lt;/code&gt; is a purely presentation consideration).&lt;/p&gt;
&lt;p&gt;I migrated all &lt;code&gt;/img/...&lt;/code&gt; paths to &lt;code&gt;https://files.lieu.gg/...&lt;/code&gt; paths. This would have been painful before but Claude Code did a really good job at it, it wrote a bunch of not-great regexes, but if you check its work and tell it it&#39;s missed a bunch of files, it can eventually do it&lt;/p&gt;
&lt;h2 id=&quot;claude-code-is-incredible&quot; tabindex=&quot;-1&quot;&gt;claude code is incredible&lt;/h2&gt;
&lt;p&gt;This is the first improvement on my site that was AI-assisted! I guess this must mark a sea change of some sort.&lt;/p&gt;
&lt;p&gt;Claude Code is incredible, really.&lt;/p&gt;
&lt;p&gt;Nothing that hasn&#39;t been said already, but two observations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&#39;s surprisingly good at brainstorming solutions, if you&#39;re smart and willing to push back. It will suggest a bunch of frameworks -- I would strongly recommend not doing that (as of June 2025--who knows what will happen in just a few months!). These new trendy frameworks are not lindy enough, they don&#39;t have a sufficiently large corpus for AI to learn from, the code Claude will write is going to be all wrong.&lt;/li&gt;
&lt;li&gt;Claude Code is good for work, but &lt;em&gt;incredible&lt;/em&gt; for personal projects. Its biggest strength is getting things done that you wouldn&#39;t have done otherwise. I have so many &amp;quot;todos&amp;quot; and &amp;quot;improvements&amp;quot; to make but I know it&#39;s going to take a few days or even weeks, so I push them back indefinitely. For example I have wanted to build a global blob store for AGES, but the pain of reading through the documentation, implementing it, migrating all the paths, etc., I could definitely have done it myself, but it would have needed a couple of weekends, and so I always pushed it back. Because Claude can write decent-to-good code so quick, it can get it done in hours instead of days. This reduces the activation energy and offers what is in effect an &amp;quot;infinity&amp;quot; productivity improvement, because the counterfactual is that these improvements just don&#39;t get built without it.&lt;/li&gt;
&lt;li&gt;It&#39;s incredible for writing documentation too! I got it to write the CHANGELOG after making some changes, check out a sample entry:&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;h2 id=&quot;%5B2025-06-21%5D---obsidian-link-compatibility&quot; tabindex=&quot;-1&quot;&gt;[2025-06-21] - Obsidian Link Compatibility&lt;/h2&gt;
&lt;h3 id=&quot;added&quot; tabindex=&quot;-1&quot;&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automatic Link Conversion&lt;/strong&gt;: Created &lt;code&gt;markdown-it-obsidian-links.js&lt;/code&gt; plugin to automatically convert Obsidian-style relative markdown links to Eleventy-compatible absolute paths during build&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugin Integration&lt;/strong&gt;: Integrated the link conversion plugin into Eleventy&#39;s markdown processing pipeline&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;fixed&quot; tabindex=&quot;-1&quot;&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Obsidian Link Compatibility&lt;/strong&gt;: Resolved incompatibility between Obsidian&#39;s relative link format (&lt;code&gt;[text](filename.md)&lt;/code&gt;) and Eleventy&#39;s expected absolute path format (&lt;code&gt;[text](/filename)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Consistency&lt;/strong&gt;: Converted all manually converted absolute path links back to Obsidian-style relative paths for consistent authoring experience&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;changed&quot; tabindex=&quot;-1&quot;&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Link Format Standardization&lt;/strong&gt;: All content now consistently uses Obsidian&#39;s native relative link format (&lt;code&gt;filename.md&lt;/code&gt;) while the plugin handles automatic conversion to absolute paths (&lt;code&gt;/filename&lt;/code&gt;) during build&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Date-based Link Conversion&lt;/strong&gt;: Converted date-based permalink URLs (e.g., &lt;code&gt;/2020/08/03/blog-rebuild-2020/&lt;/code&gt;) back to markdown file references (&lt;code&gt;2020-08-03-blog-rebuild-2020.md&lt;/code&gt;) to leverage Eleventy&#39;s permalink system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;: The plugin operates during markdown processing, detecting relative &lt;code&gt;.md&lt;/code&gt; links and converting them to absolute paths while preserving external URLs and non-markdown links. This solution eliminates the need for manual link format maintenance across 78+ affected files while ensuring seamless integration with Eleventy&#39;s routing system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I think this is pretty awesome, it can make the changes AND document it. It is a bit verbose, but it&#39;s a lot better than what I would have written myself (mainly a patience thing)&lt;/p&gt;
&lt;h2 id=&quot;further-work&quot; tabindex=&quot;-1&quot;&gt;further work&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;(bugfix) current rsync cronjob sucks and breaks often&lt;/li&gt;
&lt;li&gt;(bugfix) tasker doesn&#39;t work well with photos taken with cameras&lt;/li&gt;
&lt;li&gt;full-text search of the entire website&lt;/li&gt;
&lt;li&gt;canvas display support&lt;/li&gt;
&lt;li&gt;comment feature, ideally with threads&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;conclusion&lt;/h2&gt;
&lt;p&gt;I now have the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;data store&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;blob storage, running at &lt;a href=&quot;https://lieuzhenghong.com/2025_site_redesign/blob-service.lieu.gg&quot;&gt;blob-service.lieu.gg&lt;/a&gt; and serving files at &lt;a href=&quot;https://lieuzhenghong.com/2025_site_redesign/files.lieu.gg&quot;&gt;files.lieu.gg&lt;/a&gt; and&lt;/li&gt;
&lt;li&gt;second brain (Obsidian vault + GitHub repo)&lt;/li&gt;
&lt;li&gt;secrets vault (TODO)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;views&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2025_site_redesign/lieuzhenghong.com&quot;&gt;lieuzhenghong.com&lt;/a&gt; or &lt;a href=&quot;https://lieuzhenghong.com/2025_site_redesign/lieu.gg&quot;&gt;lieu.gg&lt;/a&gt; (static site, public by default)&lt;/li&gt;
&lt;li&gt;(in future) private view of my second brain, with full-text search over all my private notes&lt;/li&gt;
&lt;li&gt;(maybe, in future) offer services like semi-custodial crypto wallet for friends and family&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h1&gt;
&lt;h2 id=&quot;setting-up-blob-storage&quot; tabindex=&quot;-1&quot;&gt;setting up blob storage&lt;/h2&gt;
&lt;p&gt;R2 and cron&lt;/p&gt;
&lt;p&gt;Set up a Cloudflare account, set up R2 Object Storage&lt;/p&gt;
&lt;p&gt;Set up &lt;code&gt;rclone&lt;/code&gt; on the desktop&lt;/p&gt;
&lt;p&gt;Set up bisync:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rclone bisync ~/Documents/lieu-blobs/ r2:lieu-files/ --resync&lt;/code&gt; for first time, then&lt;/p&gt;
&lt;p&gt;Set up cronjob to sync&lt;/p&gt;
&lt;p&gt;&lt;code&gt;crontab -e&lt;/code&gt;
&lt;code&gt;*/2 * * * * /opt/homebrew/bin/rclone bisync ~/Documents/lieu-blobs/ r2:lieu-files/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;log show --predicate &#39;process == &amp;quot;cron&amp;quot;&#39; --info --last 1d&lt;/code&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>two types of ideas</title>
    <link href="https://lieuzhenghong.com/two_types_of_ideas/"/>
    <updated>2025-06-21T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/two_types_of_ideas/</id>
    <content type="html">&lt;p&gt;there are two kinds of ideas: those that should be scrutinised, and those that should be coddled.&lt;/p&gt;
&lt;p&gt;some ideas present clear costs against relatively predictable benefits. they benefit from being picked apart – from a transparent and strict evaluation of costs and benefits, and a thorough accounting of failure modes and unexpected consequences.&lt;/p&gt;
&lt;p&gt;on the other hand, the best product ideas are delicate, fragile seedlings germinated from one highly counterintuitive insight. they almost always sound stupid and half-baked and they lack critical detail. The ROI is unclear (&amp;quot;this could be huge, but...&amp;quot;). these ideas should be coddled.&lt;/p&gt;
&lt;p&gt;my own business was built upon one of those counterintuitive insights, and I&#39;m not sure that insight would have survived harsh scrutiny.&lt;/p&gt;
&lt;p&gt;most people lock themselves into one mode, either bearish scepticism or unquestioning support. it&#39;s probably a personality trait as well – some people are amazing at enumerating all the things that could go wrong, while others can hone in on that one magical kernel and pull out something great from an otherwise shitty idea. the best people I know have a keen sense of what type of idea something is, and modulate appropriately what type of feedback to give&lt;/p&gt;
&lt;p&gt;scrutiny is harsh, direct sunlight – great for a tall tree, but too much for a fragile seedling. Some decisions need the midday sun; others need a nursery.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.paulgraham.com/startupideas.html&quot;&gt;PG, &lt;em&gt;How to Get Startup Ideas&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>A game 10 years in the making</title>
    <link href="https://lieuzhenghong.com/dice_game/"/>
    <updated>2025-06-19T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/dice_game/</id>
    <content type="html">&lt;p&gt;A game 10 years in the making, started from &lt;a href=&quot;https://docs.google.com/document/d/1Ebu8Fy9bgaMUdLr9RBUzUrhbIElX1WoFRRS90v7rZzw/edit?tab=t.0&quot;&gt;Hunter Killer (CKY&#39;s game) in 2016&lt;/a&gt;, then &lt;a href=&quot;https://docs.google.com/document/d/13BiSxtW1lPIDFJodV-fAIBUcxRiyg3gcPU-cECqRUVo/edit?tab=t.0&quot;&gt;my version in 2022&lt;/a&gt;.  Then I themed it differently and called it &lt;a href=&quot;https://files.lieu.gg/docs/Bulge_Megathread.pdf&quot;&gt;&amp;quot;Bulge&amp;quot;&lt;/a&gt;, and built it for the &lt;a href=&quot;https://lieu.itch.io/beneath-the-skies-dev-version&quot;&gt;2022 GMTK game jam&lt;/a&gt; with dice instead of cards. Now it&#39;s a dice placement game instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Early prototype &lt;a href=&quot;https://lieuzhenghong.com/prevailing-winds-prototype/&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Inspired by Sagrada aesthetically. Also, LLMs have really grown by leaps and bounds, incredible&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/2025-06-19T04-30-02_Pasted_image_20250619123000.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/2025-06-19T04-33-40_Pasted_image_20250619123338.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;prevailing-winds&quot; tabindex=&quot;-1&quot;&gt;Prevailing Winds&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;A strategic dice placement game&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In the toxic skies above a poisoned world, airship captains have developed a peculiar tradition. When negotiations fail and direct conflict seems inevitable, they settle disputes through an ancient game of dice and grid. The game itself is simple - place dice, score patterns - but how one plays reveals everything about their faction&#39;s soul.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The tradition emerged from necessity. In the early days after the Collapse, when every faction was desperate and trigger-happy, actual combat threatened to destroy what little of humanity remained. The game became a way to resolve disputes without bloodshed - though the outcomes often determined trade routes, salvage rights, or even the fate of captured ships. What began as pragmatic conflict resolution evolved into something deeper: a ritual that reveals the philosophical core of each faction.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Every captain knows that their opponents will judge not just their final score, but how they achieved it. Every placement echoes a fundamental answer to survival: Do you scatter and adapt like the Outcasts, refusing all authority even as stronger leaders emerge? Do you build unified foundations like the Settlers, perfecting humanity through controlled breeding? Do you heal the world like the Growers, engineering nature back to life? Do you impose order like the Military, wielding pre-Collapse might in a lawless sky? Do you gather knowledge like the Seekers, preparing humanity&#39;s escape to the stars? Or do you accumulate power like the Merchants, treating the apocalypse as a business opportunity?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Victory in Prevailing Winds isn&#39;t just about points - it&#39;s about proving your way of life superior. Each captain carries their faction&#39;s honor into every placement, every calculated risk. The dice don&#39;t lie, and neither does the philosophy they reveal.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;equipment&quot; tabindex=&quot;-1&quot;&gt;Equipment&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;36 dice (6 colors, 6 dice per color)&lt;/li&gt;
&lt;li&gt;Dice bag (opaque)&lt;/li&gt;
&lt;li&gt;Scoring card deck&lt;/li&gt;
&lt;li&gt;Captain cards&lt;/li&gt;
&lt;li&gt;3 Zone coasters (numbered I, II, III)&lt;/li&gt;
&lt;li&gt;6x6 grid board&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setup&quot; tabindex=&quot;-1&quot;&gt;Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Choose Captains&lt;/strong&gt;: Each player selects a captain card, revealing their signature scoring pattern and ability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Draft Scoring Cards&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Deal 5 scoring cards to each player&lt;/li&gt;
&lt;li&gt;Each player chooses 4 cards to keep, discards 1&lt;/li&gt;
&lt;li&gt;Each player reveals 2 cards of their choice, keeps 2 hidden&lt;/li&gt;
&lt;li&gt;Players now have: 1 signature pattern (captain) + 2 revealed cards + 2 hidden cards&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prepare Zones&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Put all dice in the bag and shake&lt;/li&gt;
&lt;li&gt;Draw one die, roll it, place on Zone I coaster&lt;/li&gt;
&lt;li&gt;Repeat for Zones II and III&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;gameplay&quot; tabindex=&quot;-1&quot;&gt;Gameplay&lt;/h2&gt;
&lt;p&gt;Players alternate turns. On your turn:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Choose a Zone&lt;/strong&gt;: Starting with Zone I, decide whether to take the dice from this zone
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zone I &amp;amp; II&lt;/strong&gt;: Optional - you may choose to skip and move to the next zone
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;If you skip&lt;/em&gt;: Draw one die from the bag, roll it, and add it to the skipped zone&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zone III&lt;/strong&gt;: Mandatory - you must take these dice&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy Dice&lt;/strong&gt;: If you take dice from a zone, place all of them on empty squares of the shared 6x6 atmospheric grid
&lt;ul&gt;
&lt;li&gt;All dice become neutral once deployed - no captain ownership&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refill Zone&lt;/strong&gt;: Draw one die from the bag, roll it, and place it on the zone you just emptied&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Captain Ability&lt;/strong&gt;: You may use your captain&#39;s once-per-engagement ability at the appropriate timing&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;end-game-%26-scoring&quot; tabindex=&quot;-1&quot;&gt;End Game &amp;amp; Scoring&lt;/h2&gt;
&lt;p&gt;The game ends when the grid is completely filled (36 dice placed).&lt;/p&gt;
&lt;p&gt;Each captain scores points from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Their signature pattern&lt;/li&gt;
&lt;li&gt;Their 4 drafted scoring cards (both revealed and hidden)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The captain with the highest total score claims victory.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;key-mechanics&quot; tabindex=&quot;-1&quot;&gt;Key Mechanics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shared Grid&lt;/strong&gt;: Both captains place dice on the same grid, but dice have no owner once placed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asymmetric Scoring&lt;/strong&gt;: Captains score the same final grid using completely different patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zone Risk/Reward&lt;/strong&gt;: Earlier zones are optional but later zones are mandatory&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Information Warfare&lt;/strong&gt;: Hidden scoring cards create uncertainty about opponent&#39;s objectives&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Philosophical Expression&lt;/strong&gt;: Each captain&#39;s approach to play reveals their faction&#39;s worldview&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;faction-captains&quot; tabindex=&quot;-1&quot;&gt;Faction Captains&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Captain &amp;quot;Red&amp;quot; Vasquez (The Outcasts)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Exile&#39;s Domain&amp;quot;: 2 points for each red die on an edge, 4 points for each red die in a corner&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, instead of taking dice from a Zone, you may take up to 1 die from each Zone. Then replenish each Zone you took from. Then take your turn as normal.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;Live free or die.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Comrade Chen (The Settlers)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Genetic Purity&amp;quot;: 10 points for each 2x2 square of white dice.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, instead of taking dice from a Zone, draw 3 dice from the bag. Choose any one die, set it to your desired face, then place it on the board. Return the dice you didn&#39;t choose back to the bag.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;Unity is strength.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Engineer Mika &amp;quot;Bolts&amp;quot; Tanaka (The Growers)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Natural Progression&amp;quot;: For each sequence of consecutive green dice starting from 1, score points equal to the sum of those numbers. Multiple sequences can exist simultaneously.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;(Example: One 1-2-3 sequence scores 6 points, plus one 1-2 sequence scores 3 points, for 9 total)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, before taking your turn, you may swap any number of dice from any of the Zones. The number of dice in each Zone must be the same after your swaps. Then take your turn as normal.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;&lt;em&gt;Natura non facit saltus.&lt;/em&gt;&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Captain Susan Bates (The Military)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Maximum Firepower&amp;quot;: 3 points for each black die that shows 6&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, before taking your turn, you may reroll all dice across all Zones that show 1s or 2s. Then take your turn as normal.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;Overwhelming force, decisively concentrated.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Prof. Gennady Mitrichev (The Seekers)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Intelligence Hub&amp;quot;: 3 points for each blue die where all adjacent dice show different colors and different numbers&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, before taking your turn, draw three dice from the dice bag. Roll them and place one in each zone (your choice). Then take your turn as normal.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;Knowledge is power.&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Outer Prince Wangxian (The Merchants)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Signature Pattern&lt;/em&gt;: &amp;quot;Profitable Arbitrage&amp;quot;: 3 points for each purple die that&#39;s adjacent to both a 1 and a 6.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ability&lt;/em&gt;: Once per game, after any player&#39;s turn, you may swap any die on the board with any die from any Zone.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Style&lt;/em&gt;: &amp;quot;浑水摸鱼&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;scoring-cards&quot; tabindex=&quot;-1&quot;&gt;Scoring Cards&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;High Roller&lt;/em&gt;: 1 point for each die showing 6&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Edge Control&lt;/em&gt;: 1 point for each die on the border that has the same number as an adjacent border die&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Twins&lt;/em&gt;: 2 points for each pair of identical adjacent dice (e.g. both red 1s)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;($COLOUR) Corners&lt;/em&gt;: 1 point for each corner occupied by $COLOUR.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Spread Out&lt;/em&gt;: 3 points for each color that appears in all four quadrants of the board&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Four Corners&lt;/em&gt;: 8 points if all corners are 4s.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Straight&lt;/em&gt;: 10 points for each row, column, or diagonal that shows 1-2-3-4-5-6&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rainbow Road&lt;/em&gt;: 10 points for each row, column, or diagonal that shows R-O-Y-G-B-P&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Colour Purity&lt;/em&gt;: 12 points for each 3×2 rectangle that contains only one color&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Red Tide&lt;/em&gt;: 15 points if any border row or column is all red.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Perfect Twos&lt;/em&gt;: 15 points if the center 2x2 square contains all 2s&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Six Sixes&lt;/em&gt;: 25 points if exactly 6 dice show the number 6&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Perfect Balance&lt;/em&gt;: 30 points if each number appears exactly 6 times&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h1 id=&quot;faction-histories-%26-motivations&quot; tabindex=&quot;-1&quot;&gt;Faction Histories &amp;amp; Motivations&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;The Six Powers of the Toxic Skies&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In the aftermath of the Collapse, when the surface world became a poisoned wasteland and humanity fled to the skies, six distinct philosophies emerged. Each faction represents not just a survival strategy, but a fundamental answer to the question: &amp;quot;What does it mean to be human when the world has ended?&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-outcasts-(red)&quot; tabindex=&quot;-1&quot;&gt;The Outcasts (Red)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Freedom or death - we bow to no one.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: The Outcasts aren&#39;t a true faction so much as everyone who couldn&#39;t or wouldn&#39;t fit into the others. Exiles, rebels, free spirits, and those who simply wanted to chart their own course. They rejected the safety of large colony ships for the freedom of small, fast vessels and the open sky.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: Fierce individualism and anarchist ideals. They believe that centralized authority was what caused the Collapse in the first place, and that true freedom comes from rejecting all forms of institutional control. Every captain is sovereign over their own ship.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: Small, fast, self-sufficient vessels. Hit-and-run tactics. Survival through adaptability and improvisation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: While they embrace libertarian anarchy and radical individualism, the harsh realities of survival inevitably lead to stronger leaders consolidating power. A growing coalition under a charismatic strongman threatens their core values - but their anarchist principles make it nearly impossible to organize effective resistance.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-settlers-(white)&quot; tabindex=&quot;-1&quot;&gt;The Settlers (White)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Strong bodies, pure purpose, solid foundations.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: Descendants of survivalists and physical fitness enthusiasts who believed human enhancement was the key to reclaiming the world. They&#39;ve spent generations perfecting the human form through selective breeding, genetic engineering, and intensive physical training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: To resettle the poisoned surface world using genetically enhanced humans in environmental suits. They believe that with enough physical and mental conditioning, humanity can adapt to survive anywhere - even a toxic wasteland.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: Large sailing ships with white and red colors. Defensive tactics focused on endurance and outlasting enemies rather than quick victories.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: They preach the sanctity of the human body while practicing eugenics and forced sterilization. They claim to value mental development and diverse thinking while being deeply intolerant of dissenting viewpoints. Their pursuit of human perfection has made them profoundly inhuman.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-growers-(green)&quot; tabindex=&quot;-1&quot;&gt;The Growers (Green)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Heal the world, don&#39;t abandon it.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: Originally part of the Knowledge faction, they split over a fundamental disagreement about humanity&#39;s future. While the Blues wanted to escape to the stars, the Greens believed in healing and terraforming the damaged world.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: Develop biological solutions to purify the toxic atmosphere and rehabilitate the surface. They&#39;re breeding extremophile organisms and engineering algae to metabolize the poisonous gases, working toward a day when the surface blooms again.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: Bio-integrated ships that blur the line between vessel and organism. Patient, defensive strategies focused on long-term growth over short-term gains.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: They preach organic, natural growth and spiritual harmony while simultaneously engineering organisms at the genetic level and manipulating nature through advanced biotechnology. Their emphasis on individual spiritual enlightenment (often aided by psychedelics) conflicts with the massive coordinated effort their terraforming project requires.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-military-(black)&quot; tabindex=&quot;-1&quot;&gt;The Military (Black)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Order from chaos. Authority through strength.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: The remnants of pre-Collapse military forces who maintained their command structure and discipline even as the world ended. They possess the most powerful warships - massive pre-Collapse vessels that they struggle to maintain.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: Restore law and order in the post-apocalyptic world by establishing their monopoly on legitimate force. They see themselves as the inheritors of proper government and the only hope for returning civilization to the skies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: Overwhelming firepower and shock tactics. Use superior technology and concentrated force to end conflicts quickly and decisively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: Their irreplaceable ships are slowly failing and they can&#39;t agree whether to abandon their technological advantage or desperately search for ways to maintain it. They claim to protect civilization, but the governments they served no longer exist - they may just be preserving the forms of authority without any legitimate purpose.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-seekers-(blue)&quot; tabindex=&quot;-1&quot;&gt;The Seekers (Blue)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Through hardships to the stars.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: Born from universities, research institutions, and tech companies that survived the Collapse. They split from the Greens over whether to fix the world or transcend it, choosing the path of technological advancement and eventual escape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: Salvage lost knowledge, develop advanced technology, and escape to another world. They believe Earth is beyond saving and that humanity&#39;s future lies among the stars.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: High-tech vessels with advanced sensors and AI. Information warfare - know your enemy completely before engaging.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: They pride themselves on egalitarianism yet their austere lifestyle only attracts intellectual misfits, accidentally creating an elite caste. They&#39;re dedicated to preserving human knowledge while planning to abandon the world that created it. They claim rational problem-solving as their strength, yet their core strategy is escapism rather than solutions. Their utilitarian efficiency may suppress the very creativity and human diversity that drives innovation.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;the-merchants-(purple)&quot; tabindex=&quot;-1&quot;&gt;The Merchants (Purple)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&amp;quot;Blood, gold, and power - the eternal currencies.&amp;quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;History&lt;/strong&gt;: Built around the flying harem palace of a pre-Collapse trillionaire. Now his descendants rule a hierarchical monarchy where everyone claims blood relation to the founder, creating brutal dynastic power struggles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Motivation&lt;/strong&gt;: Maintain their decadent empire through trade and exploitation. They view all non-royals as barbarians to be used for labor or breeding. The most beautiful women around are &amp;quot;collected&amp;quot; for the inner palace and never seen again. Outer princes eke out a living, usually as merchants; inner princes live lives of decadent luxury but fight brutal dynastic battles behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fleet Philosophy&lt;/strong&gt;: Opulent vessels that display wealth and power. Slow, grinding economic warfare positions for long-term advantage rather than direct confrontation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fundamental Contradictions&lt;/strong&gt;: Their rhetoric of family obligation and noble blood conflicts with the brutal internal power struggles and dynastic backstabbing. They practice slavery, forced marriage, and sexual exploitation while claiming to honor familial bonds. Their isolationist xenophobia conflicts with their need for trade and fresh victims.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Each faction&#39;s approach to the dice grid reveals their deepest beliefs about survival, society, and the future of humanity. In Prevailing Winds, you don&#39;t just play a strategy - you embody a philosophy.&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>On growth</title>
    <link href="https://lieuzhenghong.com/growth/"/>
    <updated>2025-06-14T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/growth/</id>
    <content type="html">&lt;p&gt;if addiction is the progressive narrowing of the things that bring us joy, growth is the opposite: it&#39;s the progressive widening of the set of situations we can be comfortable in.&lt;/p&gt;
&lt;p&gt;We are all prisoners to our own neuroses. The way to grow past that is to deliberately expose ourselves to uncomfortable situations.&lt;/p&gt;
&lt;p&gt;My explicit goal in 2025 was to actively and aggressively seek out uncomfortable situations; to &amp;quot;surf the edge of my discomfort&amp;quot;, and by doing so become more comfortable with discomfort. I wanted to deliberately seek out failure and put myself in positions to get rejected more. Some personal examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Forcing myself to speak only German in Berlin&lt;/li&gt;
&lt;li&gt;Asking girls out in person&lt;/li&gt;
&lt;li&gt;Walking around Singapore barefoot&lt;/li&gt;
&lt;li&gt;Going to social dances (this was by far the hardest one! When I first started I really hated dancing; I have two left feet, I&#39;m super uncoordinated, I was pretty awkward touching people)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Discomfort should be carefully calibrated -- too much and you&#39;ll be paralysed into inaction, too little and it won&#39;t grow you maximally. How I &amp;quot;titrated&amp;quot; my discomfort:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Learning German&lt;/em&gt;: I first started sounding out the letters to Celine, who (as a kind-hearted person and my partner at the time) was obligated to be patient with me. Then I signed myself up for an intensive German course in Singapore. Finally I signed up for an intensive German course in Berlin and forced myself to speak German to strangers.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Asking girls out in person:&lt;/em&gt; I started talking to random guys at the gym, just to build up that &amp;quot;talking to strangers muscle&amp;quot;; it&#39;s a pretty low-stakes environment. Then I started going up to people at parties and introducing myself. Finally I started asking girls out in appropriate contexts (maybe don&#39;t do it on the MRT, but after a class or an activity/meetup seemed to work well enough for me)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Walking around Singapore barefoot&lt;/em&gt;: I first started going around my neighbourhood shirtless, then started wearing a sarong out, then finally started going about my day barefoot.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Learning to dance&lt;/em&gt;: What helped was going with a bunch of my classmates. Even today I have to psych myself up, I have to muster up the activation energy to leave my bed, and then I&#39;ll do some self-talk: &amp;quot;I&#39;ll just ask one person to dance&amp;quot;. And then I go there and I ask one person and then it becomes easier and easier!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many times our neuroses turn out to be unjustified or exaggerated. People are a lot nicer than you think! Examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; I thought that people would make fun of my german in berlin but it turned out everyone was mostly VERY patient and very helpful (sometimes they switched to english when they were tired babying me, which, I completely understand, but 99% of the time they were amazing)&lt;/li&gt;
&lt;li&gt;I thought I was a weirdo wearing a sarong out and I was super self-conscious about it, but people just thought I was Burmese or something. It was fine! One time someone shouted to get my attention in the street, I turned around, it was this Indian man wearing a sarong as well, he was like &amp;quot;Good job!&amp;quot; gave me a thumbs up lmao.
&lt;ul&gt;
&lt;li&gt;The barefoot stuff was a lot weirder, people would come up to me saying &amp;quot;where are your shoes&amp;quot;, I just said &amp;quot;I left them at home&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some girls turned me down, some girls said yes (yay!) but even when they turn me down they do it in a very friendly and kind way. And of course, even one girl saying yes was a HUGE win, and made my week.&lt;/li&gt;
&lt;li&gt;I was MORTIFIED going into social dancing, but people were mostly very friendly/patient; the not patient ones were cordial enough, and the best ones came back to ask for dances on their own accord, even gave me feedback and taught me new moves&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Things won&#39;t be perfect; not everyone is going to be OVERJOYED THAT YOU ARE TRYING TO LEARN GERMAN, for example. Some people will be a little &amp;quot;black face&amp;quot; or mean, but by and large it&#39;s going to be A LOT BETTER than you think.&lt;/p&gt;
&lt;p&gt;Xenophon on Cyrus:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Of all Cyrus’s many qualities: willpower, strength, charisma, glibness, intelligence, handsomeness; Xenophon makes a point of emphasizing one in particular, and his choice might strike some readers as strange. It is this: “He did not run from being defeated into the refuge of not doing that in which he had been defeated.” Cyrus learned to love the feeling of failure, because failure means you’re facing a worthy challenge, failure means you haven’t set your sights too low, failure means you’ve encountered a stone hard enough to sharpen your own edge. He’s found a cognitive meta-tool, one of those secrets of the universe which, if you can actually internalize them, make you better at everything. Failure feels &lt;em&gt;good&lt;/em&gt; to him rather than bad, is it any surprise he goes on to conquer the world?&lt;/em&gt;
(source: &lt;a href=&quot;https://www.thepsmiths.com/p/review-the-education-of-cyrus-by&quot;&gt;REVIEW: The Education of Cyrus, by Xenophon&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
</content>
  </entry>
  <entry>
    <title>Advice for finalists</title>
    <link href="https://lieuzhenghong.com/advice_for_finalists/"/>
    <updated>2025-06-13T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/advice_for_finalists/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#don&#39;t-stress-too-much-about-finals&quot;&gt;Don&amp;#39;t stress too much about finals&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#beware-the-prestige-premium&quot;&gt;Beware the prestige premium&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#your-option-set-is-a-lot-larger-than-you-think&quot;&gt;Your option set is a lot larger than you think&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#good-people-are-always-in-demand&quot;&gt;Good people are always in demand&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#learn-to-build&quot;&gt;Learn to build&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#just-ask-for-things&quot;&gt;Just ask for things&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#minimise-regret&quot;&gt;Minimise regret&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#lean-into-discomfort&quot;&gt;Lean into discomfort&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#body-affects-mind%3B-mind-affects-body&quot;&gt;Body affects mind; mind affects body&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#be-kind-to-yourself-and-others&quot;&gt;Be kind to yourself and others&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#be-humble&quot;&gt;Be humble&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#it-really-is-about-the-friends-you-make-along-the-way&quot;&gt;It really is about the friends you make along the way&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/advice_for_finalists/#be-a-good-person&quot;&gt;Be a good person&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;Advice often sucks! It encodes the advice-giver&#39;s biases, and it&#39;s never tailored for the individual. You may want to consider &lt;a href=&quot;https://slatestarcodex.com/2014/03/24/should-you-reverse-any-advice-you-hear/&quot;&gt;reversing any advice you read here&lt;/a&gt;. The &lt;a href=&quot;https://en.wikipedia.org/wiki/Golden_mean_(philosophy)&quot;&gt;golden mean&lt;/a&gt; applies.&lt;/p&gt;
&lt;h1 id=&quot;don&#39;t-stress-too-much-about-finals&quot; tabindex=&quot;-1&quot;&gt;Don&#39;t stress too much about finals&lt;/h1&gt;
&lt;p&gt;It doesn&#39;t matter as much as you think. Really. No one at my job even knows (and they certainly don&#39;t care) what university I went to or what modules I studied. Your work will speak for itself.&lt;/p&gt;
&lt;p&gt;Your agency, your work ethic, and your ability to learn and grow from here on out will make much more of a difference going forward.&lt;/p&gt;
&lt;h1 id=&quot;beware-the-prestige-premium&quot; tabindex=&quot;-1&quot;&gt;Beware the prestige premium&lt;/h1&gt;
&lt;p&gt;The more legible and &amp;quot;prestigious&amp;quot; something is, the more overrated it tends to be.&lt;/p&gt;
&lt;p&gt;By legible, I mean anything with a highly formalised and competitive application process, anything with spring/summer internship, anything with a fresh grad intake, etc.
The gobs of money you can make as a barrister, consultant, banker are highly legible, but I promise there are gobs of money to be made all over the world in domains you wouldn&#39;t and can&#39;t imagine.&lt;/p&gt;
&lt;p&gt;If you can find a field that none of your peers are going into, you&#39;ll stand out a lot. Even better if you can find a highly unpopular field people actively denigrate. These fields also select for iconoclasts, whom I always find more interesting.&lt;/p&gt;
&lt;h1 id=&quot;your-option-set-is-a-lot-larger-than-you-think&quot; tabindex=&quot;-1&quot;&gt;Your option set is a lot larger than you think&lt;/h1&gt;
&lt;p&gt;Your option set is circumscribed by your beliefs and by the people around you. In the army I somehow thought that the best thing I should do is apply for an Air Force scholarship. And in Oxford I considered doing a Masters&#39; because everyone else seemed to be doing it.&lt;/p&gt;
&lt;p&gt;We put up a lot of self-imposed barriers on what we think our options are. Oxford is a very academic place; it&#39;s hard not to consider academia when all your friends, professors etc. are doing it. And if you see your forebears doing finance, law, consulting, engineering, medicine, it&#39;s easy to follow in their footsteps, too. Don&#39;t forget the world is big, you have only seen a very small part of it.&lt;/p&gt;
&lt;h1 id=&quot;good-people-are-always-in-demand&quot; tabindex=&quot;-1&quot;&gt;Good people are always in demand&lt;/h1&gt;
&lt;p&gt;If you are good, there will always be a place for you. From what I&#39;ve seen, good people never need to look for jobs; the moment they quit, there are a string of offers for them, they just pick their favourite one. (Of course, it helps to put yourself out there: see &amp;quot;Just ask for things&amp;quot;.)&lt;/p&gt;
&lt;p&gt;I joined a startup incubator program last year. Most of the companies failed, but pretty much everyone got snapped up by other companies, because they were good.&lt;/p&gt;
&lt;p&gt;How to be good? Work on stuff &lt;em&gt;you&lt;/em&gt; genuinely think is important and interesting, not what society tells you is lucrative or prestigious. This will let you surpass everyone effortlessly; a genuine interest in something gives you the superpower of being able to work all the time, without it feeling like work.&lt;/p&gt;
&lt;p&gt;Don&#39;t conflate looking good with being good. Some founders post on Twitter about how hard they work, they&#39;ll focus on vanity metrics so they can raise bigger and bigger funding rounds, they&#39;ll go to lots of events and podcasts, they&#39;ll be Forbes 30 under 30... but none of this matters because they can&#39;t actually build. Resist the urge to play status games; just focus on being good instead.&lt;/p&gt;
&lt;h1 id=&quot;learn-to-build&quot; tabindex=&quot;-1&quot;&gt;Learn to build&lt;/h1&gt;
&lt;p&gt;The vast majority of legible, prestigious jobs seem not to be about building at all, but about managing, allocating, optimising.&lt;/p&gt;
&lt;p&gt;Learn to build, not allocate capital.&lt;/p&gt;
&lt;p&gt;Building is a lot more fun and a lot more fulfilling. Building is imposing your will on the world; it is drawing order out of chaos. Compared to a capital allocator, you have maximum agency. Would you rather watch porn or have sex?&lt;/p&gt;
&lt;p&gt;If you learn to build, you can make things happen, and making things happen is a rare superpower. Having lots of money is great, but even people with money need good builders to make things happen.&lt;/p&gt;
&lt;h1 id=&quot;just-ask-for-things&quot; tabindex=&quot;-1&quot;&gt;Just ask for things&lt;/h1&gt;
&lt;p&gt;The rules of the game are a lot more malleable than you think. A lot of the time you can just ask for stuff and you might just get it!&lt;/p&gt;
&lt;p&gt;There used to be a rule in PPE (maybe there still is) that if you wanted to do a Thesis in Politics, you had to do three other politics modules. But I didn&#39;t want to do three other politics modules. I thought it was set in stone (I mean, it&#39;s very explicitly written in the Students&#39; Handbook), but I thought I&#39;d punt anyway. So I emailed the Academic Registrar if I could do it. After a bit of back-and-forth (and with Bassel and Tia putting in a good word), it was approved???&lt;/p&gt;
&lt;p&gt;Most jobs, internships etc., are not advertised. If you admire someone and their work, tell them so, and ask if you can work with them; I promise they&#39;ll be flattered. I&#39;ve done this a few times already, and had many fruitful collaborations.&lt;/p&gt;
&lt;p&gt;The trick to asking for things is not to get too attached to the outcome. Don&#39;t take &amp;quot;no&amp;quot; too personally -- it may not be about you. (And sometimes it is, but you&#39;re always growing, right?)&lt;/p&gt;
&lt;p&gt;Treat the people whom you ask things from with the utmost respect and kindness. It&#39;s hard to say no, so make it as easy as you can for the other person. If you ask to work with someone, and they say no, maybe they don&#39;t have a vacancy, maybe you&#39;re not skilled enough yet, no worries, thank you for considering me in any case. If you ask someone out and they say no, okay that sucks, but hey, absolutely no worries at all, totally understand, respect your decision. And then tell yourself: it was a long shot anyway, I&#39;m glad I asked!&lt;/p&gt;
&lt;h1 id=&quot;minimise-regret&quot; tabindex=&quot;-1&quot;&gt;Minimise regret&lt;/h1&gt;
&lt;p&gt;A lot of the time we don&#39;t regret doing things; we regret &lt;em&gt;not&lt;/em&gt; having done things.&lt;/p&gt;
&lt;p&gt;When I was in college there was a gorgeous girl called Rosanna. I had a big crush on her and we got along quite well, but I never asked her out, because the last guy she dated was a really tall, handsome, and posh guy who went to Eton, and I didn&#39;t think she&#39;d deign to date a short Asian guy who went to Bukit Panjang Primary School. It turned out her last boyfriend was half-Asian and shorter than her, so I had ruled myself out for no reason. I still think about that sometimes. Don&#39;t let that be you!&lt;/p&gt;
&lt;p&gt;Our fears, insecurities, and anxieties often paralyse us. Force yourself to bias towards action to counteract this natural tendency. When you do something, you may succeed (great). And if you fuck up, you will learn, and that&#39;s a great outcome too. When you choose inaction, there is no chance of succeeding, plus you have learned nothing. You miss 100% of the shots you don&#39;t take.&lt;/p&gt;
&lt;h1 id=&quot;lean-into-discomfort&quot; tabindex=&quot;-1&quot;&gt;Lean into discomfort&lt;/h1&gt;
&lt;p&gt;Actively do stuff that makes you uncomfortable.&lt;/p&gt;
&lt;p&gt;If addiction is the progressive narrowing of the set of things that give you pleasure, &lt;a href=&quot;https://lieuzhenghong.com/growth/&quot;&gt;growth is the progressive widening of the set of situations you can be comfortable in&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The more you do stuff that makes you uncomfortable, the less uncomfortable those situations will become. Titrate slowly, take baby steps; you will make a lot of progress very quickly.&lt;/p&gt;
&lt;h1 id=&quot;body-affects-mind%3B-mind-affects-body&quot; tabindex=&quot;-1&quot;&gt;Body affects mind; mind affects body&lt;/h1&gt;
&lt;p&gt;I always thought of my brain as a Platonic-ideal thinking machine, with no relation to my body, always able to find some clever solution to intractable problems.&lt;/p&gt;
&lt;p&gt;My startup was gearing up for a big public launch. I&#39;d been working 7 day weeks for 3 weeks straight, with pretty much no sleep. I&#39;d try to get to bed, but I&#39;d find myself waking up in the middle of the night, heart racing, or have my mind spin in circles due to all the stuff we&#39;d still need to do.&lt;/p&gt;
&lt;p&gt;There was a lot of pushback on the launch due to some decisions we&#39;d made, and after yet another all-nighter, I&#39;d written a draft announcement reversing some of the more controversial decisions. I thought it was good work; an excellent way to thread the needle.&lt;/p&gt;
&lt;p&gt;I sent the draft over to our launch partner for final comments. The founder of that partner company called me and said: under no circumstances should you send this out, you will completely destroy your reputation.&lt;/p&gt;
&lt;p&gt;I am so glad I listened to him; he saved me from self-destructing my company.&lt;/p&gt;
&lt;p&gt;My mentor once told me: when your judgement is affected, the first thing to go is the ability to judge that your judgement is affected. Learn to listen to your body, because it really, really affects the mind.&lt;/p&gt;
&lt;p&gt;Take care of yourself!&lt;/p&gt;
&lt;h1 id=&quot;be-kind-to-yourself-and-others&quot; tabindex=&quot;-1&quot;&gt;Be kind to yourself and others&lt;/h1&gt;
&lt;p&gt;High-achiever types are often very harsh with themselves. I think it stems from some deep-seated insecurity of not being good enough.&lt;/p&gt;
&lt;p&gt;I often find myself lying in bed reliving every single one of my mistakes; &amp;quot;I should have said this, I should have done that, if only...&amp;quot;&lt;/p&gt;
&lt;p&gt;You are not perfect; you will fuck up, but you will improve. Be kind to, and patient with, yourself.&lt;/p&gt;
&lt;p&gt;My self-talk is oftentimes very harsh. When I catch myself doing so, I say to myself: &lt;em&gt;would I say this to a stranger or a friend?&lt;/em&gt; And the answer often is no.&lt;/p&gt;
&lt;p&gt;Give yourself the space to celebrate your good work, don&#39;t keep rushing to the next thing.&lt;/p&gt;
&lt;p&gt;If you admire someone for something, tell them about it! You will make their day.
&lt;img src=&quot;https://files.lieu.gg/2025-06-14T17-02-01-943Z_IMG_20250614_180050_012.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;be-humble&quot; tabindex=&quot;-1&quot;&gt;Be humble&lt;/h1&gt;
&lt;p&gt;Growing up we&#39;re all taught to do the thing where we all glaze the guy who does well (&amp;quot;wah you damn upz sia&amp;quot;) and the guy has to deflect everything (&amp;quot;no la no la lucky only&amp;quot;). This isn&#39;t actually humility; this is performative, this is &lt;em&gt;wayang&lt;/em&gt; show.&lt;/p&gt;
&lt;p&gt;Humility is not performative modesty. Humility is being rightfully proud of what you&#39;ve achieved, and simultaneously recognising that you still have a long way to go and a lot to learn.&lt;/p&gt;
&lt;h1 id=&quot;it-really-is-about-the-friends-you-make-along-the-way&quot; tabindex=&quot;-1&quot;&gt;It really is about the friends you make along the way&lt;/h1&gt;
&lt;p&gt;There is no need for everyone to like you, you don&#39;t have to be friends with everyone. Polite, cordial, certainly; but some people are just not your tribe, and that&#39;s fine. Try your best to find your tribe: the people who share your same values, who match your freak. Then hold onto them and don&#39;t let go.&lt;/p&gt;
&lt;p&gt;Some of your friends you&#39;ll admire because of their competence, others you will love because of their kind heart. You should try to find the thing you love in every one of your friends.&lt;/p&gt;
&lt;h1 id=&quot;be-a-good-person&quot; tabindex=&quot;-1&quot;&gt;Be a good person&lt;/h1&gt;
&lt;p&gt;As you focus on being a good builder and executor, don&#39;t forget to be a good person, too. Are you loyal to your friends? Are you true to your word? Are you generous? Respectful? Kind? Compassionate? Are you doing any 亏心事?&lt;/p&gt;
&lt;p&gt;As with anything else, being a good person is a learning process, too. I am selfish, judgmental, lazy, dishonest, impatient, rude, and a hundred other things, but I will always strive to be better. In the short time we are here on this earth, we should try to be like shooting stars -- lighting up the lives of those we pass by.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Braindump on language learning</title>
    <link href="https://lieuzhenghong.com/language_learning/"/>
    <updated>2025-06-10T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/language_learning/</id>
    <content type="html">&lt;p&gt;related posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/language_learning_with_ai/&quot;&gt;language learning with AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/deutsch_lernen/&quot;&gt;deutsch lernen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/language_learning_brain_plasticity/&quot;&gt;how to increase brain plasticity with language learning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Deutsch Lernen</title>
    <link href="https://lieuzhenghong.com/deutsch_lernen/"/>
    <updated>2023-09-10T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/deutsch_lernen/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
[toc]
&lt;/div&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;introduction&lt;/h1&gt;
&lt;p&gt;very rough notes, not meant for public consumption, it&#39;s where I dump everything&lt;/p&gt;
&lt;h1 id=&quot;2023-09-10&quot; tabindex=&quot;-1&quot;&gt;2023-09-10&lt;/h1&gt;
&lt;p&gt;die Gelegenheit
die Gelegenheit sprechen zu können und uns mit längeren Texten befassen zu können
ich fuhle mich verloren  - i feel lost
der? Arbeitsumfeld in den Medien
das kommt darauf an - it depends
Es kommt darauf an welchen Stil der musiker hat.
Normaleweise lese ich keine nachtrichten, selbst auf Englisch.
vorkommen
Wenn man schnell zum Arbeit gehen muss, wurde man ehe ein Taxi nehmen anstatt zu Fuß zu gehen&lt;/p&gt;
&lt;h1 id=&quot;2023-08-31&quot; tabindex=&quot;-1&quot;&gt;2023-08-31&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[x] abschnitt - a section
&lt;ul&gt;
&lt;li&gt;[x] Als Rettungsschwimmer beobachte ich einen Abschnitt des Flusses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] beweisen - to prove
&lt;ul&gt;
&lt;li&gt;[x] In meinem Studium beweise ich viele Theorien.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Interessengebiet
&lt;ul&gt;
&lt;li&gt;[x] Das wissenschaftliche Interessengebiet (das Fach, an dem man interessiert ist) von mir ist Wirtschaftswissenschaft, besonders die Spieltheorie.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] seit kurzem
&lt;ul&gt;
&lt;li&gt;[x] Seit kurzem (in letzter Zeit) mache ich Calisthenics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ablegen -- to discard&lt;/li&gt;
&lt;li&gt;[x] das Denkmuster -- the thought patterns
&lt;ul&gt;
&lt;li&gt;[x] Wenn man Chinesisches Schach spielt, muss man die alten Denkmuster aus dem internationalen Schach ablegen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der bereich -- area
&lt;ul&gt;
&lt;li&gt;[x] Im Chinesischen Schach kann der König nicht über seinen Bereich hinausgehen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] hingehen, gehen
&lt;ul&gt;
&lt;li&gt;[x] Die unterschied zwischen &amp;quot;hingehen&amp;quot; und &amp;quot;gehen&amp;quot; besteht darin, dass &amp;quot;hingehen&amp;quot; ein Ziel, einen Bestimmungsort braucht.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] erfordert -- to require
&lt;ul&gt;
&lt;li&gt;[x] Lernen erfordert ständige Wiederholung.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] unvorsichtig -- careless
&lt;ul&gt;
&lt;li&gt;[x] Ich bin sehr unvorsichtig. Ich hänge meine Figuren beim Schach immer auf.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] unüblich
&lt;ul&gt;
&lt;li&gt;[x] Es ist unüblich, &amp;quot;kreuzen&amp;quot; anstatt &amp;quot;überqueren&amp;quot; zu sagen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] überqueren: Wir überqueren die Straße.&lt;/li&gt;
&lt;li&gt;[x] ertrinken -- to drown in&lt;/li&gt;
&lt;li&gt;[x] Zeitlupe - in slow motion
&lt;ul&gt;
&lt;li&gt;[x] Ich bin ein Rettungsschwimmer. Wenn eine Person ertrinkt, laufe ich wie in Zeitlupe um die Schwimmerin zu retten.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ehreamtlich
&lt;ul&gt;
&lt;li&gt;[x] Wenn man es ehrenamtlich (freiwillig) macht, erhält man kein Gehalt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Nacktschnecke
&lt;ul&gt;
&lt;li&gt;[x] Heute haben wir im Park eine Nacktschnecke gesehen. Sie war sehr lang und rot.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Schwert, Feinde, besiegen
&lt;ul&gt;
&lt;li&gt;[x] Der Mann traniert mit einem Schwert, um seine Feinde zu besiegen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] abnehmen: to lose weight
&lt;ul&gt;
&lt;li&gt;[x] Nächstes Jahr will ich 5kg abnehmen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ausdauer, abgewogen
&lt;ul&gt;
&lt;li&gt;[x] Es wird zwischen kraft und ausdauer abgewogen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] zuständig für
&lt;ul&gt;
&lt;li&gt;[x] Die Handlers sind zuständig für das Werfen der Frisbee.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] vorhersehbar
&lt;ul&gt;
&lt;li&gt;[x] &amp;quot;Vertical Stack&amp;quot; ist relativ einfach zu spielen, aber vorhersehbar.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] höchstens
&lt;ul&gt;
&lt;li&gt;[x] Ich kann höchstens 90 Tage in Europa bleiben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;faust&quot; tabindex=&quot;-1&quot;&gt;faust&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[x] wohl&lt;/li&gt;
&lt;li&gt;[x] erscheinen, (ist erschienen) -- to publish
&lt;ul&gt;
&lt;li&gt;[x] 1587 ist bei dem frankfurter buchdrucker das werk wohl zum ersten Mal erschienen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] akten
&lt;ul&gt;
&lt;li&gt;[x] In den Akten der Städte wird er als Nigromant genannt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Sein Name soll Johann Faust gewesen sein&lt;/li&gt;
&lt;li&gt;[x] der Teufel, holen (geholt),
&lt;ul&gt;
&lt;li&gt;[x] Ob das eine Explosion war oder ob der Teufel ihn geholt hat, wissen wir natürlich nicht.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Für Kunst scheint die Idee, seine Seele dem Teufel zu verschreiben, um Erfolg zu haben, besonders naheliegend zu sein.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;wortschatz&quot; tabindex=&quot;-1&quot;&gt;wortschatz&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;[x] die Absage - the rejection&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] Je mehr Absagen ich bekam, desto frustrierter wurde ich naturlich.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] abwechlungsreich&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[x] Mein Job ist oft gefährlich, aber immer abwechslungsreich&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] anstrengend: exhausting&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[ ]&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] berechtigt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Berufserfahrung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Bewerbung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] sich durchkämpfen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] entlassen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] geeignet&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] genügend&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Herausforderung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] klappen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Lebenslauf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] das Praktikum&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Stellenanzeige&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] übernehmen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] die Tätigkeit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Verlag&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] vermitteln&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Vertrag&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] vielfältig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zahlreich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] angemessen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] das Ansehen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] anspruchsvoll&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] etw. bewältigen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Finanzkrise&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Flexibilität&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] hauptsächlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Last&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Leistung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] lukrativ&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] mangeln an&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Misserfolg&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Studie&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Verlust&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] verlässlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] vernünftig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der/die Vorgesetzte&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] ablenken von&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Geschäftsleitung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Hammer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] nahegelegen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Säge&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Teambildung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] das Teamevent&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] umrunden&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] voraussichtlich - wahrscheinlich, vermutlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zwingen zu (jmd. zwingen etwas zu tun)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Abschluss&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Anforderung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Betreuung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] einheitlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Eintrittstermin&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Kenntnis&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] einbringen in&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Fähigkeit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Stellenausschreibung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] teamfähig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] übersichtlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] umfangreich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Weiterbildung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zielorientiert&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] behandeln&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Anforderungen erfüllen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] jmd. fest anstellen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] sich an die Arbeit machen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] eine Aufgabe übernehmen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Druck ausüben&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Fehler eingestehen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] in Gefahr sein&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] sich im Job aufreiben&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Konflikte lösen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Kontakte knüpfen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Sinn und Zweck von etw.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] im Zusammenhang mit etw. stehen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zwei linke Hände haben&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Es kommt darauf an&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] aktuelle sein&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] aufpassen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] tippen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] annehmen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zweiten Spalte&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] Zeugnis&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] nicht zwingend&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] zusätzlich&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Vekehr&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Verein&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Ernährung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Konsum&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] das Krankenhaus&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] der Abschluss&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] das Studium&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Universität&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Wahlen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Behörde&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] die Medien&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-08-19&quot; tabindex=&quot;-1&quot;&gt;2023-08-19&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[x] überlegen / die überlegung
&lt;ul&gt;
&lt;li&gt;[x] Ich überlege heute abend ins Kino zu gehen&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] nachweise&lt;/li&gt;
&lt;li&gt;[x] ausgetreten&lt;/li&gt;
&lt;li&gt;[x] auf jeden fall -- definitely? in any case&lt;/li&gt;
&lt;li&gt;[x] Die Schere zwischen Arm und Reich n Singapu ist relativ groß.&lt;/li&gt;
&lt;li&gt;[x] unter Drogen stehen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;lieu, [19/08/2023 09:39]&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ischgl -- skiing spot in Austria.&lt;/li&gt;
&lt;li&gt;Apres Ski&lt;/li&gt;
&lt;li&gt;Vabali Spa -- in der Nahe von dem Hauptbahnhof&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-08-16&quot; tabindex=&quot;-1&quot;&gt;2023-08-16&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[ ] vorteil
&lt;ul&gt;
&lt;li&gt;[ ] Ich habe ein Vorteil davon, wenn ich Deutsch sprechen kann.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] aussagekräftig - relevant&lt;/li&gt;
&lt;li&gt;[ ] ausschließlich -- nur (exclusively)&lt;/li&gt;
&lt;li&gt;[ ] Eigenschaften&lt;/li&gt;
&lt;li&gt;[ ] Heutzutage schicken wir die Bewerbung per Mail mit Anhängen.&lt;/li&gt;
&lt;li&gt;[ ] leistung v.s. leitung&lt;/li&gt;
&lt;li&gt;[ ] stattfinden
&lt;ul&gt;
&lt;li&gt;[ ] alle Veranstaltungen in englischer sprache stattfinden&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] worauf ist Marein Knoller in ihrem Anschreiben eingegangen.&lt;/li&gt;
&lt;li&gt;[ ] Was Sie erzählen, sollte im Zusammenhang mit der Stelle stehen.&lt;/li&gt;
&lt;li&gt;[ ] ich brauche die herausforderung&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-08-15&quot; tabindex=&quot;-1&quot;&gt;2023-08-15&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[ ] übersichtlicher&lt;/li&gt;
&lt;li&gt;[ ] Nicht nur das Jahr, sondern auch die Monate angeben, z. B. 06/13 oder Juni 13. Achten Sie darauf, dass die Datumsangaben einheitlich sind.&lt;/li&gt;
&lt;li&gt;[ ] Mir Hammer und die Säge machen wir uns and die Arbeit, ohne von Mails oder Anrufen abgelenkt zu werden.&lt;/li&gt;
&lt;li&gt;[ ] Sie hat angerufen ohne das Teamevent buchen zu bekommen.&lt;/li&gt;
&lt;li&gt;[ ] Ich habe lange mit meinem Kollegen gesprochen, ohne dass ich ihn nicht überzeugen.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-08-13&quot; tabindex=&quot;-1&quot;&gt;2023-08-13&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[ ] sonst, diejenigen
&lt;ul&gt;
&lt;li&gt;[ ] sonst stellen besonders diejenigen, die sich im Job aufreiben, irgendwann fest, dass das restliche Leben leidet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] etwas schaffen: to accomplish something&lt;/li&gt;
&lt;li&gt;[x] schaffen: to do&lt;/li&gt;
&lt;li&gt;[x] jedoch: however
&lt;ul&gt;
&lt;li&gt;[x] Die Reise war großartig, jedoch auch anstrengend.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sowohl, als auch
&lt;ul&gt;
&lt;li&gt;[x] Für viele Stellen ist sowohl eine Ausbildung als auch genügend Berufserfahrung wichtig.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] tätigkeit&lt;/li&gt;
&lt;li&gt;[x] vorgesetzte: the boss&lt;/li&gt;
&lt;li&gt;[x] der Umgang: das Firma
&lt;ul&gt;
&lt;li&gt;[x] Vorgesetzte sollten ein angenehmes Arbeitsumfeld schaffen.&lt;/li&gt;
&lt;li&gt;[x] Vorgesetzte sollten weniger Fehler im Umgang mit ihren Mitarbeitern machen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Erwartungen erfüllen
&lt;ul&gt;
&lt;li&gt;[x] Arbeitnehmer solltern sich deshalb öfter fragen, ob die Arbeit ihre Erwartungen erfüllt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] eine große Rolle spielen&lt;/li&gt;
&lt;li&gt;[ ] eine reine Last sein&lt;/li&gt;
&lt;li&gt;[ ] sich im Job aufreiben -- to wear oneself out on the job&lt;/li&gt;
&lt;li&gt;[ ] etwas selbst in der Hand haben&lt;/li&gt;
&lt;li&gt;[ ] das Vergnügen : the pleasure&lt;/li&gt;
&lt;li&gt;[x] verlust von ansehen, mangelden
&lt;ul&gt;
&lt;li&gt;[x] Wer arbeitslos ist, hat besonders mit dem Verlust von Ansehen und sozialen Kontakten und der mangelnden strukturierung des tages zu kämpfen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] lockt
&lt;ul&gt;
&lt;li&gt;[x] Dabei lockt auch das erwartete gute Gehalt.&lt;/li&gt;
&lt;li&gt;[x] Laut Ali lockt ein schnelles Auto die Frauen an.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] angemessen
&lt;ul&gt;
&lt;li&gt;[x] Das Gehalt ist also gar nicht so entscheidend, sollte aber der Leistung angemessen sein.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Stattdessen, unterstützt
&lt;ul&gt;
&lt;li&gt;[x] Stattdessen sollten Mitarbeiter fachlich unterstützt und Konflikte schnell gelöst werden.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] beschäftigen sich, anspruchsvollen
&lt;ul&gt;
&lt;li&gt;[x] Die meisten Menschen beschäftigen sich gern mit anspruchsvollen Aufgaben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] zufrieden, vernünftigen
&lt;ul&gt;
&lt;li&gt;[x] Besonders zufrieden sind Menschen, die ihren beruf aus vernünftigen gründen wie sicherheit wählen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ein schnelles Auto zieht Frauen an&lt;/p&gt;
&lt;h1 id=&quot;2023-08-08&quot; tabindex=&quot;-1&quot;&gt;2023-08-08&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[x] die Betonung: stress, emphasis
&lt;ul&gt;
&lt;li&gt;[x] Spanisch hat eine freie &lt;strong&gt;Betonung&lt;/strong&gt; der Wörter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ständig -- immer, konstant, allzeit
&lt;ul&gt;
&lt;li&gt;[x] Ella und David haben sich ständig gestritten.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] erfüllen
&lt;ul&gt;
&lt;li&gt;[x] Ich erfülle deinen Wunsch.&lt;/li&gt;
&lt;li&gt;[ ] Ich erfülle die Rolle eines Lehrers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ertragen: (aushalten)
&lt;ul&gt;
&lt;li&gt;[x] Es gibt manchmal so viel Schönheit auf der Welt, dass ich sie fast nicht ertragen kann.&lt;/li&gt;
&lt;li&gt;[x] Wieviel kann ich noch ertragen?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] leiden
&lt;ul&gt;
&lt;li&gt;[x] Deine Gesundheit wird darunter leiden.&lt;/li&gt;
&lt;li&gt;[x] Dafür muss ich heute leiden und leiden.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] geht (es) um
&lt;ul&gt;
&lt;li&gt;[x] Wie gehen sie mit Kritik um?&lt;/li&gt;
&lt;li&gt;[x] In diesem Text geht es um Streit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Es reiz mich. Das gefällt mir.&lt;/li&gt;
&lt;li&gt;[x] leihen: 借
&lt;ul&gt;
&lt;li&gt;[x] Ich habe ihm Geld geliehen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] mittlerweile: by this time
&lt;ul&gt;
&lt;li&gt;[x] Sie versteht sich mittlerweile wieder gut mit ihrem Exfreund und manchmal hilft er ihr bei bürokratischen Problemen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] entschlossen
&lt;ul&gt;
&lt;li&gt;[x] Er war entschlossen, für Gerechtigkeit zu kämpfen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-08-07&quot; tabindex=&quot;-1&quot;&gt;2023-08-07&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;[x]  träume von (Dat.)
&lt;ul&gt;
&lt;li&gt;[x] Ben träumte schon lange von einem längeren Auslandaufenthalt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] bewarb sich bei (Dat.), bewarb sich um (Akk.)
&lt;ul&gt;
&lt;li&gt;[x] Er bewarb sich bei einer italienischen Firma.&lt;/li&gt;
&lt;li&gt;[ ] Er bewarb sich um die Stelle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] warten auf (Akk.)
&lt;ul&gt;
&lt;li&gt;[x] Ich warte ungeduldig auf eine Antwort.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] eingeladen zu (Dat)
&lt;ul&gt;
&lt;li&gt;[x] Ich habe eine Freundin zum Kaffee eingeladen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] verabreden mit (Dat)
&lt;ul&gt;
&lt;li&gt;[ ] Am Wochenende verabreden ich mich oft mit meinen Kollegen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] teilnehmen an (Dat)
&lt;ul&gt;
&lt;li&gt;[x] Wenn ich mein Deutsch verbessern, kann ich besser an Besprechungen aktiv teilnehmen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sich gewohnen an (Akk.)
&lt;ul&gt;
&lt;li&gt;[x] Ich habe mich schon gut an mein neues Leben in Berlin gewöhnt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] verletzt:
&lt;ul&gt;
&lt;li&gt;[x] Streit ist also ganz normal, solange er niemanden verletzt und eine Lösung bringt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] beachten
&lt;ul&gt;
&lt;li&gt;[x] Ich gebe Tipps, was man beachten kann, um der Konfliktlösung näher zu kommen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Keine guten Aussichten auf Erfolg hat ein Streit, der mit einem Vorwurf beginnt.
&lt;ul&gt;
&lt;li&gt;[ ] &amp;quot;Keine guten Aussichten auf Erfolg&amp;quot; - &amp;quot;No good prospect of success has an argument, ...&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Die dreckige Küche hat Ihren Streit ausgelöst?
&lt;ul&gt;
&lt;li&gt;[ ] The dirty kitchen provoked your argument?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Erweitern Sie Ihre Kritik nicht auf andere Punkte, die sie eventuell auch noch stören wie Erziehungsfragen, Geld oder die Erledigung von Arbeiten.
&lt;ul&gt;
&lt;li&gt;[ ] Extend not your criticism to other issues, that may also possibly be disturbing them, like parenting issues, money, or carrying out their work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Das erzeugt nur unnötige Spannung.
&lt;ul&gt;
&lt;li&gt;[x] creates only unnecessary tension.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Ich bin unter Druck steht.
&lt;ul&gt;
&lt;li&gt;[x] Leute, die unter Druck stehen, denken nicht schneller.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] verschieben
&lt;ul&gt;
&lt;li&gt;[x] Ich möchte nicht unseren Termin nicht verschieben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Sie wünschen sich sicherlich ähnlich viel Respekt für Ihre Themen.&lt;/li&gt;
&lt;li&gt;[ ] der Vorwurf&lt;/li&gt;
&lt;li&gt;[x] die Botschaften
&lt;ul&gt;
&lt;li&gt;[x] Versuchen Sie es lieber mit Botschaften über Sie selbst.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] einleiten
- [ ] &amp;quot;Ich möchte gern...&amp;quot; leitet viel eher eine konstruktiv Diskussion ein.&lt;/li&gt;
&lt;li&gt;[ ] Eine gemeinsame Lösung, mit der alle zufrieden sind, lässt sich nicht immer erreichen.&lt;/li&gt;
&lt;li&gt;[ ] Sie ist dann aber die Basis für die Verhandlung von einem Kompromiss in einem anderen Bereich.&lt;/li&gt;
&lt;li&gt;[ ] Wurden Sie zu laut, zu hitzig, zu böse und es tut Ihnen jetzt leid?&lt;/li&gt;
&lt;li&gt;[ ] zwar: indeed
&lt;ul&gt;
&lt;li&gt;[ ] Das sollte Ihnen im Beruf zwar am besten erst gar nicht passieren, wenn die falschen Worte aber erst einmal raus sind, ist hier eine Entschuldigung umso nötiger. (That should not happen in the first place, but once the wrong words are out there, an apology is even more important.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] (ab und zu): from time to time
&lt;ul&gt;
&lt;li&gt;[x] Bei der Verteilung der Arbeit im Beruf muss man ab und zu auch mal eine weniger gerechte Aufgabenteilung hinnehmen. (When it comes to the distribution of work at your job, from time to time one has to accept a less fair distribution of tasks.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Nutzen Sie die Chance für einen gemeinsamen Austausch, bei dem Sie kleinere Unstimmigkeiten entspannt ansprechen können.
&lt;ul&gt;
&lt;li&gt;[ ] Take the chance for a mutual exchange, where you can address minor disagreements in a relaxed manner.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sich unterhalten: to have a conversation
&lt;ul&gt;
&lt;li&gt;[x] Können wir uns kurz mal unterhalten?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Brettspiel
&lt;ul&gt;
&lt;li&gt;[x] Das bekannteste Brettspiel ist Schach.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] anwenden -- benutzen&lt;/li&gt;
&lt;li&gt;[ ] Es ist schön, dass ihr alle da seid!&lt;/li&gt;
&lt;li&gt;[ ] die Bezeichnung -- die Name&lt;/li&gt;
&lt;li&gt;[ ] verwunderlich -- wunderbar&lt;/li&gt;
&lt;li&gt;[ ] erscheinung -- Das Regen ist eine Erscheinung vom Himmel, dass ich zu Hause bleiben soll, um Deutsch zu lernen, anstatt Frisbee zu spielen.&lt;/li&gt;
&lt;li&gt;[ ] erscheinen&lt;/li&gt;
&lt;li&gt;[ ] nichtssagend -- unbedeutend, banal, geistlos&lt;/li&gt;
&lt;li&gt;[ ] entfällt -- not applicable, no longer required&lt;/li&gt;
&lt;li&gt;[x] austeilen, einstecken
&lt;ul&gt;
&lt;li&gt;[x] Wer teit Kritik aus, wer steckt Kritk ein?&lt;/li&gt;
&lt;li&gt;[ ] der Bürgermeister teilt Kritik sein Mitarbeiteren aus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] gehören
&lt;ul&gt;
&lt;li&gt;[x] Kritik Und Respekt gehören zusammen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] verschulden
&lt;ul&gt;
&lt;li&gt;[ ] etw. verschulden: to be responsible for something&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] wütenden -- sauer
&lt;ul&gt;
&lt;li&gt;[ ] Bei sehr wütenden Kunden kann auch mein Chef nicht mehr helfen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] erwarten
&lt;ul&gt;
&lt;li&gt;[x] Die Leute erwarten, dass ich in meinem Programm humorvoll bin.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] das Mitleid
&lt;ul&gt;
&lt;li&gt;[ ] ich habe Mitleid mit dem einen oder anderen Politiker.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] verursachen --- to cause, to raise, to bring about
&lt;ul&gt;
&lt;li&gt;[ ] Angst verursachen -- to cause anxiety&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Unstimmigkeiten -- discrepancies, disagreements
&lt;ul&gt;
&lt;li&gt;[x] Wir spreche bei kleinere Unstimmigkeiten an.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] Mitleid:
&lt;ul&gt;
&lt;li&gt;[x] Manchmal habe ich Mitleid mit dem einen oder anderen Politiker.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2023-07-30&quot; tabindex=&quot;-1&quot;&gt;2023-07-30&lt;/h1&gt;
&lt;p&gt;Der Helfte is Geschaft.&lt;/p&gt;
&lt;p&gt;ein Kurs nach dem anderen
eins nach dem anderen&lt;/p&gt;
&lt;p&gt;kann der Geist so schnell expandieren?&lt;/p&gt;
&lt;p&gt;im frühen September&lt;/p&gt;
&lt;p&gt;verdauen&lt;/p&gt;
&lt;p&gt;die komplette Zeitverschwendung&lt;/p&gt;
&lt;p&gt;Wenn du bald nach London gehst, dann hast du jetzt nur noch die Chance.
nur noch jetzt&lt;/p&gt;
&lt;p&gt;Frontalunterricht&lt;/p&gt;
&lt;p&gt;erhalten&lt;/p&gt;
&lt;p&gt;der austauch&lt;/p&gt;
&lt;p&gt;die sokratische Methode&lt;/p&gt;
&lt;p&gt;wenn die Fenster geöffnet sind -- gegenteil
wenn die Fenster geöffnet worden sind -- vergangenheit
wenn die Fenster geöffnet wurden -- vergangheit&lt;/p&gt;
&lt;p&gt;der Lärm&lt;/p&gt;
&lt;p&gt;der Lag -- die Verzögerung -- (latency)&lt;/p&gt;
&lt;p&gt;der Schwachpunkt&lt;/p&gt;
&lt;p&gt;Fetzen n
achmachen&lt;/p&gt;
&lt;p&gt;der Rückgriff&lt;/p&gt;
&lt;p&gt;Plastizität&lt;/p&gt;
&lt;p&gt;Neuroplastizität&lt;/p&gt;
&lt;p&gt;ganz gut Klapp&lt;/p&gt;
&lt;p&gt;irgendwie gleich anwenden -- to appl&lt;/p&gt;
&lt;p&gt;ganz gut geklappt&lt;/p&gt;
&lt;p&gt;bin und habe als Softwareingenieur gearbeitet&lt;/p&gt;
&lt;p&gt;Konsens zu erreichen&lt;/p&gt;
&lt;p&gt;übereinstimmen&lt;/p&gt;
&lt;p&gt;stimmen uber etwas ein. --&amp;gt; Ich stimme mit dir überein.&lt;/p&gt;
&lt;h1 id=&quot;links-and-wordlists&quot; tabindex=&quot;-1&quot;&gt;links and wordlists&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://wisc.pb.unizin.org/readinggerman/chapter/als-wenn-wann/&quot;&gt;2. Als, Wenn, and Wann in Expressing Time&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.dartmouth.edu/~deutsch/Grammatik/Passive/Passiv.html&quot;&gt;Das Passiv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://germanforenglishspeakers.com/verbs/the-passive-voice/&quot;&gt;German for English Speakers: The Passive Voice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.dartmouth.edu/~deutsch/Grammatik/WordOrder/Infinitives.html&quot;&gt;Infinitive Clauses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Goethe-Zertifikat_A1_Wortliste.pdf&quot;&gt;A1_Wortliste.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Goethe-Zertifikat_A2_Wortliste.pdf&quot;&gt;A2_Wortliste.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Goethe-Zertifikat_B1_Wortliste.pdf&quot;&gt;B1_Wortliste.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;thingies&quot; tabindex=&quot;-1&quot;&gt;Thingies&lt;/h1&gt;
&lt;h2 id=&quot;%22it-depends-on-...-%22-%3D%3D-%22es-h%C3%A4ngt-davon-ab..%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;it depends on ... &amp;quot; == &amp;quot;es hängt davon ab..&amp;quot;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Was ist deine Lieblingsessen? Es hängt davon ab, was heute gefällt mir.&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-um-...-zu-construction&quot; tabindex=&quot;-1&quot;&gt;the um ... zu construction&lt;/h2&gt;
&lt;p&gt;It means &amp;quot;in order to&amp;quot;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Ich bin in Berlin angekommen, um Deutsch zu lernen.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;I arrived in Berlin in order to learn German.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;either-or-in-german-is-%22entweder...-oder-%22&quot; tabindex=&quot;-1&quot;&gt;either or in German is &amp;quot;entweder... oder &amp;quot;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Wir können &lt;strong&gt;entweder&lt;/strong&gt; ins Kino &lt;strong&gt;oder&lt;/strong&gt; ins Restaurant gehen.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;We can either go to the cinema or to the restaurant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-%22zu-%2B-infinitiv%22-construction&quot; tabindex=&quot;-1&quot;&gt;the &amp;quot;zu + infinitiv&amp;quot; construction&lt;/h2&gt;
&lt;p&gt;The zu + infinitiv contruction (or just the &amp;quot;infinitive construction&amp;quot;) is used to elide the subject in a sentence that normally contains one. It introduces a subordinate clause. We change the verb into the infinitive form and put &amp;quot;zu&amp;quot; in front of it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Ich fand es schwer. Ich klettere auf den Berg.&lt;/em&gt; becomes &lt;em&gt;Ich fand es schwer, auf den Berg zu klettern.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;I found it difficult to climb the mountain.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Er hat vergessen, seiner Freundin etwas zum Geburtstag zu kaufen.&lt;/em&gt; I forgot to buy my girlfriend something for her birthday&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;da-words%2C-wo-words-(dazu%2C-darin%2C-danach%2C-daruber%2C-wohin%2C-woher%2C-woraus%2C-woruber...)&quot; tabindex=&quot;-1&quot;&gt;da-words, wo-words (dazu, darin, danach, daruber, wohin, woher, woraus, woruber...)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Ich habe einen Schlüssel, ich spiele damit.&lt;/em&gt; I have a key, I play with it.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Wovon hast du getraümt?&lt;/em&gt; What have you dreamed of?&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Es gab einen Berg. Ich habe davon getraümt.&lt;/em&gt; There was a mountain. I dreamt of it.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sie ist besser in Feedback geben&lt;/em&gt; --&amp;gt; &amp;quot;Sie ist besser &lt;em&gt;darin&lt;/em&gt;, Feedback zu geben&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note that da-words are only for nonliving things. You would say &amp;quot;Es gab einen Mann. Ich habe von ihm getraümt.&amp;quot; instead of &lt;em&gt;davon&lt;/em&gt; here.&lt;/p&gt;
&lt;h2 id=&quot;indirect-questions-(indirekte-frages%C3%A4tze)&quot; tabindex=&quot;-1&quot;&gt;Indirect questions (Indirekte Fragesätze)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Indirect questions&lt;/strong&gt; are questions that are included within the structure of another sentence. Because indirect questions are dependent clauses (&lt;em&gt;Nebensätze&lt;/em&gt; in German), we have to change the position of the verb. Indirect questions follow certain introductory phrases, see the examples below. They often end with a full stop and not a question mark. &lt;a href=&quot;https://deutsch.lingolia.com/en/grammar/sentence-structure/dependent-clauses/indirect-questions&quot;&gt;source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For example, &amp;quot;I do not know what he is doing today.&amp;quot; &lt;em&gt;Ich weiß nicht, was er heute mache.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Here are more examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Wie lange hast du gestern mit deiner Freundin telefoniert?&lt;/em&gt;
&lt;em&gt;Ich kann mich nicht erinnern, wie lange ich gestern mit meiner Freundin telefoniert &lt;strong&gt;habe.&lt;/strong&gt;&lt;/em&gt; (Note the position of the auxiliary verb!)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there is no question word, we use &amp;quot;ob&amp;quot; to introduce the indirect question.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Gehst du oft nach Berlin?&lt;/em&gt; Do you come often to Berlin?
&lt;em&gt;Er fragt mich, &lt;strong&gt;ob&lt;/strong&gt; ich oft nach Berlin gehe.&lt;/em&gt; He asked me, whether I come often to Berlin.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Kommt sie morgen?&lt;/em&gt; Is she coming tomorrow?
&lt;em&gt;Er fragt, ob sie morgen kommt.&lt;/em&gt; He asked whether she is coming tomorrow.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;relativsatz&quot; tabindex=&quot;-1&quot;&gt;Relativsatz&lt;/h2&gt;
&lt;h1 id=&quot;unregelmasige-verben&quot; tabindex=&quot;-1&quot;&gt;Unregelmasige Verben&lt;/h1&gt;
&lt;h1 id=&quot;conjunctions&quot; tabindex=&quot;-1&quot;&gt;Conjunctions&lt;/h1&gt;
&lt;h2 id=&quot;weil&quot; tabindex=&quot;-1&quot;&gt;weil&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Weil ich heute früh aufgestanden bin, bin ich jetzt sehr müde.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ich bin sehr müde, weil ich heute früh aufgestanden bin.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;obwohl&quot; tabindex=&quot;-1&quot;&gt;obwohl&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Obwohl ich total müde war, habe ich trotzdem das Brandenburger Tor besucht.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Trotzdem habe ich das Brandenburger Tor besucht, obwohl ich total müde war.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;pr%C3%A4positionen&quot; tabindex=&quot;-1&quot;&gt;Präpositionen&lt;/h1&gt;
&lt;h2 id=&quot;akkusativpr%C3%A4positionen&quot; tabindex=&quot;-1&quot;&gt;Akkusativpräpositionen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;betreffend&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;bis&lt;/li&gt;
&lt;li&gt;durch&lt;/li&gt;
&lt;li&gt;für&lt;/li&gt;
&lt;li&gt;entlang&lt;/li&gt;
&lt;li&gt;gegen&lt;/li&gt;
&lt;li&gt;ohne&lt;/li&gt;
&lt;li&gt;um&lt;/li&gt;
&lt;li&gt;wider (wider meinen Willen -- against my will)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dativpr%C3%A4positionen&quot; tabindex=&quot;-1&quot;&gt;Dativpräpositionen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;ab&lt;/li&gt;
&lt;li&gt;aus&lt;/li&gt;
&lt;li&gt;außer&lt;/li&gt;
&lt;li&gt;bei&lt;/li&gt;
&lt;li&gt;&lt;em&gt;entgegen&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;entsprechend&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;gegenüber&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;gemäß&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;laut&lt;/li&gt;
&lt;li&gt;mit&lt;/li&gt;
&lt;li&gt;nach&lt;/li&gt;
&lt;li&gt;seit&lt;/li&gt;
&lt;li&gt;von&lt;/li&gt;
&lt;li&gt;zu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;welcherpr%C3%A4positionen&quot; tabindex=&quot;-1&quot;&gt;Welcherpräpositionen&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;an&lt;/li&gt;
&lt;li&gt;auf&lt;/li&gt;
&lt;li&gt;auf&lt;/li&gt;
&lt;li&gt;hinter&lt;/li&gt;
&lt;li&gt;in&lt;/li&gt;
&lt;li&gt;neben&lt;/li&gt;
&lt;li&gt;über&lt;/li&gt;
&lt;li&gt;unter&lt;/li&gt;
&lt;li&gt;vor&lt;/li&gt;
&lt;li&gt;zwischen&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;worte&quot; tabindex=&quot;-1&quot;&gt;Worte&lt;/h1&gt;
&lt;h2 id=&quot;adjektiv&quot; tabindex=&quot;-1&quot;&gt;Adjektiv&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;zurzeit&lt;/li&gt;
&lt;li&gt;angstlich&lt;/li&gt;
&lt;li&gt;nervig&lt;/li&gt;
&lt;li&gt;brav&lt;/li&gt;
&lt;li&gt;zufrieden&lt;/li&gt;
&lt;li&gt;laut&lt;/li&gt;
&lt;li&gt;irritiert&lt;/li&gt;
&lt;li&gt;glücklich&lt;/li&gt;
&lt;li&gt;traruig&lt;/li&gt;
&lt;li&gt;sicher&lt;/li&gt;
&lt;li&gt;irritiert&lt;/li&gt;
&lt;li&gt;ruhiger&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;adverbs&quot; tabindex=&quot;-1&quot;&gt;Adverbs&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;besonders&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;other-stuff&quot; tabindex=&quot;-1&quot;&gt;other stuff&lt;/h1&gt;
&lt;p&gt;Was für ... (Akk) -- because&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Was für einen Beruf hast du?&lt;/li&gt;
&lt;li&gt;Was für ein Instrument kannst du spielen?&lt;/li&gt;
&lt;li&gt;Was für Musik magst du?&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;random-words&quot; tabindex=&quot;-1&quot;&gt;random words&lt;/h1&gt;
&lt;h2 id=&quot;2023-06-26&quot; tabindex=&quot;-1&quot;&gt;2023-06-26&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;spüren: to feel&lt;/li&gt;
&lt;li&gt;merken: to notice&lt;/li&gt;
&lt;li&gt;sofort:&lt;/li&gt;
&lt;li&gt;gewesen: past tense of sein&lt;/li&gt;
&lt;li&gt;die Ankunft: arrival&lt;/li&gt;
&lt;li&gt;ziehen: to pull&lt;/li&gt;
&lt;li&gt;schreien: to shout&lt;/li&gt;
&lt;li&gt;tief: deep&lt;/li&gt;
&lt;li&gt;einatmen (atmen ein): to take a breath&lt;/li&gt;
&lt;li&gt;drinnen: inside&lt;/li&gt;
&lt;li&gt;drausen: outside&lt;/li&gt;
&lt;li&gt;das Shicksal: fate, destiny.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Das Schicksal mischt die Karten und wir spielen.&lt;/em&gt; Fate shuffles the cards and we play.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;das Benzin: petrol.
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Ich habe kein Benzin mehr im Tank.&lt;/em&gt; I have no more petrol in my tank.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;bestimmen: to decide&lt;/li&gt;
&lt;li&gt;nutzen, benutzen: to use.
&lt;ul&gt;
&lt;li&gt;Take note that nutzen is for abstract things (talent, opportunities) and benutzen is for concrete things (word, car, phone...)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Ich nutze jede gute Gelegenheit.&lt;/em&gt; I use every good opportunity.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Kann ich deine Gabel benutzen?&lt;/em&gt; Can I use your fork?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;aufregen: excited.&lt;/li&gt;
&lt;li&gt;entspannen: relaxed&lt;/li&gt;
&lt;li&gt;zufrieden: pleased&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2022-04-17&quot; tabindex=&quot;-1&quot;&gt;2022-04-17&lt;/h2&gt;
&lt;p&gt;Ich denke dass die Bank auf Bild 3 mir besser gefallen.&lt;/p&gt;
&lt;p&gt;In einige Staat man kann aus dem Brunnen/vom Brunnen trinken.&lt;/p&gt;
&lt;p&gt;Homeless person -- Obdachlose&lt;/p&gt;
&lt;p&gt;der Obdachlose -n
die Obdachlose -n&lt;/p&gt;
&lt;p&gt;Sind Sie Obdachlos?&lt;/p&gt;
&lt;p&gt;Ein Obdachloser kann auf der Parkbank schlafen.&lt;/p&gt;
&lt;p&gt;Ich brauche dieses Wort für wann ich nach Berlin reisen.&lt;/p&gt;
&lt;p&gt;Das war ein scherzen
Ich macht Spaß&lt;/p&gt;
&lt;p&gt;Hotel söllen jeden Tag geöffnet.&lt;/p&gt;
&lt;p&gt;Was gibt es in der Umgebung__&lt;/p&gt;
&lt;p&gt;Wie sieht es aus: how does it look like there&lt;/p&gt;
&lt;p&gt;Hochhaus
Man kann bekommt alles.&lt;/p&gt;
&lt;p&gt;vier Etagen&lt;/p&gt;
&lt;p&gt;Abteilung&lt;/p&gt;
&lt;p&gt;die Umgebung
in der Umgebung: in the surrounding area
in der Nähe&lt;/p&gt;
&lt;p&gt;Meine favourite&lt;/p&gt;
&lt;p&gt;In der Umgebung gibt es viele Abfallkorben.&lt;/p&gt;
&lt;p&gt;Es gibt viele leute, die nicht zu ende essen.&lt;/p&gt;
&lt;p&gt;Es gibt Leute, die nicht schlafen. relativ satz, nebensatz&lt;/p&gt;
&lt;p&gt;Ich denke dass wir eng wohnen. ---&lt;/p&gt;
&lt;p&gt;anschluss: connect
Parkanschluss&lt;/p&gt;
&lt;p&gt;hätte gern
Was hätten Sie gern&lt;/p&gt;
&lt;p&gt;benutzen: to use&lt;/p&gt;
&lt;p&gt;Der Tisch auf Bild 4 gefallt mir am besten.&lt;/p&gt;
&lt;p&gt;Die Person wirft den Abfall nicht weg.
(weg wirfen -- trennbares Verben)&lt;/p&gt;
&lt;p&gt;Was denken Sie uber die Person von Schreibtisch 3.&lt;/p&gt;
&lt;p&gt;Unter uns ist das Restaurant ABER unten ist das restaurant&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hallo Christine,&lt;/p&gt;
&lt;p&gt;Hier sind meine Antworten für (zu?) deinen Fragen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Was für ein ‚Schreibtischtyp‘ sind Sie? Wohin räumen Sie Ihre Gegenstände? Wie richten Sie Ihre Wohnung (oder Traumwohnung) ein?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Mein Schreibtisch ist nur ein Platz für meine Gegenstände; ich glaube meine Schreibtischtyp ist &#39;a mess&#39;. Normalerweise räume ich meine Gegenstände von auf dem Tisch zu auf dem Boden, und auf dem Boden zu auf dem Tisch! Wenn ich Zeit habe, ich wurde meine Kleidung an den Schrank hangen... aber das ist nicht oft.&lt;/p&gt;
&lt;p&gt;Ich hatte gedacht, dass meine Wohnung sehr Minimalist wurde sein. &amp;quot;Ich will in meine Wohnung kein Tisch, keine Stühle--gar nicht&amp;quot;, ich hatte gedacht.&lt;/p&gt;
&lt;p&gt;Aber wenn ich meine Wohnung hatte eingezogen, ich realisiert dass das nicht praktisch war. Als meine Freunden mich besucht, es gab keinen Platz zum Sitzen, und wir kann nicht Mahjong spielen. Jetzt, ich weiß besser. Man muss in ihren Gedanken flexibel sein.&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Was finden Sie beim Einkaufen wichtig? Lieblingskaufzentrum? Welche Sachen? Einkaufstyp? Wie oft? Mit wem? Warum?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ich liebe kaufe Lebensmittel ein. Ich kann viele Stunden in diese Geschäfte bleiben. Ich gehe fast jeden Tag zum Lebensmittelgeschäft, um meine Mittagessen zu einkaufen--und ich kaufe immer zu viele Essen ein!&lt;/p&gt;
&lt;p&gt;Meine Lieblingsaktivität wenn ich nach andere Land reise ist Lebensmittelgeschäft besuchen. Diese Frage sind sehr interessant für mich: Was esst die Leute in diese Land? Wie kauft die Leute ein--schnell oder langsam? Wer kauft was wann?&lt;/p&gt;
&lt;p&gt;Kleidung gefällt mir nicht. Wenn ich mit eine schöne Frau für Kleidung einkaufen, es ist vielleicht OK!&lt;/p&gt;
&lt;p&gt;Es gibt (present tense) means &#39;there is&#39; or &#39;there are&#39;. It is almost always used in the imperfect tense rather than the perfect tense.&lt;/p&gt;
&lt;p&gt;The imperfect form of es gibt is es gab. It means &#39;there was&#39; or &#39;there were&#39;.&lt;/p&gt;
&lt;p&gt;Als meine Mutter jünger war, gab es einen Freibad im Dorf. – When my mother was younger, there was an outdoor pool in the village.
Es gab gestern Abend viele Leute auf der Party. – There were lots of people at the party last night.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;2023-07-04&quot; tabindex=&quot;-1&quot;&gt;2023-07-04&lt;/h1&gt;
&lt;p&gt;(B1.2 Hausaufgaben in Berlin)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Übers Streiten&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Es gibt zwei Typen von Streit: ein Streit über die Fakten, und ein Streit über Gefühlen. Man verwechselt oft die zwei, und dann kommen Konflikte.&lt;/p&gt;
&lt;p&gt;Zum Beispiel, wenn man sagt &amp;quot;Spar Geld!&amp;quot;, vielleich bedeutet das &amp;quot;Wir müssen für ein Haus sparen&amp;quot;, oder &amp;quot;Ich fühle mich nervos dass wir zu wenig Geld haben&amp;quot;. Wenn man sagt &amp;quot;Warum kommst du sehr spät zuruck?&amp;quot; vielleicht bedeutet das &amp;quot;Ich muss für dich die Tur öffen&amp;quot;, oder &amp;quot;Ich habe dich vermisst&amp;quot;.&lt;/p&gt;
&lt;p&gt;Für die ersten Type von Streit sollt man Logik benutzen: Wie viel Geld sollen wir sparen? Wie Uhr möchtest du mich zuruckkommen? Aber das schadet dem zweiten Type von Streit. Für die zweiten Type von Streit musst man über Gefühle sprechen: Warum fühlst du dich nervos? Ich verstehe dass du mich vermisst, und ich werde mehr Zeit mit dir verbringen.&lt;/p&gt;
&lt;p&gt;Die zwei Geschlechte mögen unterschiedliche Methoden. Männer wollen schneller Lösung finden; Frauen wollen erst verstehen. Das wichtigste Ding ist zu wissen, welchen Streit man hat.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;2023-07-06&quot; tabindex=&quot;-1&quot;&gt;2023-07-06&lt;/h1&gt;
&lt;p&gt;(B1.2 Hausaufgaben in Berlin)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Morgenroutine&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gesund Leben&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Annabelle: Gesundheit ist natürlich wichtig. Aber wie soll ich gesund leben, wenn ich immer so viel Stress habe? Ich arbeite den ganzen Tag und danach muss ich noch 1.000 Dinge erledigen. Für Bewegung bleibt da wenig Zeit. Und mittags esse ich meistens in der Kantine.
Schreiben Sie nun Ihre Meinung zum Thema (ca. 80 Wörter)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ich kann natürlich gut Annabelle verstehen. Als ich in Singapur war, habe ich zwei mal pro Woche Frisbee gespielt, und ich habe jede Wochentag ein Workout im Fitnessstudio gemacht. Aber jetzt habe ich in Berlin keine Zeit. Ich muss arbeiten, ich habe Intensivkurs, und ich habe viele neue Freunde, mit denen zu Zeit verbringen. Ich glaube das wichtigste Ding ist, das unsere Altagsleben Gesund sind. Zum Beispiel, man sollst die Treppen benutzen wenn man zum dem Büro geht. Oder man kann stehen während er arbeitet. Ich bewege mich oft während ich denke. Ich glaube, dass man kann auch sich gesund in der Kantine ernähren, wenn man gesündere Auswahlen nehmen.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;2023-07-07&quot; tabindex=&quot;-1&quot;&gt;2023-07-07&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Sich entschuldigen. Schreiben Sie eine E-Mail.&lt;/p&gt;
&lt;p&gt;Sie besuchen zwei Mal pro Woche einen Yoga-Kurs. Die Kursleiterin, Frau Moser, hat für morgen Abend ein gemeinsames Abendessen für alle Teilnehmer und Teilnehmerinnen organisiert. Sie können zu dem Termin aber nicht kommen.&lt;/p&gt;
&lt;p&gt;Schreiben Sie an Frau Moser. Entschuldigen Sie sich höflich und berichten Sie, warum Sie nicht kommen kömmen. Schreiben Sie eine E-Mail (ca. 40 Wörter). Vergessen Sie nicht die Anrede und den Gruß am Schluss.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Liebe Frau Moser,&lt;/p&gt;
&lt;p&gt;leide kann ich morgen nicht zu dem Abendessen kommen. Ich habe eine Beschwerde und ich fühle mich ein bissen krank. Mein Nacken tut weh und ich habe Bauchschmerzen. Ich glaube dass, ich mich nur zu erholen brauche. Hoffentlich werdet ihr viel Spaß ohne mich haben!&lt;/p&gt;
&lt;p&gt;Mit freundlichen Grüßen,
Zhenghong&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&quot;2023-07-09&quot; tabindex=&quot;-1&quot;&gt;2023-07-09&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://old.reddit.com/r/German/comments/4mpw2y/opinions_on_the_goethe_institut/d3xqsg1/&quot;&gt;possibly useful insight:&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Maybe I&#39;ll make a separate thread for this one day. Here was my regimen.&lt;/p&gt;
&lt;p&gt;1 do everything you can to surround yourself with people who speak better than you do and communicate with them at every possible instance. i was lucky enough to see a girl who was C1 while i was just starting out, but the goal is to chisel away at the 1) psychological barriers preventing you from communicating with others out of the fear of making grammatical/vocab mistakes 2) reliance on your mother tongue. both of these things are very difficult to overcome, especially number 2 for english speakers as there will almost always be outlets to use english instead of german. don&#39;t take them, and conversely don&#39;t allow german speakers to take them either.&lt;/p&gt;
&lt;p&gt;2 VOCAB. the building blocks of language. getting vocab down is a three pronged attack based on the principle of less is more/more is less.&lt;/p&gt;
&lt;p&gt;2a. Have a little diary of new words, spreadsheets are okay too. take down new words that you see and write their meanings down with their contexts (optional). this information will be nice to have in some form to look back up at some point.&lt;/p&gt;
&lt;p&gt;2b. take these new words and plug them into &lt;a href=&quot;http://ankisrs.net/&quot;&gt;Anki&lt;/a&gt;. Set the Anki settings to either cloze or whatever type you use to actually type the words in. just saying them out loud won&#39;t cut it. my settings were 5 new words per day, 20 review words.&lt;/p&gt;
&lt;p&gt;without getting too wonky, 5 new words a day &lt;em&gt;plenty&lt;/em&gt; for mortal men. even at the fluency level, where i am taking a shitload of new words in at all times, i still commit myself to 5 a day. anything more than that and you will lose them faster than you can take them in, negating the whole process. have those 5 words a day be your bitch by...&lt;/p&gt;
&lt;p&gt;2c. writing those five words down on flashcards (or whatever) and using them throughout the day. the more mental gymnastics you have to pull to work those words into a conversation, the better. you have to earn those words through rote memorization by way of creative application. words in anki getting thrown at you again and again need to have life breathed into them by real-world usage, otherwise they have no visceral meaning to the speaker and become useless.&lt;/p&gt;
&lt;p&gt;3 have conversations with yourself in the target language. when you read a book, summarize it to yourself later, paragraph by paragraph or page by page if need be (nothing wrong with that!)&lt;/p&gt;
&lt;p&gt;4 write as much as you sustainably can every day. if it&#39;s a paragraph, fine, if it&#39;s a page, perfect.&lt;/p&gt;
&lt;p&gt;5 do not use a cell phone to look up words in class at every single possible fucking juncture. this will ruin your learning experience. this is a massive problem with students in the digital era that extends far past learning another language. when a new word comes across, &lt;strong&gt;ask your teacher for a definition or consult a dictionary&lt;/strong&gt; (english-german dictionaries are perfectly fine). teachers in the GI know that they will use hundreds of foreign words a day and it is their job to explain them to their students. this is also a psychological barrier that will need to be overcome: fear of looking stupid by asking questions. don&#39;t succumb to it! look as dumb as you actually are(!!), because most people are probably at the same level and will be gawking at you in 6 months time when you have surpassed them, all because you weren&#39;t afraid to make mistakes and look dumb!&lt;/p&gt;
&lt;p&gt;6 read ALL THE TIME. books are living examples of how language is used throughout time. it is probably my favorite way of collecting new vocab. the GI has a great library of beginner books: USE THEM!!!!&lt;/p&gt;
&lt;h2 id=&quot;2023-07-10&quot; tabindex=&quot;-1&quot;&gt;2023-07-10&lt;/h2&gt;
&lt;p&gt;Monday morning. A bit tired.&lt;/p&gt;
&lt;p&gt;Came back from German. Bought some books to learn German. I did Hausaufgaben on a typewriter.&lt;/p&gt;
&lt;p&gt;Good meeting with Ben. 2330 -- 0100, after all was said and done. Hopefully I get some answers soon.&lt;/p&gt;
&lt;h2 id=&quot;2023-07-15&quot; tabindex=&quot;-1&quot;&gt;2023-07-15&lt;/h2&gt;
&lt;p&gt;what is the best way to learn a language&lt;/p&gt;
&lt;p&gt;surely it must be: lots of writing practice, lots of speaking practice, lots of hearing practice&lt;/p&gt;
&lt;p&gt;my main bottleneck now is my lack of vocabulary.&lt;/p&gt;
&lt;h2 id=&quot;2023-07-17&quot; tabindex=&quot;-1&quot;&gt;2023-07-17&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Welche Orte in einer Stadt sind wichtig für Sie? Was machen Sie dort?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;quot;Dritter Ort&amp;quot; is für mir wichtig. Ein dritter Ort ist nicht ein konkreter Ort, sondern ein abstrakter Typ von Ort.&lt;/p&gt;
&lt;p&gt;Das Konzept von dem &amp;quot;dritter Ort&amp;quot; wurde von Ray Oldenberg, einer Americanischer Stadtsoziologe, in seinem Buch &amp;quot;The Great Good Place&amp;quot; erklärt. Der erster Ort ist die Wohnung, der zweiter das Büro, und dann kommt der dritter Ort. Ein dritter Ort ist ein Ort, in dem Leute viele Zeit verbringen; ein Ort, in dem man in Öffentlichkeit entspannt; ein Ort, in dem man neue Menschen kennenlernen kann. Dritter Orte sind (fast) kostenlos, neutral, einladend, freundlich, und angenehm.&lt;/p&gt;
&lt;p&gt;Ein paar Beispiele von dritter Orte sind Kneipen, Bibliotheken, Parks, Plätzen, und so weiter. Ein dritter Ort hat für die Gesellschaft eine riesige Bedeutung. Es ist einen Ort für alle Menschen miteinander zu reden. Obwohl jeder Mensch anders ist -- arm oder reich, jung oder alt -- in einem dritter Ort, alle gleichberechtigt sein. Dritte Orte sind deshalb für Zivilgesellschaft, Demokratie, und Zivilcourage wichtig.&lt;/p&gt;
&lt;p&gt;(korrigieren)&lt;/p&gt;
&lt;p&gt;&amp;quot;Dritter Ort&amp;quot; is für mich wichtig. Ein dritter Ort ist kein konkreter Ort, sondern ein abstrakter Typ von Ort.&lt;/p&gt;
&lt;p&gt;Das Konzept von dem &amp;quot;dritter Ort&amp;quot; wurde von Ray Oldenberg, einem Amerikanischen Stadtsoziologen, in seinem Buch &amp;quot;The Great Good Place&amp;quot; erklärt. Der erste Ort ist die Wohnung, der zweite das Büro, und dann kommt der dritte Ort. Ein dritter Ort ist ein Ort, in dem Leute viele Zeit verbringen; ein Ort, wo man in Öffentlichkeit entspannt; ein Ort, in dem man neue Menschen kennenlernen kann. Dritte Orte sind (fast) kostenlos, neutral, einladend, freundlich, und angenehm.&lt;/p&gt;
&lt;p&gt;Ein paar Beispiele von dritten Orten sind Kneipen, Bibliotheken, Parks, Plätzen, und so weiter. Ein dritter Ort hat für die Gesellschaft eine riesige Bedeutung. Es ist einen Ort für alle Menschen, um miteinander abzuschalten. Obwohl jeder Mensch anders ist -- arm oder reich, jung oder alt -- in einem dritten Ort sind alle gleichberechtigt. Dritte Orte sind deshalb für Zivilgesellschaft, Demokratie und Zivilcourage wichtig.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;[x] spießig: square, uncool&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Die Menschen im Munschen sind spießiger als Berliner.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] der Wolkenkratzer: the skyscraper.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Der Wolkenkratzer ist insgesamt 1,000 meter hoch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] das Nachtleben: the nightlife&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Berlin ist sehr bekannt für das Nachleben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[ ] erholen: to relax&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Wohngebäude: the residential building&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Plattenbau: a type of building that was built in the DDR&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Vorort: the suburb&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] die Sehenswürdigkeit: the point of interest&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eine &lt;strong&gt;Sehenswürdigkeit&lt;/strong&gt; von Binic ist die Kirche Notre-Dame de Bon Voyage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] der Obdachlose: the homeless person&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In den Jahren nach dem Zweiten Weltkrieg gab es in München viele &lt;strong&gt;obdachlose&lt;/strong&gt; Männer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Kneipe: the bar&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] der Lärm: loudness&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lärm&lt;/strong&gt; mindert auch die körperliche und geistige Leistungsfähigkeit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] das Angebot: the offer&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Früher haben verschiedene Banken Kredite für Studenten angeboten.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Aussicht: the view&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das Fenster bietet eine schöne Aussicht.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Fußgänger: the pedestrian&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Fahrzeug: the vehicle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Lage: the location, position&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wir wohnen in einer guten Lage.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Schaufenster: the shop window&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] leise: quiet&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Die leise Stimme des Gewissens kann man auch zum Schweigen bringen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Dach: a roof&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] die Träne: the tear.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Der Mann ist keine Träne wert.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Vermutung: the supposition&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;vermuten: to suppose, to suspect&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Entzundung: the inflammation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;echt: real, genuine&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das Fleicht is echt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] die Geschwindigkeit: the speed&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Die Geschwindigkeit des Lebens in der Stadt ist sehr schnell.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;begreifen: verstehen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] deswegen: deshalb, daher, darum...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nicht wenige Entertainer verfielen &lt;strong&gt;deswegen&lt;/strong&gt; selbst dem Alkohol.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;versorgen: to supply, to provide&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] das Versorgung: the supply of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In der Stadt gibt es bessere medizinische Versorgung.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] der Eindruck: the impression&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Er hat ein Job Interview einen guten Eindruck gemacht.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] die Veranstaltung: the event&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Am Christopher Street Day gibt es viele verschiedene Veranstaltungen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] eindeutig: clear, obvious&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In Berlin kann man jeden Tag neues Essen probieren. Das geht in einem Dorf (village) eindeutig nicht.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] gegenseitig: miteinander&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hier sprechen viel leute noch Dialekt, jeder kennt jeden und wir helfen uns auch gegenseitig.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;anscheinend: it seems to be&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Landmensch? Anschienend bin ich einer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] einsam: allein&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Man stirbt einsam.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] stören: to disturb&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Darf ich dich kurz stören?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x]  überhaupt: absolutely, at all&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das macht überhaupt keinen Sinn.&lt;/li&gt;
&lt;li&gt;Er war überhaupt keine Hilfe.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2023-07-19&quot; tabindex=&quot;-1&quot;&gt;2023-07-19&lt;/h2&gt;
&lt;h3 id=&quot;die-morgendliche-aussicht&quot; tabindex=&quot;-1&quot;&gt;Die Morgendliche Aussicht&lt;/h3&gt;
&lt;p&gt;Sechs Uhr früh morgens. Die Betrunken stolpern nach Haus zurück während die Arbeitslosen aus euer Häuser stolpern, um einen Job zu finden. Auf der Brücke im Friedrichstrasse Bahnhof, wo ein Obdachsloser schlaf, wurde eine Nackige von einem Voyeur über Glasscherben photographiert. Von meinem Fenster sehe ich alle, und ich denke: obwohl wir in die Gesellschaft alle verschieden sind, scheint die Sonne gleich auf uns alle.&lt;/p&gt;
&lt;h3 id=&quot;unser-projekt&quot; tabindex=&quot;-1&quot;&gt;Unser Projekt&lt;/h3&gt;
&lt;p&gt;Zuerst möchten wir ein Kultur-Treffpunkt am Erdgeschoss bauen, und daruber möchten wir Buros zu Wohnungen umbauen. Da wir diese zwei Projekte kombiniert haben, kosten die Projekte natürlich weniger. Wir sehen für den Umbau und den Treffpunkt insgesamt 10 Millionen Euros ausgeben vor. Die zwei alten Schulen in der Nähe von die Wohnungen werden renoviert werden.&lt;/p&gt;
&lt;p&gt;Zweitens möchten wir ein Fahrradweg und Fahrrad-Taxi-Dienstleitung statt der neuen Strassenbahn-Linie bauen. Freiwillige Jugendliche werden alte Leute und Menschen mit Behinderung mit dem Fahrrad-Taxi transportieren.&lt;/p&gt;
&lt;h3 id=&quot;meine-stadt&quot; tabindex=&quot;-1&quot;&gt;Meine Stadt&lt;/h3&gt;
&lt;p&gt;Hallo Eric, mein Schnuckiputzi!&lt;/p&gt;
&lt;p&gt;ich freue mich schon darauf, mir meine Stadt zu zeigen. Singapur ist sicher und sehr multikulti. Unser Sprache, &amp;quot;Singlish&amp;quot;, wird für dich interessant werden, weil du ein Philologe ist. Es ist eine gut gemischt von Hokkien, Englisch, und Malaysisch.&lt;/p&gt;
&lt;p&gt;Obwohl du in den USA Chinesische Essen probieren hast, die Essen hier in Singapur absolut besser ist.&lt;/p&gt;
&lt;p&gt;Hoffentlich wirst du Lüst haben und bis bald!&lt;/p&gt;
&lt;p&gt;Viele Grüße,
Lieu&lt;/p&gt;
&lt;h3 id=&quot;w%C3%B6fur-w%C3%BCrden-sie-es-ausgeben%3F&quot; tabindex=&quot;-1&quot;&gt;Wöfur würden Sie es ausgeben?&lt;/h3&gt;
&lt;p&gt;Es hängt&lt;/p&gt;
&lt;h2 id=&quot;2023-07-20&quot; tabindex=&quot;-1&quot;&gt;2023-07-20&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;jeweils: each, every&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Und dann suchen wir {{jeweils}} irgendeine Kneipe aus.&lt;/li&gt;
&lt;li&gt;Diese Punkte betreffen aussließlich die {{jeweilige}} Stadt.&lt;/li&gt;
&lt;li&gt;Jeder Schuler bekommt jeweils ein Examsheet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Pfleger: the nurse&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Frühschicht: the early shift&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Unfall: the accident, the mishap&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Verletzter: the casualty&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;einliefern: to take someone to the hospital&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;entfernt: remote, distant&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Angestellte&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Auszubildenden:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kunden:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bestellungen:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;erwachen: to awake&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Erzieher:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Müllabführ:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Altenheim:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;üblich: usual&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Auszubildende: the apprentice&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Bauhof: the builders yard, construction yard&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;angestellt: to be employed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;betrent: to take after&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;der Verwandter: the relative&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Pferd: the horse&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unbedingt: necessary&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sterblichen: the deceased&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;betrunken: the drunk&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;stolpern: to stumble&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] obdachslose: homeless&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;weltweit:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ausgewählt: to be selected, to be chosen&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Das X hat 40 Städte weltweit ausgewählt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Gesetzte: the law&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bewertet: to review&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Gesetze der jeweiligen Staaten spielen da naturlich eine wichtige Rolle..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Anspruch: claim, right&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;schließlich:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Fläche:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Durchschnitt: average&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zugang: access&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;genannt:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;gefährlich: dangerous&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nachteile: disadvantage&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;gehört: to belong to&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dreckig: schmutzig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;überzeugen: to convince&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;begeistet: enthusiastic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;genervt: to be annoyed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] ausreden: to finish speaking&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lass mich {{ausreden}}.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] vorschlagen: to put forward an idea.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Welche Lösung {{schlagen}} Sie {{vor}}?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] unterbrechen: to interrupt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rücksicht: consideration (for the poor, disabled, etc.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] regieren: to rule&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Geld regiert die ganze Welt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;gebrauchte: second hand&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;die gebrauchte Gitarre&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;anhalfe&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Einrichtung: the furnishings&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;abschalten: to turn off&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beim spazieren gehen kann ich gut abschalten&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;verzichtet: to quit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] stolz: proud&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ich bin stolz auf dich.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;unterhalten: to entertain, to speak.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ich unterhalte mich mit dir.&lt;/li&gt;
&lt;li&gt;Er unterhalt seine Gäste.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ubertreiben: to exaggerate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;leisten:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ich können mir nicht leisten.&lt;/li&gt;
&lt;li&gt;Das kann ich mir leisten.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;[x] vernichten: to annihilate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ich werde dich vernichten.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ausgeben für:&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fälschen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;stehlen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sich Geld leihen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;angeben: to spend&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;verwenden: benutzen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;versäumen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Schulden&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;leihen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Zinzen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Einnahmen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Ausgaben&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;fällig&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die mahnung&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;verlangen&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;die Rundfunktgebühr&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;dabheben&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;das Gehalt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ausreichend&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2023-07-21&quot; tabindex=&quot;-1&quot;&gt;2023-07-21&lt;/h2&gt;
&lt;h3 id=&quot;ein-%C3%BCberblick-von-meiner-stadt&quot; tabindex=&quot;-1&quot;&gt;Ein Überblick von meiner Stadt&lt;/h3&gt;
&lt;p&gt;In jeder Ecke von Singapur gibt es viele, viele Pflanzen. Die Pflanzen in Deutschland sind ziemlich regelmäsig. Nicht so in Singapur. Eine Blatt der Macrorrhiza ist großer als einen Tisch. Die Blätter der Mimosa schließen, wenn man sie berührt. Im April, gibt es so viele Mangos, dass sie zu Boden fallen und verfaulen. Die ganze Luft duftet von süßen, fruchtigem Wein.&lt;/p&gt;
&lt;p&gt;Einige Pflanzen, weil die Sonne auf die gut scheint, oder weil die im gut Erd gepflanzt wurden, wachsen groß und stark. Ihre Blätte wachsen groß und blockieren die Sonne unten. Für andere Pflanzen, die weniger Sonnenlicht bekommen, werden die Blätter kleiner und kleiner und am Ende sterben sie. Es ist traurig, dass die großest Pflanzen keine Zeit haben, um über ihre Brüder und Schwestern nachzudenken.&lt;/p&gt;
&lt;p&gt;Jeden tag gibt es so viele Sonnen in Singapur. Die Pflanzen sind von der Sonne geblindet. Die Pflanzen kann nur Sonne sehen, und sie wachseln so schnell sie können, um mehr Sönnen zu bekommen. Sönnen, sönnen, sönnen. Die Pflanzen können gar nicht anderes sehen. Die Pflanzen haben nicht gedacht, was sie eigentlich wollen.&lt;/p&gt;
&lt;p&gt;Was wollen sie eigentlich? Um die Welt reisen? Philologie studieren? Eine schöne Frau in einem schmutzigen Kneipe küssen?&lt;/p&gt;
&lt;p&gt;Einige Pflanzen haben realisiert, was sie eigentlich wollen. Aber sie haben viel Angst. Sie denken: &amp;quot;Wenn ich nicht so schnell wachseln, wie ich kann, werde ich sterben.&amp;quot; Oder, &amp;quot;Ich werde die Welt bereisen, wenn ich Geld habe. Ich kann nicht meinen Job kündigen. Ich muss für eines Haus und meine zukünftigen Kinder Geld sparen&amp;quot; und so weiter.&lt;/p&gt;
&lt;p&gt;Und am Ende sterben sie, Kopf voll von Träume.&lt;/p&gt;
&lt;p&gt;Ich habe in Europa für ein Paar Jahre gewohnt. Und ich hatte die Glück, viele Europaische Pflanzen kennenzulernen. Mein Wunsch ist, für die Pflanzen in meinem Heimatland, von die Europaische Pflanzen zu lernen.&lt;/p&gt;
&lt;h2 id=&quot;2023-07-25&quot; tabindex=&quot;-1&quot;&gt;2023-07-25&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;treiben --&lt;/li&gt;
&lt;li&gt;kräftig -- strong, powerful&lt;/li&gt;
&lt;li&gt;das Bein -- the leg&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/Pasted%20image%2020230726090616.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Und da muss man ganz liese in eine Ecke stellen und mucksmäuschenstill sein, damit
man nicht auffällt.&lt;/p&gt;
&lt;p&gt;Und können sie sich es leisten, langsam aufzustehen oder müssen Sie sich jeden Morgen beeilen?&lt;/p&gt;
&lt;p&gt;bitte sprecht mich nicht an
Bist du eine leidenschaftliche Person?
Wofür was entfacht in dir Leidenschaft&lt;/p&gt;
&lt;p&gt;Es wird von den Prüfungsteilnehmenden erwartet, dass sie den hier vorliegenden Wortschatz zumindest rezeptiv beherrschen, das heiß dass diese beim Bearbeiten der geschriebenen Texte verstanden werden müssen.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;je nachdem -- it depends&lt;/li&gt;
&lt;li&gt;gurken&lt;/li&gt;
&lt;li&gt;empfinden -- to feel something&lt;/li&gt;
&lt;li&gt;einhalten -- to observe something, or to halt, to stop&lt;/li&gt;
&lt;li&gt;enthalten -- contained, covered, to include, to enclose&lt;/li&gt;
&lt;li&gt;die Ehre -- the glory&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;what does that remind me of&amp;quot; -- to segue from topic to topic&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;why&amp;quot; questions -- Why did you decide to do that&lt;/li&gt;
&lt;li&gt;what do you do, why do you do it?&lt;/li&gt;
&lt;li&gt;laughing is a habit that gets better&lt;/li&gt;
&lt;li&gt;mirroring -- last one to three words&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A1: 650
A2: 1300
B1: 2400&lt;/p&gt;
&lt;h2 id=&quot;2023-07-26&quot; tabindex=&quot;-1&quot;&gt;2023-07-26&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] überfordern - to be overwhelmed&lt;/li&gt;
&lt;li&gt;[x] unabhängig - independent&lt;/li&gt;
&lt;li&gt;[x] vertretung - replacement&lt;/li&gt;
&lt;li&gt;[x] heraushängen - to hang out&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a2-wortliste-(1300-worte)&quot; tabindex=&quot;-1&quot;&gt;A2 Wortliste (1300 Worte)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] die Ampel:
&lt;ul&gt;
&lt;li&gt;Wenn die Ampel grün wird kannst du die Strasse überqueren.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] anbieten
&lt;ul&gt;
&lt;li&gt;Kann ich dich etwas zu trinken anbieten?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] aufpassen
&lt;ul&gt;
&lt;li&gt;Tut mir leid. Da habe ich wohl nicht aufgepasst.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] aufräumen
&lt;ul&gt;
&lt;li&gt;Vor meinem Urlaub muss ich unbedingt noch meinen Schreibtisch aufräumen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] aufregen
&lt;ul&gt;
&lt;li&gt;Ganz ruhig! Bitte regen Sie sich nicht auf.&lt;/li&gt;
&lt;li&gt;Heute hast du eine Prüfung. Bist du schon aufgeregt?&lt;/li&gt;
&lt;li&gt;Die Musikgruppe zu erleben war sehr aufregend.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Ausbildung
&lt;ul&gt;
&lt;li&gt;Ich habe meine Ausbildung abgeschlossen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Ausflug
&lt;ul&gt;
&lt;li&gt;Am Wochenende machen wir mit Freunden einen Ausflug nach Heidelberg.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sich ausruhen
&lt;ul&gt;
&lt;li&gt;Sie ruhen sich von der Arbeit aus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] außerdem
&lt;ul&gt;
&lt;li&gt;Der Film war langweilig, und außerdem haben die Schauspieler schlecht gespielt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] außerhalb
&lt;ul&gt;
&lt;li&gt;Wir wohnen außerhalb des Waldes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] aussteigen
&lt;ul&gt;
&lt;li&gt;Diese ist meine Haltestelle. Ich steige hier aus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Ausstellung
&lt;ul&gt;
&lt;li&gt;20.000 Eintrittskarten waren bereits vor Beginn der Ausstellung verkauft worden&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] beeilen
&lt;ul&gt;
&lt;li&gt;Wir müssen uns beeilen. Sonst verpassen wir den Zug.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] begründen
&lt;ul&gt;
&lt;li&gt;Bitte begründen Sie Ihre Meinung.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] beraten
&lt;ul&gt;
&lt;li&gt;Unser Personal berät Sie gern, wenn Sie Fragen haben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] berichten
&lt;ul&gt;
&lt;li&gt;Alle Zeitungen haben über den Unfall berichtet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Bescheid
&lt;ul&gt;
&lt;li&gt;Den endgültigen Bescheid erhalten Sie in etwa vier Wochen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] (sich) beschweren
&lt;ul&gt;
&lt;li&gt;Wo können wir uns beschweren (to complain)?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] besonders
&lt;ul&gt;
&lt;li&gt;Es ist besonders gut, dass du Big Dick Energy hast.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] bestätigen
&lt;ul&gt;
&lt;li&gt;Die Firma hat mir den Termin schriftlich bestätigt.&lt;/li&gt;
&lt;li&gt;Ich kann bestätigen, dass er hier war.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] (sich) bewerben
&lt;ul&gt;
&lt;li&gt;Ich habe mich um diese Stelle beworben.&lt;/li&gt;
&lt;li&gt;Ich habe mich als Kellner beworben.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] bitten
&lt;ul&gt;
&lt;li&gt;Darf ich Sie bitten, kurz zuzuhören?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Blatt
&lt;ul&gt;
&lt;li&gt;Das Blatt der Macrorrhiza ist so groß wie ein Tisch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Bohne
&lt;ul&gt;
&lt;li&gt;Ich esse gern Bohnen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] braten
&lt;ul&gt;
&lt;li&gt;Das Fleisch muss zehn Minuten braten.&lt;/li&gt;
&lt;li&gt;Heute gibt es gebratenen Fisch.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] buchen
&lt;ul&gt;
&lt;li&gt;Ich habe für morgen einen Flug nach Rom gebucht (to book).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] darauf
&lt;ul&gt;
&lt;li&gt;Darauf fällt mir keine Antwort ein.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] darüber
&lt;ul&gt;
&lt;li&gt;Darüber spreche ich nicht gern.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] dabei
&lt;ul&gt;
&lt;li&gt;Hast du einen Stift dabei?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] dafür
&lt;ul&gt;
&lt;li&gt;Ich bin dafür.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] dagegen
&lt;ul&gt;
&lt;li&gt;Ich bin dagegen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] damals
&lt;ul&gt;
&lt;li&gt;Mit 15 wollte ich gerne Klavier spielen lernen. Aber damals hatte ich kein Geld dafür.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] deutlich
&lt;ul&gt;
&lt;li&gt;Schreiben Sie bitte deutlich (neatly)!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] dringend
&lt;ul&gt;
&lt;li&gt;Ich muss dich dringend (eilig) sprechen.&lt;/li&gt;
&lt;li&gt;Ich erwarte einen dringenden Anruf.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] drüben
&lt;ul&gt;
&lt;li&gt;Dort drüben ist die Haltestelle.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] drücken
&lt;ul&gt;
&lt;li&gt;Sie brauchen nur auf den Knopf zu drücken.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] drucken
&lt;ul&gt;
&lt;li&gt;Bei welcher Firma haben Sie diese Prospekte drucken lassen?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] dünn
&lt;ul&gt;
&lt;li&gt;Mein Sohn ist sehr dünn (thin). Er isst zu wenig.&lt;/li&gt;
&lt;li&gt;Warum ziehst du nur so einen dünnen Mantel an? Es ist kalt draußen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] eintragen
- Tragen Sie sich bitte in die Liste ein.&lt;/li&gt;
&lt;li&gt;[x] einverstanden
&lt;ul&gt;
&lt;li&gt;Bist du einverstanden, wenn wir bald nach Hause gehen?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] einzeln
&lt;ul&gt;
&lt;li&gt;Dieses Mineralwasser gibt es nur als Sechserpack, nicht einzeln.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] einziehen
&lt;ul&gt;
&lt;li&gt;Die Wohnung ist fertig. Wir können nächste Woche einziehen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] erkältet
&lt;ul&gt;
&lt;li&gt;Ich bin erkältet, daher kann ich heute nicht kommen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Erlaubnis
&lt;ul&gt;
&lt;li&gt;Sie hätten ihn vorher um Erlaubnis bitten müssen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Ermäßigung
&lt;ul&gt;
&lt;li&gt;Es gibt eine Ermäßigung für Kinder und Senioren.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Fach
&lt;ul&gt;
&lt;li&gt;Die Handtücher sind im obersten Fach links.&lt;/li&gt;
&lt;li&gt;Welches Fach magst du in der Schule am liebsten?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Abfahrt
&lt;ul&gt;
&lt;li&gt;Es bleiben uns noch zwanzig Minuten bis zur Abfahrt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] faul
&lt;ul&gt;
&lt;li&gt;Mein Sohn war am Anfang in der Schule sehr faul. Heute lernte er sehr fließig.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sich freuen
&lt;ul&gt;
&lt;li&gt;Es freut mich, dass alles so gut geklappt hat.&lt;/li&gt;
&lt;li&gt;Ich habe mich über Ihr Geschenk sehr gefreut.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] froh
&lt;ul&gt;
&lt;li&gt;Ich bin froh, dass alles so gut geklappt hat.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Führerschein
&lt;ul&gt;
&lt;li&gt;Wenn Sie betrunken Auto fahren, verlieren Sie Ihren Führerschein (driving license).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] furchtbar
&lt;ul&gt;
&lt;li&gt;Gestern Abend gab es ein Gewitter. Es hat furchtbar (terribly) geblitzt und gedonnert.&lt;/li&gt;
&lt;li&gt;Das war mir furchtbar (terribly) unangenehm.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Gabel&lt;/li&gt;
&lt;li&gt;[x] das Gehalt&lt;/li&gt;
&lt;li&gt;[x] die Geldbörse
&lt;ul&gt;
&lt;li&gt;[x] Ich habe nur Kleingeld in meiner Geldbörse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] das Gerät&lt;/li&gt;
&lt;li&gt;[ ] das Gericht&lt;/li&gt;
&lt;li&gt;[x] das Geschirr&lt;/li&gt;
&lt;li&gt;[ ] das Gewitter&lt;/li&gt;
&lt;li&gt;[ ] die Grippe&lt;/li&gt;
&lt;li&gt;[x] gültig sein&lt;/li&gt;
&lt;li&gt;[x] der Hals&lt;/li&gt;
&lt;li&gt;[x] die Haltestelle&lt;/li&gt;
&lt;li&gt;[ ] das Heft&lt;/li&gt;
&lt;li&gt;[ ] die Heizung&lt;/li&gt;
&lt;li&gt;[ ] der Herd&lt;/li&gt;
&lt;li&gt;[ ] herstellen&lt;/li&gt;
&lt;li&gt;[ ] herunterladen&lt;/li&gt;
&lt;li&gt;[ ] holen&lt;/li&gt;
&lt;li&gt;[ ] husten&lt;/li&gt;
&lt;li&gt;[ ] die Jugendherberge&lt;/li&gt;
&lt;li&gt;[ ] die Kasse&lt;/li&gt;
&lt;li&gt;[ ] die Kenntnisse&lt;/li&gt;
&lt;li&gt;[ ] die Kette&lt;/li&gt;
&lt;li&gt;[ ] klappen&lt;/li&gt;
&lt;li&gt;[ ] die Kreuzung&lt;/li&gt;
&lt;li&gt;[x] (sich) kümmern
&lt;ul&gt;
&lt;li&gt;[x] Die Polizei kümmert sich um die Sicherheit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] kündigen
&lt;ul&gt;
&lt;li&gt;[x] Ich war mit meiner Stelle (Arbeitsplatz) nicht zufrieden und habe gekündigt (resigned).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] leer&lt;/li&gt;
&lt;li&gt;[x] liefern
&lt;ul&gt;
&lt;li&gt;[x] Wir liefern (to deliver) Ihnen das Regal (the shelf) direkt ins Haus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] die Lüge&lt;/li&gt;
&lt;li&gt;[x] der Magen
&lt;ul&gt;
&lt;li&gt;[x] Mit tut der magen (bauch) weh. Ich habe Magenschmerzen (Bauchschmerzen).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] malen
&lt;ul&gt;
&lt;li&gt;[x] Ich male (paint) die Wand rot mit meinem Blut.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] die Mannschaft&lt;/li&gt;
&lt;li&gt;[ ] der Mantel&lt;/li&gt;
&lt;li&gt;[x] die Menge
&lt;ul&gt;
&lt;li&gt;[x] Diesen Preis gibt es nur, wenn Sie große Mengen (amount) kaufen.&lt;/li&gt;
&lt;li&gt;[ ] Ich kenne schon eine Menge Leute in der Stadt.&lt;/li&gt;
&lt;li&gt;[ ] Das Auto hat bestimmt eine Menge geld gekostet.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] die Mütze&lt;/li&gt;
&lt;li&gt;[x] nass
&lt;ul&gt;
&lt;li&gt;[x] Es hat schrecklich geregnet. Ich bin ganz nass (feucht) geworden.&lt;/li&gt;
&lt;li&gt;[x] Geh nicht mit den nassen (feucht) Schuhen ins Wohnzimmer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] nebenan&lt;/li&gt;
&lt;li&gt;[x] neblig&lt;/li&gt;
&lt;li&gt;[ ] nirgends&lt;/li&gt;
&lt;li&gt;[x] das Pferd&lt;/li&gt;
&lt;li&gt;[x] raten
&lt;ul&gt;
&lt;li&gt;[x] Ich möchte billig Urlaub machen. Was raten (to advise) Sie mir?&lt;/li&gt;
&lt;li&gt;[x] Rate (to guess) mal, wen ich heute getroffen habe! Deinen Lehrer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] das Rätsel&lt;/li&gt;
&lt;li&gt;[ ] rechnen&lt;/li&gt;
&lt;li&gt;[ ] der Reifen&lt;/li&gt;
&lt;li&gt;[x] die Reihe
&lt;ul&gt;
&lt;li&gt;[x] In {{jeder Reihe}} (every row) saß eine Person.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] die Reinigung&lt;/li&gt;
&lt;li&gt;[ ] reiten&lt;/li&gt;
&lt;li&gt;[ ] sammeln&lt;/li&gt;
&lt;li&gt;[ ] schädlich&lt;/li&gt;
&lt;li&gt;[ ] schaffen&lt;/li&gt;
&lt;li&gt;[ ] der Schalter&lt;/li&gt;
&lt;li&gt;[ ] die Schere&lt;/li&gt;
&lt;li&gt;[ ] das Schiff&lt;/li&gt;
&lt;li&gt;[ ] das Schild&lt;/li&gt;
&lt;li&gt;[ ] schimpfen&lt;/li&gt;
&lt;li&gt;[ ] schlimm&lt;/li&gt;
&lt;li&gt;[ ] schrecklich&lt;/li&gt;
&lt;li&gt;[ ] schriftlich&lt;/li&gt;
&lt;li&gt;[x] schwach&lt;/li&gt;
&lt;li&gt;[x] die Seife&lt;/li&gt;
&lt;li&gt;[ ] die Sendung&lt;/li&gt;
&lt;li&gt;[ ] speichern&lt;/li&gt;
&lt;li&gt;[ ] stattfinden&lt;/li&gt;
&lt;li&gt;[ ] die Stelle&lt;/li&gt;
&lt;li&gt;[ ] der Stiefel&lt;/li&gt;
&lt;li&gt;[ ] stören&lt;/li&gt;
&lt;li&gt;[ ] streng&lt;/li&gt;
&lt;li&gt;[ ] sympathisch&lt;/li&gt;
&lt;li&gt;[ ] die Tafel&lt;/li&gt;
&lt;li&gt;[x] teilnehmen
&lt;ul&gt;
&lt;li&gt;[x] Ich werde morgen am Frisbee-Spiel teilnehmen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] übernachten&lt;/li&gt;
&lt;li&gt;[ ] übersetzen&lt;/li&gt;
&lt;li&gt;[x] die Übersetzung&lt;/li&gt;
&lt;li&gt;[x] unbedingt
&lt;ul&gt;
&lt;li&gt;[x] Ich muss unbedingt (absolutely) mit dir sprechen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] der Unfall&lt;/li&gt;
&lt;li&gt;[ ] (sich) unterhalten&lt;/li&gt;
&lt;li&gt;[ ] die Unterkunft&lt;/li&gt;
&lt;li&gt;[ ] unternehmen&lt;/li&gt;
&lt;li&gt;[ ] untersuchen&lt;/li&gt;
&lt;li&gt;[x] verabredet sein&lt;/li&gt;
&lt;li&gt;[x] der Verein&lt;/li&gt;
&lt;li&gt;[ ] vereinbaren&lt;/li&gt;
&lt;li&gt;[x] verletzt&lt;/li&gt;
&lt;li&gt;[ ] verliebt&lt;/li&gt;
&lt;li&gt;[ ] verlieren&lt;/li&gt;
&lt;li&gt;[ ] verreisen&lt;/li&gt;
&lt;li&gt;[ ] verschieben&lt;/li&gt;
&lt;li&gt;[ ] versuchen&lt;/li&gt;
&lt;li&gt;[x] der Vertrag&lt;/li&gt;
&lt;li&gt;[ ] vorher&lt;/li&gt;
&lt;li&gt;[ ] vorn(e)
&lt;ul&gt;
&lt;li&gt;Bitte vorn(e) einsteigen&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[ ] vorsichtig&lt;/li&gt;
&lt;li&gt;[ ] vorstellen&lt;/li&gt;
&lt;li&gt;[ ] vorwärts&lt;/li&gt;
&lt;li&gt;[ ] wach&lt;/li&gt;
&lt;li&gt;[ ] wecken&lt;/li&gt;
&lt;li&gt;[ ] wegnehmen&lt;/li&gt;
&lt;li&gt;[x] der Wettbewerb&lt;/li&gt;
&lt;li&gt;[ ] die Zahl&lt;/li&gt;
&lt;li&gt;[ ] zeichnen&lt;/li&gt;
&lt;li&gt;[ ] die Zeitschrift&lt;/li&gt;
&lt;li&gt;[ ] der Zettel&lt;/li&gt;
&lt;li&gt;[ ] das Zeugnis&lt;/li&gt;
&lt;li&gt;[ ] ausgezogen&lt;/li&gt;
&lt;li&gt;[ ] zufrieden&lt;/li&gt;
&lt;li&gt;[ ] zuhören&lt;/li&gt;
&lt;li&gt;[ ] zuletzt&lt;/li&gt;
&lt;li&gt;[ ] zumachen&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a1-wortliste-(650-worte)&quot; tabindex=&quot;-1&quot;&gt;A1 Wortliste (650 Worte)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[x] abfahren: to depart&lt;/li&gt;
&lt;li&gt;[x] abgeben&lt;/li&gt;
&lt;li&gt;[x] abholen&lt;/li&gt;
&lt;li&gt;[x] der Absender&lt;/li&gt;
&lt;li&gt;[x] anbieten&lt;/li&gt;
&lt;li&gt;[x] anklicken&lt;/li&gt;
&lt;li&gt;[x] ankreuzen&lt;/li&gt;
&lt;li&gt;[x] die Anrede&lt;/li&gt;
&lt;li&gt;[x] der Anrufbeantworter&lt;/li&gt;
&lt;li&gt;[x] die Ansage&lt;/li&gt;
&lt;li&gt;[x] der Anschluss&lt;/li&gt;
&lt;li&gt;die Anzeige&lt;/li&gt;
&lt;li&gt;[x] sich anziehen&lt;/li&gt;
&lt;li&gt;[x] aufhören&lt;/li&gt;
&lt;li&gt;[x] die Auskunft&lt;/li&gt;
&lt;li&gt;[x] aussteigen: to get off (a stop)&lt;/li&gt;
&lt;li&gt;[x] der Ausweis&lt;/li&gt;
&lt;li&gt;[x] (sich) ausziehen&lt;/li&gt;
&lt;li&gt;[x] besetzt: occupied
&lt;ul&gt;
&lt;li&gt;die nummer ist immer besetzt.&lt;/li&gt;
&lt;li&gt;der platz ist besetzt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] besichtigen: to visit (a place)
&lt;ul&gt;
&lt;li&gt;Sehenswürdigkeiten besichtigen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Birne -- the pear&lt;/li&gt;
&lt;li&gt;[x] der Bleistift -- the pencil&lt;/li&gt;
&lt;li&gt;der Blick -- (look, glance). überraschter Blick, im Blick auf ..&lt;/li&gt;
&lt;li&gt;[x] böse -- vicious, wicked, angry...
&lt;ul&gt;
&lt;li&gt;Ich bin böse auf mich.&lt;/li&gt;
&lt;li&gt;Ich habe dein Buch vergessen. Hoffentlich bist du mir nicht böse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] daneben
&lt;ul&gt;
&lt;li&gt;Du kennst doch die Post. Daneben ist die Bank.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] drücken - to squeeze, to push, to press
&lt;ul&gt;
&lt;li&gt;Drück hier, dann geht der Computer an.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;die Durchsage: die Anssage&lt;/li&gt;
&lt;li&gt;[x] eilig: urgent
&lt;ul&gt;
&lt;li&gt;Ich habs nicht eilig. Und du?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] einsteigen: to enter, to step in, to board
&lt;ul&gt;
&lt;li&gt;Schnell, steig ein, der Zug fährt gleich.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Eintritt&lt;/li&gt;
&lt;li&gt;der Empfänger: the recipient
&lt;ul&gt;
&lt;li&gt;Empfänger unbekannt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Ergebnis&lt;/li&gt;
&lt;li&gt;[x] erlauben: allowed
&lt;ul&gt;
&lt;li&gt;Rauchen ist hier nicht erlaubt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] erzählen: to tell something, to narrate
&lt;ul&gt;
&lt;li&gt;Lügen erzählen: to tell lies&lt;/li&gt;
&lt;li&gt;Ich muss Ihnen davon erzählen, um es mir vom Herzen zu reden.&lt;/li&gt;
&lt;li&gt;Es schadet nie, eine gute Geschichte zweimal zu erzählen.&lt;/li&gt;
&lt;li&gt;Die Himmel erzählen die Ehre Gottes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] fehlen: to lack, to miss
&lt;ul&gt;
&lt;li&gt;Mir fehlen die Worte. Words fail me.&lt;/li&gt;
&lt;li&gt;Entschuldigung für mein Fehlen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Gepäck: the luggage
&lt;ul&gt;
&lt;li&gt;Lassen Sie ihr Gepäck nicht unbeaufsichtigt!&lt;/li&gt;
&lt;li&gt;Wollen Sie Ihr Gepäck mitnehmen?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] geradeaus: ahead, straight on
&lt;ul&gt;
&lt;li&gt;Gehen sie geradeaus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] das Gewicht: the weight, the severity, the importance
&lt;ul&gt;
&lt;li&gt;etwas Gewicht verleihen&lt;/li&gt;
&lt;li&gt;an Gewicht zunehmen, an Gewicht verlieren&lt;/li&gt;
&lt;li&gt;sein Gewicht in Gold wert.&lt;/li&gt;
&lt;li&gt;Ist dies ein Argument von Gewicht?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] gültig:
&lt;ul&gt;
&lt;li&gt;Der Pass ist nicht mehr gültig.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Haltestelle:
&lt;ul&gt;
&lt;li&gt;An der nächsten Haltestelle müssen Sie aussteigen.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] hell
&lt;ul&gt;
&lt;li&gt;Im Sommer ist es bis 21 Uhr hell.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Herd
&lt;ul&gt;
&lt;li&gt;In der neuen Küche fehlt noch der Herd.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] holen:
&lt;ul&gt;
&lt;li&gt;Ich hole zwei Flaschen Wasser aus der Küche.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] die Kasse
&lt;ul&gt;
&lt;li&gt;Zahlen Sie bitte an der Kasse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] kriegen: verdienen?
&lt;ul&gt;
&lt;li&gt;Ich kriege 15 Euro in der Stunde für meine Arbeit.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] kümmern sich um:
&lt;ul&gt;
&lt;li&gt;Jede Mutter kümmert sich um ihre kleinen Kinder.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] ledig:
&lt;ul&gt;
&lt;li&gt;Sind Sie verheiratet? – Nein. Ledig.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] mitnehmen&lt;/li&gt;
&lt;li&gt;[x] das Öl&lt;/li&gt;
&lt;li&gt;[x] die Rechnung&lt;/li&gt;
&lt;li&gt;[x] das Schild, -er&lt;/li&gt;
&lt;li&gt;der Schluss
&lt;ul&gt;
&lt;li&gt;Ich muss jetzt Schluss machen&lt;/li&gt;
&lt;li&gt;Zum Schluss gibt er uns allen die Hand.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] zu sein: to be closed
&lt;ul&gt;
&lt;li&gt;Die Tür ist zu.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] sofort: immediately&lt;/li&gt;
&lt;li&gt;[x] übernachten&lt;/li&gt;
&lt;li&gt;[x] überweisen&lt;/li&gt;
&lt;li&gt;[x] umziehen&lt;/li&gt;
&lt;li&gt;[x] unterschreiben&lt;/li&gt;
&lt;li&gt;[x] die Unterschrift&lt;/li&gt;
&lt;li&gt;[x] der Verein&lt;/li&gt;
&lt;li&gt;[x] weiblich&lt;/li&gt;
&lt;li&gt;[x] weiter
&lt;ul&gt;
&lt;li&gt;Der Bus fährt nicht weiter.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;[x] der Zoll&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;625-words&quot; tabindex=&quot;-1&quot;&gt;625 words&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;der Schauspieler -- actor&lt;/li&gt;
&lt;li&gt;das Adjektiv -- adjective&lt;/li&gt;
&lt;li&gt;der Erwachsene -- adult&lt;/li&gt;
&lt;li&gt;die Luft -- the air&lt;/li&gt;
&lt;li&gt;der Flughafen-- the airport&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;lebendig -- alive&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;das Tier-- the animal&lt;/li&gt;
&lt;li&gt;die Wohnung -- apartment&lt;/li&gt;
&lt;li&gt;der Apfel -- apple&lt;/li&gt;
&lt;li&gt;April -- April&lt;/li&gt;
&lt;li&gt;der Arm -- arm&lt;/li&gt;
&lt;li&gt;die Armee -- army&lt;/li&gt;
&lt;li&gt;die Kunst -- art&lt;/li&gt;
&lt;li&gt;der Kunstler -- artist&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;der Überfall -- the attack&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;August -- August&lt;/li&gt;
&lt;li&gt;der Author -- the author&lt;/li&gt;
&lt;li&gt;das Kleinkind -- the baby&lt;/li&gt;
&lt;li&gt;der Rücken -- the back (body)&lt;/li&gt;
&lt;li&gt;hinter -- back (direction)&lt;/li&gt;
&lt;li&gt;schlecht -- bad&lt;/li&gt;
&lt;li&gt;die Tasche -- the bag&lt;/li&gt;
&lt;li&gt;das Ball -- the ball&lt;/li&gt;
&lt;li&gt;die Banane -- the banana&lt;/li&gt;
&lt;li&gt;die Band -- the band&lt;/li&gt;
&lt;li&gt;die Bank -- the bank&lt;/li&gt;
&lt;li&gt;die Kneipe -- the bar&lt;/li&gt;
&lt;li&gt;das Badezimmer -- the bathroom&lt;/li&gt;
&lt;li&gt;der Strand -- the beach&lt;/li&gt;
&lt;li&gt;der Bart -- the beard&lt;/li&gt;
&lt;li&gt;schlagen -- beat (someone)&lt;/li&gt;
&lt;li&gt;schön -- beautiful&lt;/li&gt;
&lt;li&gt;das Bett -- bed&lt;/li&gt;
&lt;li&gt;das Schlafzimmer -- bedroom&lt;/li&gt;
&lt;li&gt;das Rindfleich -- the beef&lt;/li&gt;
&lt;li&gt;das Bier -- the beer&lt;/li&gt;
&lt;li&gt;biegen -- bend&lt;/li&gt;
&lt;li&gt;das Getränk -- the beverage&lt;/li&gt;
&lt;li&gt;das Fahrrad -- bicycle&lt;/li&gt;
&lt;li&gt;groß -- big, large&lt;/li&gt;
&lt;li&gt;die Rechnung -- the bill&lt;/li&gt;
&lt;li&gt;billion&lt;/li&gt;
&lt;li&gt;der Vogel -- the bird&lt;/li&gt;
&lt;li&gt;schwarz -- black&lt;/li&gt;
&lt;li&gt;blind -- blind&lt;/li&gt;
&lt;li&gt;das Blut -- blood&lt;/li&gt;
&lt;li&gt;blau -- blue&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;das Boot -- boat&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;der Körper-- body&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;der Knochen-- bone&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;-- book&lt;/li&gt;
&lt;li&gt;-- bottle&lt;/li&gt;
&lt;li&gt;-- bottom&lt;/li&gt;
&lt;li&gt;-- the box&lt;/li&gt;
&lt;li&gt;-- the boy&lt;/li&gt;
&lt;li&gt;-- the brain&lt;/li&gt;
&lt;li&gt;-- the bread&lt;/li&gt;
&lt;li&gt;-- to break&lt;/li&gt;
&lt;li&gt;-- breakfast&lt;/li&gt;
&lt;li&gt;-- the bridge&lt;/li&gt;
&lt;li&gt;-- the brother&lt;/li&gt;
&lt;li&gt;-- brown&lt;/li&gt;
&lt;li&gt;-- to build&lt;/li&gt;
&lt;li&gt;-- the building&lt;/li&gt;
&lt;li&gt;-- to burn&lt;/li&gt;
&lt;li&gt;-- the bus&lt;/li&gt;
&lt;li&gt;-- to buy&lt;/li&gt;
&lt;li&gt;-- the cake&lt;/li&gt;
&lt;li&gt;-- to call&lt;/li&gt;
&lt;li&gt;-- the camera&lt;/li&gt;
&lt;li&gt;-- the camp&lt;/li&gt;
&lt;li&gt;-- the car&lt;/li&gt;
&lt;li&gt;-- the card&lt;/li&gt;
&lt;li&gt;-- to carry&lt;/li&gt;
&lt;li&gt;-- the cat&lt;/li&gt;
&lt;li&gt;-- to catch&lt;/li&gt;
&lt;li&gt;-- the ceiling&lt;/li&gt;
&lt;li&gt;das Handy -- the cellphone&lt;/li&gt;
&lt;li&gt;-- centimeter&lt;/li&gt;
&lt;li&gt;-- the chair&lt;/li&gt;
&lt;li&gt;-- cheap&lt;/li&gt;
&lt;li&gt;-- the cheese&lt;/li&gt;
&lt;li&gt;-- the chicken&lt;/li&gt;
&lt;li&gt;-- the child&lt;/li&gt;
&lt;li&gt;-- the circle&lt;/li&gt;
&lt;li&gt;-- the city&lt;/li&gt;
&lt;li&gt;-- the clay&lt;/li&gt;
&lt;li&gt;sauber -- clean (adj.)&lt;/li&gt;
&lt;li&gt;putzen -- to clean&lt;/li&gt;
&lt;li&gt;die Uhr -- the clock&lt;/li&gt;
&lt;li&gt;schlossen -- to close&lt;/li&gt;
&lt;li&gt;die Kleidung -- the clothing&lt;/li&gt;
&lt;li&gt;-- the club&lt;/li&gt;
&lt;li&gt;-- the coat&lt;/li&gt;
&lt;li&gt;-- the coffee&lt;/li&gt;
&lt;li&gt;-- cold&lt;/li&gt;
&lt;li&gt;-- the colour&lt;/li&gt;
&lt;li&gt;-- the computer&lt;/li&gt;
&lt;li&gt;-- the consonant&lt;/li&gt;
&lt;li&gt;-- the contract&lt;/li&gt;
&lt;li&gt;-- to cook&lt;/li&gt;
&lt;li&gt;-- cool&lt;/li&gt;
&lt;li&gt;-- the copper&lt;/li&gt;
&lt;li&gt;-- the corn&lt;/li&gt;
&lt;li&gt;-- the corner&lt;/li&gt;
&lt;li&gt;zählen -- to count&lt;/li&gt;
&lt;li&gt;das Land -- the country&lt;/li&gt;
&lt;li&gt;das Gericht-- the court&lt;/li&gt;
&lt;li&gt;-- the cow&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;die Gedränge -- the crowd&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;-- to cry&lt;/li&gt;
&lt;li&gt;die Tasse-- the cup&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;gebogen-- curved&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;schneiden -- to cut&lt;/li&gt;
&lt;li&gt;tanzen -- to dance&lt;/li&gt;
&lt;li&gt;dunkel -- dark&lt;/li&gt;
&lt;li&gt;das Datum -- the date&lt;/li&gt;
&lt;li&gt;die Tochter -- the daughter&lt;/li&gt;
&lt;li&gt;der Tag -- the day&lt;/li&gt;
&lt;li&gt;der Toter, die Toten -- the dead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;taub -- deaf&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;der Tod -- the death&lt;/li&gt;
&lt;li&gt;der Dezember -- December&lt;/li&gt;
&lt;li&gt;tief -- deep&lt;/li&gt;
&lt;li&gt;das Diamant -- the diamond&lt;/li&gt;
&lt;li&gt;sterben -- to die&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;graben -- to dig&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;das Abendessen -- the dinner&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;die Richtung -- the direction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;schmutzig -- dirty&lt;/li&gt;
&lt;li&gt;die Krankheit -- the disease&lt;/li&gt;
&lt;li&gt;-- the doctor&lt;/li&gt;
&lt;li&gt;-- the dog&lt;/li&gt;
&lt;li&gt;-- the dollar&lt;/li&gt;
&lt;li&gt;-- the door&lt;/li&gt;
&lt;li&gt;-- the dot&lt;/li&gt;
&lt;li&gt;-- down&lt;/li&gt;
&lt;li&gt;-- to draw&lt;/li&gt;
&lt;li&gt;-- the dream&lt;/li&gt;
&lt;li&gt;-- the dress&lt;/li&gt;
&lt;li&gt;-- to drink&lt;/li&gt;
&lt;li&gt;-- to drive&lt;/li&gt;
&lt;li&gt;-- the drug&lt;/li&gt;
&lt;li&gt;trocken-- dry&lt;/li&gt;
&lt;li&gt;-- the dust&lt;/li&gt;
&lt;li&gt;-- the ear&lt;/li&gt;
&lt;li&gt;-- the Earth&lt;/li&gt;
&lt;li&gt;-- the east&lt;/li&gt;
&lt;li&gt;-- to eat&lt;/li&gt;
&lt;li&gt;-- the edge&lt;/li&gt;
&lt;li&gt;-- the egg&lt;/li&gt;
&lt;li&gt;-- the election&lt;/li&gt;
&lt;li&gt;-- the electronics&lt;/li&gt;
&lt;li&gt;-- the energy&lt;/li&gt;
&lt;li&gt;-- the engine&lt;/li&gt;
&lt;li&gt;-- the evening&lt;/li&gt;
&lt;li&gt;-- the exercise&lt;/li&gt;
&lt;li&gt;teuer -- expensive&lt;/li&gt;
&lt;li&gt;-- to explode&lt;/li&gt;
&lt;li&gt;-- the eye&lt;/li&gt;
&lt;li&gt;-- the face&lt;/li&gt;
&lt;li&gt;-- the autumn&lt;/li&gt;
&lt;li&gt;-- the family&lt;/li&gt;
&lt;li&gt;-- famous&lt;/li&gt;
&lt;li&gt;-- the electric fan&lt;/li&gt;
&lt;li&gt;-- the sports fan&lt;/li&gt;
&lt;li&gt;-- the farm&lt;/li&gt;
&lt;li&gt;-- fast&lt;/li&gt;
&lt;li&gt;-- the father&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Path UBI</title>
    <link href="https://lieuzhenghong.com/Path_UBI/"/>
    <updated>2023-09-10T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/Path_UBI/</id>
    <content type="html">&lt;h1 id=&quot;the-case-for-path&quot; tabindex=&quot;-1&quot;&gt;The case for PATH&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Vision:&lt;/strong&gt; to bring value into the world.
&lt;strong&gt;Mission&lt;/strong&gt;: to give every creator a basic income of $1,000 a month so they can create without concern.&lt;/p&gt;
&lt;p&gt;Imagine a toy economy where taxes accrue to the treasury and are used to fund a UBI of sorts.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There is a token2022 called PATH.&lt;/li&gt;
&lt;li&gt;Each transaction involving PATH pays a 0.1% transfer tax, which accrues to the treasury.&lt;/li&gt;
&lt;li&gt;The treasury gives out PATH daily equally to all verified human accounts (leave the proof-of-personhood aside for now), capped at X PATH/person/day.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note we couldn&#39;t do this with USDC or any other currency that we do not control, as USDC does not allow for a tax-on-transfer. The challenge then is to incentivise the velocity of PATH, by creating an ecosystem (like the real economy) of goods and services.&lt;/p&gt;
&lt;p&gt;Tons of ideas of how we do that were expressed above, but at a 0.1% transfer rate, the total velocity of money has to be 1000x the amount distributed per day. If you want to give out 1,000 PATH per day, you need 1M PATH moving in and out of the system.&lt;/p&gt;
&lt;p&gt;The pie-in-the-sky case is that there&#39;s a 10M, 100M PATH of volume moving around everyday worth of goods and services transacted. 10M == 10,000 PATH per day, 100M == 100,000 PATH per day.&lt;/p&gt;
&lt;h1 id=&quot;sources-and-sinks&quot; tabindex=&quot;-1&quot;&gt;Sources and sinks&lt;/h1&gt;
&lt;p&gt;For this to work the treasury must either keep growing or be revenue neutral.&lt;/p&gt;
&lt;p&gt;Inflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Investment or business income&lt;/li&gt;
&lt;li&gt;0.1% transfer tax&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Outflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic income&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Inflows &amp;gt;= outflows.&lt;/p&gt;
&lt;p&gt;Suggestions for inflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Anyone can suggest an business idea to the Pathfinder treasury DAO&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;e.g. &amp;quot;ChatGPT on Telegram&amp;quot; -- get a grant on completion and in return revenue share with the Pathfinders DAO&lt;/li&gt;
&lt;li&gt;e.g. &amp;quot;SUPERHOT wallet on Telegram&amp;quot; -- a superhot wallet that&#39;s 1-of-2 custodial (although ideally making it noncustodial would be amazing), that comes with quick shortcuts e.g. &amp;quot;/transfer 1 SOL to 0xfp.sol&amp;quot;, &amp;quot;/swap 1 SOL to USDC&amp;quot;, &amp;quot;/withdraw all to 0xfp.sol&amp;quot;. The use case would be to reduce the friction of onboarding all my friends from Telegram (can start sending our employees PATH!)
&lt;ul&gt;
&lt;li&gt;literally a tiplink-esque thing would be nice, /send @celineli 1 PATH&lt;/li&gt;
&lt;li&gt;Which Pathfinder/Pathfinder creature is best for wallet? &amp;quot;Elio&amp;quot; for ChatGPT, &amp;quot;X&amp;quot; for Wallet?&lt;/li&gt;
&lt;li&gt;FYI: Bots are now able to use &lt;a href=&quot;https://telegram.org/blog/topics-in-groups-collectible-usernames#collectible-usernames&quot;&gt;collectible usernames&lt;/a&gt; — including links &lt;strong&gt;without&lt;/strong&gt; the &lt;em&gt;-bot&lt;/em&gt; suffix.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I think this alone is a huge idea
&lt;img src=&quot;https://files.lieu.gg/img/Pasted%20image%2020230910235544.png&quot; alt=&quot;&quot;&gt; Stripe Crypto onramp from Telegram maybe..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But to receive a basic income one has to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;be a real person;&lt;/li&gt;
&lt;li&gt;be a Pathfinder;&lt;/li&gt;
&lt;li&gt;be near-unanimously voted in by the other Pathfinders (which means they must have demonstrated a track record of value)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Number of Pathfinders is (for now) hard capped at 10,000, but obviously Editions 2, 3, 4 etc. are possible. I would keep it as small as possible though at the start.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;synergy-with-pathfinders&quot; tabindex=&quot;-1&quot;&gt;Synergy with Pathfinders&lt;/h1&gt;
&lt;p&gt;Strategy: Use the Pathfinders NFT project to bootstrap the Pathfinders economy. Build goods and services that can be purchased at a discount (or exclusively) with PATH.&lt;/p&gt;
&lt;p&gt;As the economy grows and the treasury accumulates, each Pathfinder NFT will be worth more and more money because they hold the keys to the kingdom: only Pathfinder NFT holders are eligible to receive a basic income.&lt;/p&gt;
&lt;p&gt;We bootstrap the economy by paying all contributors to the Pathfinder project with PATH. True believers can buy PATH and start buying goods and services (e.g. art, compute, GPT-time, plushies, stickers...) with PATH.&lt;/p&gt;
&lt;p&gt;The goal for us is to make stuff that people want to pay for and take PATH as payment.
One example is to convert the mint proceeds from SOL to PATH, and to charge people PATH for any future live-service content.&lt;/p&gt;
&lt;p&gt;Pathfinders is an IP (universe), a community, and now an economy. There&#39;s a reason for the community to stick together and consume goods and services from one another: we get richer together.&lt;/p&gt;
&lt;p&gt;In the future businesses will be incentivised to &amp;quot;hook in&amp;quot; to the Pathfinders community (ergo accept PATH) to benefit from the goodwill, the free marketing, and also they might be able to charge a slight premium because believers &lt;em&gt;want&lt;/em&gt; to use PATH (??? questionable)&lt;/p&gt;
&lt;p&gt;PATH Visa card? LOL -- how would this work&lt;/p&gt;
&lt;h1 id=&quot;things-to-look-out-for&quot; tabindex=&quot;-1&quot;&gt;Things to look out for&lt;/h1&gt;
&lt;p&gt;At the beginning we must avoid at all costs people who sign up to get the UBI and contribute nothing to the economy.  This is the problem with all past UBI projects: they didn&#39;t think about the sinks, only the sources. Onboarding people too fast is a death knell.&lt;/p&gt;
&lt;p&gt;In the future if the economy is sufficiently closed (you can buy everything you need to eat, rent a Pathfinders capsule hotel), or if we become &amp;quot;post-scarcity&amp;quot; (we make so much money from our Pathfinders businesses that we can give that surplus away), then this would be no problem, but that&#39;s still a long ways away.&lt;/p&gt;
&lt;p&gt;I would position it not as a universal basic income (because there are 8 billion people out there), but a global collective of creators (not creatives -- programmers, farmers, restauranteurs) supporting one another.&lt;/p&gt;
&lt;h1 id=&quot;closing-thoughts&quot; tabindex=&quot;-1&quot;&gt;Closing thoughts&lt;/h1&gt;
&lt;p&gt;I will say that if we give 10,000 people $1,000 a month, that&#39;s an outflow of $10M/month. That&#39;s an incredible amount. Can the treasury really make it back? That defies expectations. Literally incredible. They should feel like the luckiest 10,000 people on Earth. Lol.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>on education</title>
    <link href="https://lieuzhenghong.com/education/"/>
    <updated>2023-07-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/education/</id>
    <content type="html">&lt;p&gt;Brian Caplan&#39;s &amp;quot;The Case against Education&amp;quot; -- education is 1/3rd signaling, 1/3rd ability bias, 1/3rd human capital growth&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://astralcodexten.substack.com/p/your-book-review-the-educated-mind&quot;&gt;Your Book Review: The Educated Mind&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.theintrinsicperspective.com/p/why-we-stopped-making-einsteins?s=w&quot;&gt;Why we stopped making Einsteins (part 1 of 3)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.theintrinsicperspective.com/p/follow-up-why-we-stopped-making-einsteins&quot;&gt;Objections to the importance of aristocratic tutoring (part 2 of 3)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.theintrinsicperspective.com/p/how-geniuses-used-to-be-raised&quot;&gt;How geniuses used to be raised (part 3 of 3)&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>How to increase brain plasticity for language learning</title>
    <link href="https://lieuzhenghong.com/language_learning_brain_plasticity/"/>
    <updated>2023-06-27T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/language_learning_brain_plasticity/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104&quot;&gt;Critical Periods in Speech Perception&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;![[Screenshot_2023-06-27-07-17-56-532_org.mozilla.firefox.jpg]]&lt;/p&gt;
&lt;h2 id=&quot;reopening-critical-periods&quot; tabindex=&quot;-1&quot;&gt;REOPENING CRITICAL PERIODS&lt;/h2&gt;
&lt;p&gt;A continuing question is whether the age-related changes in phonetic perception involve a full loss of sensitivity. Those consonant contrasts that show the most robust evidence of perceptual attunement in infancy—such as the English /r/-/l/ and the Hindi /d/-/D/—are the same ones that show the most resistance to training in adulthood. With systematic training, however, significant improvement on discrimination of nonnative contrasts can be induced (e.g., &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Bradlow et al. 1997&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Lively et al. 1994&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;McCandliss et al. 2002&lt;/a&gt;), particularly when feedback is provided (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Lively et al. 1994&lt;/a&gt;) or the training progresses from the easiest to the most difficult tokens (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Ingvalson et al. 2012&lt;/a&gt;). Although training seldom leads to improvements to the level of native speakers (e.g., &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Bradlow et al. 1997&lt;/a&gt;), there are large individual differences in performance following training (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;McCandliss et al. 2002&lt;/a&gt;), with one predictor of success the thickness of white matter tracts in Heschl&#39;s gyrus in the left hemisphere (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Golestani et al. 2007&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Animal models now indicate that the mature brain is intrinsically plastic and actively stabilized by a variety of brake-like factors in adult life (see &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;&lt;strong&gt;Table 1&lt;/strong&gt;&lt;/a&gt;). As a result, it is possible to reopen CP levels of plasticity by judicious lifting of these brakes. Two potent pathways by which to do this involve focused attention and &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#dl1&quot;&gt;epigenetics&lt;/a&gt; (turning on or off genes), both of which can reestablish the E-I balance necessary for opening plasticity (see sidebar for further details). In the past, we would have explained the improvements in nonnative speech perception in adults as evidence that the CP had never fully closed and/or that there was thus some residual plasticity. Today we can investigate an equally plausible explanation: The training regimens that are most effective work by activating biological processes that remove molecular brakes.&lt;/p&gt;
&lt;p&gt;The action of neuromodulators (such as the serotonin and nicotinic acetylcholine receptor signaling onto particular GABA neurons) acutely regulates E-I balance (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Lee et al. 2010&lt;/a&gt;), effectively disinhibiting the local circuitry to enable adult learning (Brown et al. 2012, Donato et al. 2013, Letzkus et al. 2011). In adult barn owls, active hunting can extend CP plasticity (Bergan et al. 2005). Video games are particularly potent in engaging attentional mechanisms, which can be leveraged for enhanced learning (Bavelier &amp;amp; Davidson 2013). Highly engaging learning situations similarly may be more effective in improving speech perception in adults.&lt;/p&gt;
&lt;p&gt;Stimulation of the basal forebrain or vagus nerve raises neuromodulatory tone to produce CP plasticity in adult A1 (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Engineer et al. 2011&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Kilgard &amp;amp; Merzenich 1998&lt;/a&gt;) sufficient to correct a rodent model of tinnitus. In V1, the Lynx1 protein was further identified as a brake-like factor that actively suppresses adult plasticity (see sidebar) (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Morishita et al. 2010&lt;/a&gt;). Genetic removal of Lynx1 or acetylcholinesterase inhibitor treatment of adult wild-type animals restores CP plasticity, enabling recovery from amblyopia in adulthood. Likewise, phase 2 clinical trials with SRIs are proceeding for the treatment of amblyopia, as these drugs were found to rescue amblyopia in a rodent model by acutely perturbing E-I balance, perhaps epigenetically (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Maya Vetencourt et al. 2008&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;2011&lt;/a&gt;). Interestingly, contemplative practices to focus attention may also achieve plasticity enhancement noninvasively by engaging neuromodulatory systems (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Slagter et al. 2011&lt;/a&gt;) as well as by producing epigenetic changes (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Kaliman et al. 2014&lt;/a&gt;). This is another area for future study.&lt;/p&gt;
&lt;p&gt;Epigenetic signatures such as DNA methylation, histone acetylation, and phosphorylation accompany the closure of CPs (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Putignano et al. 2007&lt;/a&gt;). Thus, treating adult rodents with HDAC inhibitors such as valproic acid alters preference to paired acoustic stimuli (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Yang et al. 2012&lt;/a&gt;) or reopens plasticity and rescues amblyopia in V1 (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Silingardi et al. 2010&lt;/a&gt;). The same valproic acid treatment of healthy young adult humans enables the acquisition of absolute pitch, again when trained concurrently (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Gervain et al. 2013&lt;/a&gt;). Elimination of inhibitory synapses is a major component of adult visual plasticity (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Takesian &amp;amp; Hensch 2013&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;van Versendaal et al. 2012&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As noted at the beginning of this review, language is one of the few complex cognitive systems for which CPs exist. This may have implications for when and whether training of speech sound discrimination can improve language use. To date, the improvements reported at the level of speech sound (phonetic) discrimination seldom generalize to new syllables or new speakers (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Ingvalson et al. 2011&lt;/a&gt;). Moreover, even when nonnative phonetic sensitivities improve with training, deficits still exist in how well the retrained categories facilitate the recognition of words in continuous speech (e.g., &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Pallier et al. 1997&lt;/a&gt;). In animal model work, prolonged sensory deprivation (such as dark rearing or white noise in adulthood) has been shown to change the E-I balance and reopen plasticity (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Duffy &amp;amp; Mitchell 2013&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;He et al. 2006&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Zhou et al. 2011&lt;/a&gt;). It remains to be determined whether comparable manipulations would similarly reopen CPs in language acquisition, but it is a theoretical possibility. Moreover, since input at all levels of the language system—not just phonetic perception—would be removed, perhaps higher-level use of speech perception sensitivities would also improve.&lt;/p&gt;
&lt;h2 id=&quot;conclusions-and-future-directions&quot; tabindex=&quot;-1&quot;&gt;CONCLUSIONS AND FUTURE DIRECTIONS&lt;/h2&gt;
&lt;p&gt;In summary, infants begin life with a set of perceptual biases, learning mechanisms, and neural systems that orients them to language, provides an initial foundation for categorization, and allows them to learn the properties of the native language. Infants become attuned to these properties in a sequential fashion, beginning with the most global prosodic characteristics of the native language and eventually reaching to detailed phonetic analysis. In at least some cases, the timing of attunement appears to be under maturational control, suggesting the operation of a critical or sensitive period. The perceptual attunement to native language characteristics supports acquisition of the relevant structures, for example, of cues to word order or of word-meaning mappings. Moreover, attunement of the properties at each tier enables more focused attention to the next level of specificity.&lt;/p&gt;
&lt;p&gt;It is often claimed that because there is lifetime plasticity, CPs are moot—but that misses the point. There are biologically verifiable CPs beyond which the brain works hard to maintain stability. By understanding the processes that function to maintain stability (molecular brakes), we may figure out how to remove those brakes and reopen plasticity. The opening and closing of a CP is like opening and then locking a door. Once a key is turned or a combination set, the door is locked. However, if one has the key or knows the combination, the door can be unlocked. The exciting work in neurobiology over the past 15 years has shed light on how that unlocking is done (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Takesian &amp;amp; Hensch 2013&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;New advances have brought within reach a more objective mechanistic definition of CP timing as a consequence of maturational state. Future directions include the combination of animal models with human work, as illustrated above. For example, despite the long-postulated parallels of birdsong and human language acquisition (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Doupe &amp;amp; Kuhl 1999&lt;/a&gt;), only recently has mechanistic work been done with respect to CPs (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Balmer et al. 2009&lt;/a&gt;). In the barn owl system, incremental training is effective in producing cumulative large changes in auditory maps (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Linkenhoker &amp;amp; Knudsen 2002&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In addition, one can now carefully examine human populations with molecular markers in mind (see &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;&lt;strong&gt;Table 1&lt;/strong&gt;&lt;/a&gt;). Methods borrowed from experimental neuroscience, such as serendipitous pharmacology or epigenetic profiling, can be applied to track the trajectory of human language acquisition. Notably, many mental illnesses that include language impairment—such as schizophrenia and autism—are of neurodevelopmental origin and share defects in the triggers and brakes that normally regulate CP timing (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Gogolla et al. 2009&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Insel 2010&lt;/a&gt;, &lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Rubenstein &amp;amp; Merzenich 2003&lt;/a&gt;). Interventions to restore CP mistiming are starting to yield promising therapeutic strategies in animal models (&lt;a href=&quot;https://www.annualreviews.org/doi/full/10.1146/annurev-psych-010814-015104#&quot;&gt;Gogolla et al. 2014&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;In summary, in this article we have reviewed recent work on CPs in speech perception development within the mechanistic framework of understanding how sensory CPs work at a biological level. We are hopeful that by bringing new insights from neuroscience to one of the longest-standing debates in the language acquisition field, we can move beyond old strictures to better position scientists and clinicians across fields to gain a deeper understanding of how language development unfolds and to implement more effective interventions when development goes awry.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Georgism in Singapore</title>
    <link href="https://lieuzhenghong.com/georgism-in-singapore/"/>
    <updated>2023-06-24T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/georgism-in-singapore/</id>
    <content type="html">&lt;p&gt;https://progressandpoverty.substack.com/p/singapore-economic-prosperity-through&lt;/p&gt;
&lt;p&gt;https://ink.library.smu.edu.sg/cgi/viewcontent.cgi?article=1006&amp;amp;context=soe_research&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Guerilla Gardening</title>
    <link href="https://lieuzhenghong.com/guerilla_gardening/"/>
    <updated>2023-06-04T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/guerilla_gardening/</id>
    <content type="html">&lt;p&gt;Idea of guerilla gardening is to plant shit wherever without soliciting the permission of the government or city council or whatever. Just plant stuff, let it grow, eat some papaya. You&#39;d be surprised at how much shit grows in a small space.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Joy</title>
    <link href="https://lieuzhenghong.com/joy/"/>
    <updated>2023-05-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/joy/</id>
    <content type="html">&lt;p&gt;Eight years ago I read &lt;em&gt;Anna Karenina&lt;/em&gt; in a cold and dark storeroom. I don&#39;t remember the plot exactly now, but I remember how I felt. I remember it gripped me from start to end. I remember viscerally feeling Anna&#39;s aching passion and her pain, and when I read that final, climactic scene, it felt like a train had hit me, too. I read that part a dozen times, reliving it again and again before I had to put the book down. I felt a sickening sense of loss. My heart pounded hard and my chest felt incredibly tight, stretched taut almost to breaking underneath my admin tee. Jaye and Benny were only inches away from me. But in that moment I felt incredibly distant, my mind and body transported to a time long ago, a place far away. Reading that book gave me joy.&lt;/p&gt;
&lt;p&gt;I took many modules in college, and enjoyed all of them. Learning new things gave me joy. I enjoyed working through particularly tricky proofs in Logic, Analysis, and Game Theory. I enjoyed very much thinking through Berlin and Nozick. I worked hardest for PolSoc and my thesis. I remember lying on the couch in the PPE room with my feet up and my eyes closed, thinking very hard in my repose. I&#39;d fill the whiteboard with papers, summaries, regression equations. Occasionally I&#39;d sneak a peek at Julia Stadlmann--hard at work with some derivation or other--and sometimes she&#39;d catch me and grace me with a smile and giggle. That gave me joy. I enjoyed parking the disparate readings into different camps, finding methodological errors in the papers, and finally synthesising everything into a theory of my own. I came to every insight with nothing but the Feynman method, and that exercise of my mental faculties gave me joy.&lt;/p&gt;
&lt;p&gt;I talked to so many people about my thesis, who lavished me with help I didn&#39;t deserve. I was in Tak Huen&#39;s attic room. I was in the common room of 59 with Filip, Nina, and Martin. I was in Bassel&#39;s garden, talking until the sun went down. I was in Nuffield quad and Andy&#39;s office. I was in my room writing code until the sunrise. All of that was pain, uncertainty, and stress. But at the end, when the results aligned almost exactly with my predictions, I felt that I had discovered some truth about the world. A contingent, &lt;em&gt;a posteriori&lt;/em&gt;, wishy-washy sort of truth, but a truth nonetheless. That gave me joy. And I felt unadulterated joy when Celine and I received our results atop Kühlenbronn, with the sun in our eyes and the cool mountain air in our lungs.&lt;/p&gt;
&lt;p&gt;Last year I started playing frisbee. Why do I play it? It keeps me fit and lets me meet new people, but those reasons are only incidental. I play for the brute joy of running down the field as quickly as I can and jumping as high as I can. That raw exercise of my physical capacities is joyful to me. There is beauty in the game too, which I&#39;m starting to appreciate. There is beauty when a play is executed nicely, when the disc moves swiftly from strike to strike and then put nicely and cleanly to score in the endzone. There is beauty when someone reads the disc so well that he grabs it out perfectly from two defenders. Those things give me joy.&lt;/p&gt;
&lt;p&gt;Some time ago I had my heart broken. We spent one intimate and vulnerable night together. That gave me joy. Then I spent many sleepless nights alone feeling pain, anguish, and overall very sorry for myself. But I felt like I hadn&#39;t felt in years--a full-bodied, hot-blooded grief--and that gave me joy too.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>On Tiktok and Instagram Reels</title>
    <link href="https://lieuzhenghong.com/tiktok/"/>
    <updated>2023-05-14T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/tiktok/</id>
    <content type="html">&lt;p&gt;Last night a friend showed me her Instagram DMs. Too many of her conversations were reels back and forth punctuated by a few words of filler reaction (&amp;quot;lol&amp;quot;, &amp;quot;HAHAHAHAHA&amp;quot;, &amp;quot;very cool&amp;quot;, etc). How could it be otherwise? There are no scintillating rejoinders to a tiktok where someone is pulling funny faces while making a very large portion of food.&lt;/p&gt;
&lt;p&gt;It is good to share Internet stuff with one&#39;s friends. But these tiktoks are so vacuous that they terminate thought instead of sparking discussion. They are the 2020s version of an MSN nudge or a Facebook poke: they contain the form of a message, but have none of the substance, like biting into a xiaolongbao and getting only air.&lt;/p&gt;
&lt;p&gt;A conversation of reels is a poor substitute for an actual one. It&#39;s become far too easy to ping-pong Tiktoks back and forth; far too easy to shirk the work of having real conversations with the people you love.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Using technology to aid language learning</title>
    <link href="https://lieuzhenghong.com/language_learning_with_ai/"/>
    <updated>2023-04-23T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/language_learning_with_ai/</id>
    <content type="html">&lt;p&gt;Some scattered thoughts on how we can use technology to build something 100x better for language learning&lt;/p&gt;
&lt;h2 id=&quot;chatgpt-can-act-as-a-native-speaker&quot; tabindex=&quot;-1&quot;&gt;ChatGPT can act as a native speaker&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-45-17.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-45-53.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-45-58.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-46-02.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-46-06.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-46-10.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;chatgpt-can-give-you-exercises&quot; tabindex=&quot;-1&quot;&gt;ChatGPT can give you exercises&lt;/h2&gt;
&lt;p&gt;Here is ChatGPT&lt;/p&gt;
&lt;p&gt;Prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;German Konjunctiv II practice

I would like to practice the German Konjunctiv II mood, and I would like you to be my helpful and knowledgeable German tutor. I would like you to give me a sentence in English, and grade me on my translation. The sentences you give me should use the Konjunctiv II mood.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-51-55.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;German Reflexive Verb Practice

I am looking to practice German reflexive verbs. I would like you to give me a reflexive verb in German, with an example English sentence using the verb. I should translate the sentence into German correctly.

An example:

Reflexive verb: sich freuen (to be happy)
English sentence: I am happy because I have a party on the weekend.

You should wait for me to give you my attempt at translating the sentence to English before you give me the correct German translation.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/2023-04-17-14-52-30.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-proper-dictionary-extension-and-flashcard-capturing-extension&quot; tabindex=&quot;-1&quot;&gt;A proper dictionary extension and flashcard capturing extension&lt;/h2&gt;
&lt;p&gt;Idea: something that allows you to highlight any word or phrase, and it automatically looks up dict.cc&lt;/p&gt;
&lt;p&gt;also it should give you the option to translate it automatically and capture it into a flashcard deck. maybe even do text-to-speech&lt;/p&gt;
&lt;h2 id=&quot;snip-video-fragments-and-put-them-into-flashcards%3F%3F&quot; tabindex=&quot;-1&quot;&gt;snip video fragments and put them into flashcards??&lt;/h2&gt;
&lt;p&gt;idk&lt;/p&gt;
&lt;h2 id=&quot;ai-generated-flashcards&quot; tabindex=&quot;-1&quot;&gt;AI-generated flashcards&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>Improving the site (2023)</title>
    <link href="https://lieuzhenghong.com/revamping-the-site-again/"/>
    <updated>2023-04-08T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/revamping-the-site-again/</id>
    <content type="html">&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#removed-github-pages-actions%2C-moved-to-vercel&quot;&gt;Removed Github Pages Actions, moved to Vercel&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#add-encryption-for-private-posts&quot;&gt;Add encryption for private posts&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#spring-cleaning-cruft&quot;&gt;Spring cleaning cruft&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#updating-old-descriptions&quot;&gt;Updating old descriptions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/revamping-the-site-again/#what&#39;s-next%3F&quot;&gt;What&amp;#39;s next?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;I have been making new posts regularly, but haven&#39;t changed either the design or the backend of the website &lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/&quot;&gt;since 2020&lt;/a&gt;. Time flies!
I wanted to do it &lt;a href=&quot;https://lieuzhenghong.com/site_redesign_2022/&quot;&gt;back in 2022&lt;/a&gt; but 2022 was a very busy year for me. Thankfully things are less hectic now.&lt;/p&gt;
&lt;h1 id=&quot;removed-github-pages-actions%2C-moved-to-vercel&quot; tabindex=&quot;-1&quot;&gt;Removed Github Pages Actions, moved to Vercel&lt;/h1&gt;
&lt;p&gt;It was taking upwards of 20 minutes for any change to reflect on my website after I pushed the changes. It turned out that Github Actions save something called an artifact, which took a long time (~10 minutes!) given my many huge files in the repo.&lt;/p&gt;
&lt;p&gt;Serving purely static files shouldn&#39;t take anywhere near that long. I switched to Vercel instead, now it builds in seconds.
I&#39;m still using GitHub Actions to run eleventy build and encryption (see next section)&lt;/p&gt;
&lt;h1 id=&quot;add-encryption-for-private-posts&quot; tabindex=&quot;-1&quot;&gt;Add encryption for private posts&lt;/h1&gt;
&lt;p&gt;I used to keep private posts up, but events transpired that made this no longer a good idea. I took them down for over 2 years but was always looking for a way to keep them up with password protection. (see my 2022 post). I&#39;d been thinking of a way to do client-side encryption. Two months ago I found &lt;a href=&quot;https://news.ycombinator.com/item?id=34849024&quot;&gt;a HN post&lt;/a&gt; doing exactly that -- and I finally took the time to set up use &lt;a href=&quot;https://github.com/Greenheart/pagecrypt&quot;&gt;pagecrypt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tag private posts in the front matter with &lt;code&gt;tags: [&amp;quot;private&amp;quot;, &amp;quot;bla&amp;quot;, bleh]&lt;/code&gt;. The compiled &lt;code&gt;.html&lt;/code&gt; file results in an anchor element &lt;code&gt;&amp;lt;a href=&amp;quot;/tags/ private&amp;quot;&amp;gt; private &amp;lt;/a&amp;gt;&lt;/code&gt;. I grep for this and password-protect it with &lt;code&gt;npx pagecrypt&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I have a &lt;code&gt;passwords.txt&lt;/code&gt; file that lets me set a different password for each file, with a default password as fallback:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;default: wouldnt_you_like_to_know
_site/test_private_post/index.html: hunter2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I add the following action after &lt;code&gt;npx eleventy&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;password_file&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;passwords.txt&quot;&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;default_password&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^default: &quot;&lt;/span&gt; $password_file &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39; &#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token for-or-select variable&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rl&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/tags/ private&quot;&lt;/span&gt; _site&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;token assign-left variable&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^&lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt;: &quot;&lt;/span&gt; $password_file &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39; &#39;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$password&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
        npx pagecrypt &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$password&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--iterations&lt;/span&gt; 2e6
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        npx pagecrypt &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$filename&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$default_password&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--iterations&lt;/span&gt; 2e6
    &lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;done&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check it out -- &lt;a href=&quot;https://lieuzhenghong.com/test_private_post/&quot;&gt;a super private post&lt;/a&gt;. The password is definitely not &lt;code&gt;hunter2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is kind of a hack because I&#39;m relying on the final &lt;code&gt;.html&lt;/code&gt; file output having the text string &lt;code&gt;/tags/ private&lt;/code&gt; in it.
Additionally, any post that mentions &lt;code&gt;/tags/ private&lt;/code&gt; will be password protected. So I&#39;ve made sure to put a space here.
This will change if I change the layout of my Nunjucks post template in the future. I&#39;ll keep looking for more elegant solutions.&lt;/p&gt;
&lt;h1 id=&quot;spring-cleaning-cruft&quot; tabindex=&quot;-1&quot;&gt;Spring cleaning cruft&lt;/h1&gt;
&lt;p&gt;This website has been up at the same website since 2016 -- that&#39;s seven years now. I&#39;m glad to have maintained continuity of the site, but there&#39;s a lot of cruft accumulated over the years. e.g. lots of orphan tags, weird bash scripts, commented out code, code in eleventy.js that I&#39;m not sure does anything.&lt;/p&gt;
&lt;p&gt;I moved/deleted/cleaned up various files.&lt;/p&gt;
&lt;h1 id=&quot;updating-old-descriptions&quot; tabindex=&quot;-1&quot;&gt;Updating old descriptions&lt;/h1&gt;
&lt;p&gt;I cleaned up some of the old descriptions, updating the About and Resume pages.&lt;/p&gt;
&lt;h1 id=&quot;what&#39;s-next%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s next?&lt;/h1&gt;
&lt;p&gt;Not sure. I think there&#39;s more cruft I can slowly clean up. Does the website design look dated?
I want to implement full text search eventually. &lt;a href=&quot;https://lucaongaro.eu/blog/2019/01/30/minisearch-client-side-fulltext-search-engine.html&quot;&gt;Minisearch&lt;/a&gt;, &lt;a href=&quot;https://lunrjs.com/&quot;&gt;Lunr&lt;/a&gt; and &lt;a href=&quot;https://fusejs.io/&quot;&gt;Fuse.js&lt;/a&gt; are good candidates.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to draw isometric cubes with Javascript and HTML canvas</title>
    <link href="https://lieuzhenghong.com/isometric_cubes/"/>
    <updated>2023-03-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/isometric_cubes/</id>
    <content type="html">&lt;p&gt;How do you draw isometric tiles on a HTML canvas element?&lt;/p&gt;
&lt;p&gt;&lt;canvas id=&quot;game&quot; width=&quot;300&quot; height=&quot;500&quot;&gt;&lt;/canvas&gt;&lt;/p&gt;
&lt;script&gt;
  let Game = document.getElementById(&quot;game&quot;);
  Game.ctx = Game.getContext(&quot;2d&quot;);
  class IsoRect {
    constructor(settings) {
      this.position = settings.position;
      this.width = settings.width;
      this.height = settings.height;
      this.direction = settings.direction;
      this.color = settings.color;
      this.angle = settings.angle ? settings.angle : 30
    }
    render() {
      Game.ctx.save();
      Game.ctx.fillStyle = this.color;
      const angle = (Math.PI / 180) * this.angle;
      Game.ctx.translate(
        this.position[0] + this.width / 2,
        this.position[1] + this.height / 2,
      );
      if (this.direction === &quot;side&quot;) {
        Game.ctx.rotate(angle);
        Game.ctx.transform(1, 0, Math.tan(angle), 1, 0, 0);
        Game.ctx.scale(1, Math.cos(angle));
      } else if (this.direction === &quot;front&quot;) {
        // front
        Game.ctx.rotate(-angle);
        Game.ctx.transform(1, 0, Math.tan(angle * -1), 1, 0, 0);
        Game.ctx.scale(1, Math.cos(angle));
      } else {
        // plant
        Game.ctx.rotate(angle);
        Game.ctx.transform(1, 0, Math.tan(angle * (90-this.angle*2) / this.angle *  -1), 1, 0, 0);
        Game.ctx.scale(1, Math.cos(angle));
      }
      Game.ctx.translate(
        -(this.position[0] + this.width / 2),
        -(this.position[1] + this.height / 2),
      );
      Game.ctx.fillRect(
        this.position[0],
        this.position[1],
        this.width,
        this.height,
      );
      Game.ctx.restore();
    }
  }

  new IsoRect({
    position: [100, 100],
    width: 100,
    height: 100,
    direction: &quot;side&quot;,
    color: &quot;red&quot;,
    angle: 26.5,
  }).render();
  new IsoRect({
    position: [188, 100],
    width: 100,
    height: 100,
    direction: &quot;front&quot;,
    color: &quot;tomato&quot;,
    angle: 26.5,
  }).render();
  new IsoRect({
    position: [144, 33],
    width: 100,
    height: 90,
    direction: &quot;plant&quot;,
    color: &quot;orange&quot;,
    angle: 26.5,  
  }).render();


  new IsoRect({
    position: [100, 305],
    width: 100,
    height: 100,
    direction: &quot;side&quot;,
    color: &quot;red&quot;,
  }).render();
  new IsoRect({
    position: [186, 305],
    width: 100,
    height: 100,
    direction: &quot;front&quot;,
    color: &quot;tomato&quot;,
  }).render();
  new IsoRect({
    position: [143, 230],
    width: 100,
    height: 100,
    direction: &quot;plant&quot;,
    color: &quot;orange&quot;,
  }).render();
&lt;/script&gt;
&lt;p&gt;A great first resource is &lt;a href=&quot;https://nicoguaro.github.io/posts/isometric_inkscape/&quot;&gt;Isometric graphics in Inkscape&lt;/a&gt; from Nicolás Guarín-Zapata&#39;s blog, but that&#39;s not going to work as-is for canvas. The difference is that in Inkscape you&#39;re drawing the square on the canvas before you make the transformations, but in HTML Canvas you&#39;re transforming the canvas first before you draw the square.&lt;/p&gt;
&lt;p&gt;There are several key modifications you need to make:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Do the reverse of what&#39;s mentioned in the blog post: rotate, transform, then scale, in that order. This is because the complete transformation matrix is given by&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mtext&gt;complete&lt;/mtext&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mtext&gt;rotation&lt;/mtext&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mtext&gt;skew&lt;/mtext&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mtext&gt;scaling&lt;/mtext&gt;&lt;/msub&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;M_{\textrm{complete}} = M_{\textrm{rotation}} M_{\textrm{skew}} M_{\textrm{scaling}}.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9694em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord text mtight&quot;&gt;&lt;span class=&quot;mord textrm mtight&quot;&gt;complete&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9694em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3175em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord text mtight&quot;&gt;&lt;span class=&quot;mord textrm mtight&quot;&gt;rotation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord text mtight&quot;&gt;&lt;span class=&quot;mord textrm mtight&quot;&gt;skew&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord text mtight&quot;&gt;&lt;span class=&quot;mord textrm mtight&quot;&gt;scaling&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You need to translate the canvas such that it&#39;s centered on your square before rotating and skewing. In HTML canvas the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/rotate&quot;&gt;&lt;code&gt;CanvasRenderingContext2D.rotate()&lt;/code&gt;&lt;/a&gt; function the center of rotation is the top-left corner of the canvas and not a location relative to any shape.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will have to play around with the positions and sizes of the faces if you want them to line up properly. I don&#39;t really understand exactly how
In addition, note the skew transform for angle that are not 30 degrees. The transform should be &lt;code&gt;Math.tan(angle * (90-this.angle*2) / this.angle *  -1)&lt;/code&gt;, not simply &lt;code&gt;Math.tan(angle * -1)&lt;/code&gt;. 30 degrees is a special case. This is useful for e.g. playing nicely with isometric pixel art assets that &lt;a href=&quot;https://pixelparmesan.com/fundamentals-of-isometric-pixel-art/&quot;&gt;usually use a 26.5 degree angle&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Source code for the example above:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;canvas id&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;game&quot;&lt;/span&gt; width&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;300&quot;&lt;/span&gt; height&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;500&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;canvas&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; Game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;game&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;direction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;direction&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; settings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; angle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;180&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;direction &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;side&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;direction &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;front&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// front&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// plant&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angle &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;angle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;position&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      Game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;restore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;side&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;188&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;front&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tomato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;144&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;orange&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;angle&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;305&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;side&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;186&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;305&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;front&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tomato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsoRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;230&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plant&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;orange&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Can NFTs be used to fund art?</title>
    <link href="https://lieuzhenghong.com/nfts_and_public_goods/"/>
    <updated>2023-01-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/nfts_and_public_goods/</id>
    <content type="html">&lt;p&gt;Imagine you&#39;re an artist who&#39;s just created a piece of art--say, a novel. You&#39;d like this piece of art to be enjoyed by people around the world, but at the same time, you need money to eat. The way you&#39;d normally square this circle  is to publish the novel and gate access to it, e.g. sell the eBook for $10, the paperback for $20, and only the people who have bought the book can read it.&lt;/p&gt;
&lt;p&gt;That&#39;s the normal approach. Can we do something different? Here&#39;s a crazy thought: distribute the work completely free. Let anyone read it, make copies of it, send it to their friends, whatever. Let the work spread as widely as possible. &lt;em&gt;Then,&lt;/em&gt; create a golden plaque signed by you, the artist (or maybe a signed copy of a gilded hardback version, whatever strikes your fancy). Then auction it off to the highest bidder.&lt;/p&gt;
&lt;p&gt;The question is: would this work? Would this make the artist any money? Better yet, could an artist make more money under this &lt;em&gt;post-hoc&lt;/em&gt; auction model compared to the regular model?&lt;/p&gt;
&lt;p&gt;The auction approach seems quite compelling. As an artist, I&#39;d want my work to be accessible to as many people as possible. I wouldn&#39;t want to deny others the pleasure of experiencing my work by gating it off -- especially when it costs me nothing to give someone a copy of an eBook or a JPEG. At the same time, though, I&#39;d be really worried that the auction model wouldn&#39;t work; that nobody would pay me fairly for my work, that I wouldn&#39;t recoup the costs associated with the production of the work. So I&#39;d need to be seriously convinced that I could make as much -- if not more -- money under the auction model.&lt;/p&gt;
&lt;p&gt;I worked with Bassel to create a toy economic model of how this could work.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Protocols for optimal health</title>
    <link href="https://lieuzhenghong.com/health/"/>
    <updated>2023-01-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/health/</id>
    <content type="html">&lt;h2 id=&quot;sleep&quot; tabindex=&quot;-1&quot;&gt;Sleep&lt;/h2&gt;
&lt;p&gt;Entrain circadian clock with as much light as possible in the day, and avoid light as much as possible at night&lt;/p&gt;
&lt;p&gt;Light entrainment happens solely in the upper visual field -- extraocular light perception does not exist.&lt;/p&gt;
&lt;p&gt;Get light in the upper visual field.&lt;/p&gt;
&lt;h2 id=&quot;exercise&quot; tabindex=&quot;-1&quot;&gt;Exercise&lt;/h2&gt;
&lt;p&gt;To be maximally healthy, we should have long duration steady state cardio, short and intense maximal heart rate cardio, and resistance training.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;180 minutes of Zone 2 cardio&lt;/li&gt;
&lt;li&gt;30 minutes of maximal HR cardio (certainly not sustained)&lt;/li&gt;
&lt;li&gt;Resistance training&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The primary driver of muscle hypertrophy is mechanical tension. Your muscles have to produce force to overcome a weight. By Newton&#39;s Third Law, a force likewise acts on your muscles. The cells in your body ha&lt;/p&gt;
&lt;p&gt;&amp;quot;mechanotransduction&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2043154/&quot;&gt;Burkholder (2007). Mechanotransduction in skeletal muscle&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There&#39;s some evidence that loading the muscle (ergo forcing it to produce force) in a stretched position (e.g. when the muscle is at its longest)&lt;/p&gt;
&lt;h2 id=&quot;nutrition&quot; tabindex=&quot;-1&quot;&gt;Nutrition&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>Optimising my onebag</title>
    <link href="https://lieuzhenghong.com/optimising-my-onebag/"/>
    <updated>2022-12-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/optimising-my-onebag/</id>
    <content type="html">&lt;h1 id=&quot;things-to-remove&quot; tabindex=&quot;-1&quot;&gt;Things to remove&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Timberland boots: Too heavy, can be replaced with something a bit more minimalistic, even for Iceland / really cold weather.&lt;/li&gt;
&lt;li&gt;Uniqlo cargo pants: Too heavy of a weight, not necessary, and replaced with the water resistant pants anyway.
&lt;ul&gt;
&lt;li&gt;In future, wear 1 pair of pants, pack 1 pair of pants, so I&#39;ll just go with grey slacks plus gray water resistant pants&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Toiletries: Carrying way too much soap/shampoo, I&#39;ll just use one bar of soap for everything in the future.&lt;/li&gt;
&lt;li&gt;IMDA green bomber jacket: Actually quite decent, dresses up nicely, but doesn&#39;t have much warmth at all, I feel like almost always i&#39;d rather wear the UL down or an outer layer rather than this.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;things-to-add&quot; tabindex=&quot;-1&quot;&gt;Things to add&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;The weird rubber thingys that let you strap stuff to the outside of the onebag that I saw in a Reddit post somewhere&lt;/li&gt;
&lt;li&gt;Sunscreen&lt;/li&gt;
&lt;li&gt;Button-up shirt: Get something nice enough to wear to formal dinners, but also casual enough to wear on its own, probably some sort of Merino wool shirt&lt;/li&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;something long sleeve, light, breezy, can&#39;t be linen because that doesnt look formal enough? and it cannot ever wrinkle&lt;/li&gt;
&lt;li&gt;does such a thing even exist???&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sandals/slippers: Something open-toed, but with straps, used for lounging round the beach, walking around indoors, minimalist hiking/walking.&lt;/li&gt;
&lt;li&gt;Phone case/stand of some sort: To prop up phone so I can have a more comfortable viewing angle when working on the go.&lt;/li&gt;
&lt;li&gt;Bluetooth mouse. Not strictly necessary but it&#39;s a bit annoying to have to tap the screen of my phone to click stuff. Also useful for laptop obviously.&lt;/li&gt;
&lt;li&gt;Cap/hat/visor (for hot weather): Something to keep the sun out of my eyes, good for walking on sunny days, Frisbee, etc.&lt;/li&gt;
&lt;li&gt;Gloves: Not super pressing this time of year, but look out for a good, lightweight pair that works with touchscreens.
&lt;ul&gt;
&lt;li&gt;I DEFINITELY needed gloves for skiing, and those gloves are bulky AF -- don&#39;t think they can fit in a onebag. Maybe Arcteryx or Patagonia sells some UL versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Merino buff: I see this recommended all the time on r/onebag. Neck and head protection for the cold, and even potentially the heat (avoid sunburn), impromptu sleep mask, face mask.&lt;/li&gt;
&lt;li&gt;Sarong. This was such a good thing to wear around hostels, lounging round the house, even as an impromptu picnic mat, sunshade, etc. Thee batik pattern certainly attracted attention. Cotton isn&#39;t such a good material though, takes forever to dry (to be fair, it doesn&#39;t really have to be washed that often), maybe look for IDK, linen??&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;things-to-replace%3A&quot; tabindex=&quot;-1&quot;&gt;Things to replace:&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Laptop: Biggest win in my opinion. Really full-featured, but way too big and heavy, and battery life is now poor. But running a proper desktop OS is non-negotiable, and Windows is an additional bonus for gaming (but I do very little of this while traveling). I&#39;d like to replace it with something that has a much smaller form factor.
&lt;ul&gt;
&lt;li&gt;Ideal device is something like a tablet form factor that&#39;s
&lt;ul&gt;
&lt;li&gt;runs Linux&lt;/li&gt;
&lt;li&gt;folds into two&lt;/li&gt;
&lt;li&gt;can also be used as a portable external monitor for the phone&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Maybe some sort of foldable portable monitor with an all in one &amp;quot;PC Stick&amp;quot;, or Raspi with custom battery case, or the Framework Laptop case, idk&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Phone: It&#39;s functional, but if it were foldable and ran Linux I wouldn&#39;t need a phone at all. I&#39;ve recently been able to be more productive on the go by buying a foldable Bluetooth keyboard: small enough to pack in a coat pocket
&lt;ul&gt;
&lt;li&gt;One incredibly underrated thing about a bluetooth keyboard is that apart from allowing you to type with all ten fingers, it also effectively doubles the phone&#39;s screen real estate (since when you type on your phone half of the screen is taken up by the on-screen keyboard)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remarkable: Don&#39;t do enough reading on it, because I consume a lot of content online, and the friction of sending PDFs/eBooks to my RM is too great.
&lt;ul&gt;
&lt;li&gt;Can be changed with the right habits. Keeping for now.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Rain shell. The existing outer layer I have sucks, not waterproof at all. Thinking of getting a Arcteryx shell of some sort as an outer layer that&#39;s waterproof but also breathable with pit zips etc, using it as the only layer on warmer days and adding in Uniqlo UL Down jacket + Heattech layers in cold weather.&lt;/li&gt;
&lt;li&gt;Heattech thermal layers. Do I really need 2 pairs of each?
&lt;ul&gt;
&lt;li&gt;The thinner blue layer is quite nice for going to the gym on slightly colder days, packs small anyway, so i&#39;m fine&lt;/li&gt;
&lt;li&gt;I think the thing that takes the most space is the grey Heattech extra warm sweater layer, that one is indeed very warm, it&#39;s like a sweater of some sort almost, maybe I take it as double duty.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;maybe%3F&quot; tabindex=&quot;-1&quot;&gt;Maybe?&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Some sort of sling or hot weather vest: backpacks go on the back, hard to slip stuff in and out quickly, I have very much appreciated the deep inner pockets you get on the Uniqlo UL Down jacket.&lt;/li&gt;
&lt;li&gt;Relatedly, hot weather friendly outer shell -- UV protection, rain protection, with inner pockets and stuff, must be super breathable (pit zips are a must) maybe in a light grey colour, how do the Arcteryx stuff stack up in hot weather?&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;things-i-want-but-rejected%3A&quot; tabindex=&quot;-1&quot;&gt;Things I want but rejected:&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Cleats: Honestly this would be really nice to have to play sports but sacrifices have to be made while onebagging I guess.
&lt;ul&gt;
&lt;li&gt;Why don&#39;t they make something like detachable cleats? LOL&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Beanie: Really nice to have in cold weather, but they tend to stink because of my head oils. Find another solution.&lt;/li&gt;
&lt;li&gt;Magic TCG deck. Lol&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;other-thoughts&quot; tabindex=&quot;-1&quot;&gt;Other thoughts&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Is there an outer shell that is suitable for wearing in hot weather?? Honestly having an outer shell that&#39;s waterproof in Singapore seems like a good shout.. but full black is going to be incredibly hot, maybe some sort of grey would be better.&lt;/li&gt;
&lt;li&gt;Have been wearing the Vivobarefoot Primus Trail FG for two weeks now. Reasonably comfortable, doesn&#39;t smell (yet), have been putting it through its paces with frisbee and stuff. A bit less traction than I&#39;d like on the hard muddy grass, I&#39;ve slipped a couple of times.&lt;/li&gt;
&lt;li&gt;Haven&#39;t found any use for the big metal container that I bought in Iceland, it is really nice that it&#39;s metal so you can heat it up, store hot food in it etc, but it just takes up so much bulk. I suppose I can use it as a container to store like idk, socks or underwear or something?&lt;/li&gt;
&lt;li&gt;What do I do with the metal crampons that I bought, they are so heavy and useful for only one specific thing (hiking in Iceland in winter/spring). This is more general question that is worth considering: what do you do with all the one-use stuff you need for a specific usecase, can&#39;t keep bringing that stuff with you&lt;/li&gt;
&lt;li&gt;The fanny pack is great, keeps all my stuff with me safe and sound, no complaints there. Good buy.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>My &quot;indefinite&quot; onebag setup</title>
    <link href="https://lieuzhenghong.com/onebag/"/>
    <updated>2022-12-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/onebag/</id>
    <content type="html">&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/new_ways_of_living_and_working/&quot;&gt;Radically new ways of living and working are for the first time available to us&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/six-months-on-the-road/&quot;&gt;Six months on the road&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/optimising-my-onebag/&quot;&gt;Optimising my onebag&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Der Schatz von Hiddensee</title>
    <link href="https://lieuzhenghong.com/der_schatz_von_hiddensee/"/>
    <updated>2022-10-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/der_schatz_von_hiddensee/</id>
    <content type="html">&lt;h1 id=&quot;%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60%60&quot; tabindex=&quot;-1&quot;&gt;`````````````````````&lt;/h1&gt;
&lt;p&gt;Der Schatz von Hiddensee&lt;/p&gt;
&lt;h2 id=&quot;winterferien&quot; tabindex=&quot;-1&quot;&gt;Winterferien&lt;/h2&gt;
&lt;p&gt;&amp;quot;Annika, bist du fertig? Wir warten auf dich!&amp;quot;&lt;/p&gt;
&lt;p&gt;Familie Sonntag will in Urlaub fahren. Die Koffer sind schon im Auto, aber Annika ist noch nicht da.&lt;/p&gt;
&lt;p&gt;&amp;quot;Ja, ich komme gleich. Ich shreibe nur noch schnell eine SMS an Nora!&amp;quot;, ruft Annika.&lt;/p&gt;
&lt;p&gt;&amp;quot;Das kannst du auch im Auto machen! Komm, wir wollen fahren. Deine Schwester wartet schon auf uns.&amp;quot;&lt;/p&gt;
&lt;p&gt;Nora ist Annikas ältere Schwester. Sie ist Studentin in Greifswald. Alle haben Ferien und wollen zusammen auf der Insel Hiddensee Urlab machen. Familie Sonntag wohnt in Dresden. Sie fahren mit dem Auto über die Autobahn in Richtung Berlin und dann weiter nach Greifswald. Da holen sie Nora ab und fahren dann zusammen weiter an die Ostsee.&lt;/p&gt;
&lt;p&gt;&amp;quot;Mama, wie lange fahren wir denn bis Greifswald?&amp;quot; will Annika wissen, als sie im Auto sitzen und losfahren.&lt;/p&gt;
&lt;p&gt;&amp;quot;Ungefähr vier bis fünf Studen&amp;quot;, antwortet Frau Sonntag.&lt;/p&gt;
&lt;p&gt;&amp;quot;Und wie lange fahren wir dann von Greifswald bis Hiddensee?&amp;quot; fragt Annika.&lt;/p&gt;
&lt;p&gt;&amp;quot;Das dauert noch einmal ungefähr zwei oder drei Stunden&amp;quot;, sagt ihr Vater.&lt;/p&gt;
&lt;p&gt;Sie fahren durch das Zentrum von Dresden und kommen an der Frauenkirche vorbei. Die Kirche var viele Jahre eine Ruine, aber seit ein paar Jahren ist sie fertig restauriert. Es gibt viele Touristen, die die Kirche sehen wollen. Danach kommen sie an der Semperoper vorbei.&lt;/p&gt;
&lt;p&gt;&amp;quot;In die Semperoper müssen wir bald wieder gehen. Wir waren schon lange nicht mehr im Konzert&amp;quot;, sagt Herr Sonntag.&lt;/p&gt;
&lt;p&gt;&amp;quot;Stimtt, das letzte Konzert war ein Mozart-Konzert. Das war so schön!&amp;quot; erinnert sich Frau Sonntag. &amp;quot;Vielleicht gibt es ja auf Hiddensee ein klassiches Konzert. Dann können wir da alle yusammen hingehen!&amp;quot;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Aber Annika interessiert sich nicht für klassische Musik oder Opern. Sie hört lieber Popmusik. Im Sommer gibt es in Touristenorten auch Konzerte für junge Leute, aber im Winter? Da ist es sicher sehr langweillig auf der Insel. Annika freut sich nicht auf diese Ferien. Ihre Klassenkameraden fliegen auf die Kanarischen Inseln oder nach Florida oder gehen in den Alpern Skifahren. Aber ihre Familie macht Urlaub in Deutschland - auf einer Mini-Insel. Wie langweillig. Gut, dass Nora mitkommt! Vielleicht hat sie ein paar coole Ideen, was man auf der Insel so machen kann. Weil die Fahrt ein paar Stunden dauert, schaltet sie ihren MP3-Player ein. Bis sie Nora treffen, kann sie noch viele Songs hören.&lt;/p&gt;
&lt;h2 id=&quot;unterwegs-zur-insel&quot; tabindex=&quot;-1&quot;&gt;Unterwegs zur Insel&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>Farming snails in Singapore</title>
    <link href="https://lieuzhenghong.com/farming_snails_in_singapore/"/>
    <updated>2022-08-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/farming_snails_in_singapore/</id>
    <content type="html">&lt;p&gt;Bigger picture is &lt;a href=&quot;https://lieuzhenghong.com/alternative_agriculture/&quot;&gt;Alternative Agriculture&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Begg%20(2003).%20Farming%20edible%20snails--lessons%20from%20Italy.pdf&quot;&gt;Begg (2003). Farming edible snails--lessons from Italy&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Begg%20(2006).%20Free-range%20snail%20farming%20in%20Austrailia.pdf&quot;&gt;Begg (2006). Free-range snail farming in Australia&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://files.lieu.gg/docs/FAO%20(1970).%20Farming%20Snails%201.pdf&quot;&gt;FAO (1970). Farming Snails 1&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Alternative agriculture</title>
    <link href="https://lieuzhenghong.com/alternative_agriculture/"/>
    <updated>2022-08-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/alternative_agriculture/</id>
    <content type="html">&lt;h2 id=&quot;snail-farming&quot; tabindex=&quot;-1&quot;&gt;Snail farming&lt;/h2&gt;
&lt;p&gt;Also called heliciculture.
&lt;a href=&quot;https://lieuzhenghong.com/farming_snails_in_singapore/&quot;&gt;Farming snails in Singapore&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Should we bring back the triclinium?</title>
    <link href="https://lieuzhenghong.com/triclinium/"/>
    <updated>2022-05-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/triclinium/</id>
    <content type="html">&lt;p&gt;https://blogs.getty.edu/iris/reclining-and-dining-and-drinking-in-ancient-rome/&lt;/p&gt;
&lt;p&gt;https://books.google.com.sg/books/about/The_Roman_banquet.html?id=PaAk2tWYTEQC&amp;amp;redir_esc=y&lt;/p&gt;
&lt;p&gt;https://www.google.com/search?q=the+roman+banquet&amp;amp;hl=en&amp;amp;source=lnms&amp;amp;tbm=isch&amp;amp;sa=X&amp;amp;ved=2ahUKEwjZyJS724LxAhXUmuYKHXZkDKQQ_AUoAXoECAcQAw&amp;amp;biw=1715&amp;amp;bih=927&amp;amp;dpr=1#imgrc=x26EGEAecc9zpM&lt;/p&gt;
&lt;p&gt;https://www.npr.org/sections/thesalt/2019/05/20/712772285/the-lavish-roman-banquet-a-calculated-display-of-debauchery-and-power&lt;/p&gt;
&lt;p&gt;https://www.througheternity.com/en/blog/things-to-do/banquets-ancient-rome.html&lt;/p&gt;
&lt;p&gt;https://en.wikipedia.org/wiki/Food_and_dining_in_the_Roman_Empire#/media/File:Triclinium_-_Arch%C3%A4ologische_Staatssammlung_M%C3%BCnchen.JPG&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ants</title>
    <link href="https://lieuzhenghong.com/ants/"/>
    <updated>2022-04-23T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ants/</id>
    <content type="html">
&lt;head&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/brython@3/brython.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/brython@3/brython_stdlib.js&quot;&gt;&lt;/script&gt;
&lt;style&gt;
canvas { 
	background: #ccc; 
	display: block; 
	margin: 0 auto; 
	width: 100%;
	object-fit: contain;
}

&lt;/style&gt;

&lt;/head&gt;
&lt;body onload=&quot;brython(1)&quot;&gt;

&lt;p&gt;&lt;em&gt;Toh gave this puzzle to me and Wilfred in Gold Mine; coded this on Saturday afternoon with Rayhan before going to Croatia&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;One hundred ants are dropped on a
    meter stick. Each ant is traveling either to the left or the right with constant
    speed 1 meter per minute. When two ants meet, they bounce off each other
    and reverse direction. When an ant reaches an end of the stick, it falls off.
    At some point all the ants will have fallen off. The time at which this happens
    will depend on the initial configuration of the ants.
&lt;/p&gt;

&lt;h2&gt; Question &lt;/h2&gt;
&lt;p&gt;Over ALL possible initial configurations, what is the longest amount of time
that you would need to wait to guarantee that the stick has no more ants?&lt;/p&gt;


&lt;h2&gt; Answer &lt;/h2&gt;

&lt;p&gt; 
	One minute, regardless of the number of ants.
&lt;/p&gt;


&lt;h3&gt; Proof by animation &lt;/h3&gt;
&lt;div&gt;
&lt;canvas id=&quot;myCanvas&quot;&gt;&lt;/canvas&gt;
&lt;script type=&quot;text/python&quot; src=&quot;https://lieuzhenghong.com/ants.py&quot;&gt;&lt;/script&gt;
&lt;button id=&quot;reset_button&quot;&gt;Reset&lt;/button&gt;
&lt;button id=&quot;more_ants&quot;&gt;More ants&lt;/button&gt;
&lt;button id=&quot;fewer_ants&quot;&gt;Fewer ants&lt;/button&gt;
&lt;/div&gt;

&lt;h2&gt; Bibliography &lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;https://physics.montana.edu/avorontsov/teaching/problemoftheweek/documents/problem_Math004.pdf&quot;&gt;(a) canonical text of the problem&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/ants.pdf&quot;&gt;local mirror&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/ants.py&quot;&gt;Python source code for the simulation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/body&gt;</content>
  </entry>
  <entry>
    <title>Recontextualising my site (2022)</title>
    <link href="https://lieuzhenghong.com/site_redesign_2022/"/>
    <updated>2022-02-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/site_redesign_2022/</id>
    <content type="html">&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;The last time I redesigned my website was &lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/&quot;&gt;2020&lt;/a&gt;.
I moved from Jekyll to Eleventy and made the site look a bit nicer.
Now I want to do a bit more with it: not so much a &lt;em&gt;redesign&lt;/em&gt;, but rather a &lt;em&gt;recontextualisation&lt;/em&gt;.
What do I want my site to be and do?&lt;/p&gt;
&lt;h2 id=&quot;full-text-search&quot; tabindex=&quot;-1&quot;&gt;Full-text search&lt;/h2&gt;
&lt;p&gt;I want people to be able to discover my website with a &lt;code&gt;Ctrl-K&lt;/code&gt; input, something like Notion, or the full text search in Visual Studio Code &lt;code&gt;Ctrl-Shift-F&lt;/code&gt;. Ideally they should be able to discover all the tags as well.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Joel Lee, [3/2/2022 1:53 PM] &amp;gt; [In reply to lieu] &amp;gt; https://docsearch.algolia.com/ ?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;lieu, [3/2/2022 1:55 PM] &amp;gt; [In reply to Joel Lee]
Yeah i know algolia but it seems a bit heavy and or overkill&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;https://lunrjs.com/&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the kind of search I&#39;m looking for:&lt;/p&gt;
&lt;p&gt;https://braindump.jethro.dev/search/?query=food&lt;/p&gt;
&lt;p&gt;https://github.com/jethrokuan/braindump I think it&#39;s built into his template so he didn&#39;t have to implement&lt;/p&gt;
&lt;p&gt;https://thesephist.com/posts/monocle/&lt;/p&gt;
&lt;p&gt;I really like Monocle, this is almost exactly what I want&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://thesephist.com/img/monocle-preview.png&quot; alt=&quot;Monocle preview&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;password-protect-private-posts&quot; tabindex=&quot;-1&quot;&gt;Password-protect private posts&lt;/h2&gt;
&lt;p&gt;Right now, private posts are on the website, but they&#39;re just not displayed publicly (you have to have the exact URL). This is OK for now but will obviously become an issue once full-text search is implemented.&lt;/p&gt;
&lt;p&gt;I would ideally like to index private posts as well (make them searchable) but password-protect the full text content.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Can you gain muscle doing only isometric exercises?</title>
    <link href="https://lieuzhenghong.com/isometric_only_hypertrophy/"/>
    <updated>2022-02-02T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/isometric_only_hypertrophy/</id>
    <content type="html">&lt;h1 id=&quot;hypothesis&quot; tabindex=&quot;-1&quot;&gt;Hypothesis&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Oranchuk%20et%20al.%20(2018).%20Isometric%20training%20and%20long%E2%80%90term%20adaptations%20-%20Effects%20of%20muscle%20length,%20intensity,%20and%20intent%20-%20A%20systematic%20review.pdf&quot;&gt;Oranchuk et al. (2018)&lt;/a&gt;
performed a meta-analysis of twenty-six studies and found that &amp;quot;substantial improvements in muscular hypertrophy and maximal force production were reported regardless of training intensity&amp;quot;.&lt;/p&gt;
&lt;p&gt;maximum voluntary isometric contraction (MVIC)&lt;/p&gt;
&lt;p&gt;Unfortunately &amp;quot;most studies (16/26) recruited untrained participants, while the remainder (11/26) utilized &amp;quot;active&amp;quot; or &amp;quot;recreationally trained&amp;quot; participants&amp;quot;, so the evidence isn&#39;t strong whether isometric training can result in hypertrophy in well-trained individuals.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pubmed.ncbi.nlm.nih.gov/15075307/&quot;&gt;Skeletal muscle hypertrophy in response to isometric, lengthening, and shortening training bouts of equivalent duration&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;practical-applications&quot; tabindex=&quot;-1&quot;&gt;Practical applications&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.t-nation.com/training/isometrics-for-mass/&quot;&gt;T-Nation &amp;quot;Isometrics for Mass&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://liftbigeatbig.com/isometrics-for-strength-hypertrophy/&quot;&gt;&amp;quot;Isometrics for Strength Hypertrophy&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Is nonsurgical penile enhancement possible?</title>
    <link href="https://lieuzhenghong.com/penile_enhancement/"/>
    <updated>2022-01-25T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/penile_enhancement/</id>
    <content type="html">&lt;h1 id=&quot;key-questions&quot; tabindex=&quot;-1&quot;&gt;Key questions&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Are there nonsurgical methods that (semi-)permanently increase flaccid length?&lt;/li&gt;
&lt;li&gt;Are there nonsurgical methods that (semi-)permanently increase erect length?&lt;/li&gt;
&lt;li&gt;Are there nonsurgical methods that (semi-)permanently increase penile girth?&lt;/li&gt;
&lt;li&gt;If any of 1 to 3 hold, how do these methods work mechanistically/what is their anatomical basis?&lt;/li&gt;
&lt;li&gt;What are the potential gains and risks of these methods?&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;motivation&quot; tabindex=&quot;-1&quot;&gt;Motivation&lt;/h1&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Good study by &lt;a href=&quot;https://pubmed.ncbi.nlm.nih.gov/30365247/&quot;&gt;Moncada et al. (2022)&lt;/a&gt;. RCT. n=93 patients with Peyronie&#39;s (curved penis):
penile traction devices are effective at decreasing curvature and increasing stretched penile length: &amp;quot;SPL increased significantly in the PG compared to baseline and compared with the NIG, ranging from 0.5 to 3.0 cm (mean 1.8 cm; P &amp;lt; 0.05)&amp;quot;&lt;/p&gt;
&lt;p&gt;Not so good study: &lt;a href=&quot;https://pubmed.ncbi.nlm.nih.gov/20102448/&quot;&gt;Nikoobakht et al. (2011)&lt;/a&gt;. n=23 patients who complained of &amp;quot;short penis&amp;quot; were given their &amp;quot;Golden Erect&amp;quot; (lmao) penile traction device. Mean stretched penile length also significantly increased from 11.5 ± 1.0 cm to, respectively, 12.4 ± 1.3 cm and 13.2 ± 1.4 cm during the first and second follow-up (P &amp;lt; 0.05).&lt;/p&gt;
&lt;h2 id=&quot;mechanism-of-penile-growth&quot; tabindex=&quot;-1&quot;&gt;Mechanism of penile growth&lt;/h2&gt;
&lt;p&gt;Initial length gains come from loosening of the suspensory ligament; further gains come from tunica stretching.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://old.reddit.com/r/gettingbigger/comments/k8qlmp/part_1_penis_growth_the_causes_and_phases/&quot;&gt;Reddit post&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Length gains are caused by a few things.&lt;/p&gt;
&lt;p&gt;Erection quality improvements, loosening the suspensory ligaments and stretching of the tunica and increase in blood vessel volume.&lt;/p&gt;
&lt;p&gt;Erection Quality is perhaps the easiest and quickest way to gain. Simply put, erection quality is determined by much blood a penis holds during an erection. The more blood it can hold, the stronger the erection.&lt;/p&gt;
&lt;p&gt;Gains from EQ typically are about .25 of an inch for a man with okay EQ. Bad EQ can be as much as .5 of an inch&lt;/p&gt;
&lt;p&gt;EQ improvements happen in the first 4 weeks of PE. Most PE techniques improve EQ passively over time but for active develop, I recommend using an angion method for 2-3 weeks. (A post on angion method is TBD)&lt;/p&gt;
&lt;p&gt;The suspensory ligaments connect at the base of the pubic bone. They are what attach the penis to the body. They play a role in erection angle as well as length. Loosening the Suspensory ligaments allow more of the chambers of the penis to stick out of the body, as the chambers start much farther back into pelvic region(3-6 inches)&lt;/p&gt;
&lt;p&gt;Gains from loosening of the suspensory ligaments usually happens within two months. Depending on how tight they were at the beginning the average man can expect to gain .25-.5 of an inch Targeting the suspensory ligaments.&lt;/p&gt;
&lt;p&gt;Stretching the tunica takes much more time compared to EQ gains or suspensory gains. The tunica surrounds the shaft like a wrapper. This is what gives the penis it&#39;s hardness during an erection, otherwise it would be very spongy, like the glans/head. What causes growth in this fashion is the healing of micro damage from stretching the penis in multiple ways. Daily length sessions cause the microtears generated to heal in an elongated state leading to a longer shaft.&lt;/p&gt;
&lt;p&gt;Blood vessel expansion will be covered more with girth&lt;/p&gt;
&lt;p&gt;Gains from tunica stretching are about .5 of inch every 6 months given commitment and correct use of progress overload.&lt;/p&gt;
&lt;p&gt;Given all three of the of the ways to a gain a man new to PE can gain 1 inch in as little as 6 months but typically it is about 4 -14 months, depending on their bodies response to the stimulus, their starting size, where larger men tend to grow faster, proper techniques, and personal commitment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;evidence for suspensory ligament loosening: see &lt;a href=&quot;https://www.annaliitalianidichirurgia.it/wp-content/uploads/2019/01/199-204-min.pdf&quot;&gt;Protogerou et al. (2019)&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;still-unanswered-questions&quot; tabindex=&quot;-1&quot;&gt;Still-unanswered questions&lt;/h1&gt;
&lt;p&gt;How does tension &lt;em&gt;actually&lt;/em&gt; induce growth? Is it actually microtears? It&#39;s possible. We know that isn&#39;t the mechanism in &lt;em&gt;muscular&lt;/em&gt; hypertrophy. but the tunica is fibrous tissue that is made up of elastin and collagen. But is it microtearing that causes the lengthening or some other mechanism causing the plastic deformation?&lt;/p&gt;
&lt;h1 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h1&gt;
&lt;p&gt;Most helpful article so far:
&lt;a href=&quot;https://www.annaliitalianidichirurgia.it/wp-content/uploads/2019/01/199-204-min.pdf&quot;&gt;Protogerou V, Anagnostopolou S, Venierates D, Troupis T, Plagou M, Vlassis K, Skandalakis P. Penis ligaments: their use in &amp;quot;increasing&amp;quot; the size of the penis in penile augmentation procedures. Anatomical description in human cadavers and clinical results of a phalloplasty series. Ann Ital Chir. 2010 May-Jun;81(3):199-204. PMID: 21090558.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://link.springer.com/content/pdf/10.1007/BF01653133.pdf&quot;&gt;Zhang X, Huang Z, Xiao Y, Kuang L, Zhang M, Zhang G, Li Q, Bai W, Xu T. Suspensory ligament release combined with acellular dermal matrix filler in infrapubic space: A new method for penile length augmentation. Andrologia. 2019 Oct;51(9):e13351. doi: 10.1111/and.13351. Epub 2019 Jul 2. PMID: 31264245.&lt;/a&gt;
https://pubmed.ncbi.nlm.nih.gov/31264245/&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pubmed.ncbi.nlm.nih.gov/30365247/&quot;&gt;Moncada I, Krishnappa P, Romero J, Torremade J, Fraile A, Martinez-Salamanca JI, Porst H, Levine L. Penile traction therapy with the new device &#39;Penimaster PRO&#39; is effective and safe in the stable phase of Peyronie&#39;s disease: a controlled multicentre study. BJU Int. 2019 Apr;123(4):694-702. doi: 10.1111/bju.14602. Epub 2018 Nov 22. PMID: 30365247.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Is sauna good for you?</title>
    <link href="https://lieuzhenghong.com/sauna/"/>
    <updated>2022-01-23T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/sauna/</id>
    <content type="html">&lt;h1 id=&quot;key-questions&quot; tabindex=&quot;-1&quot;&gt;Key questions&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Is sauna good for you?&lt;/li&gt;
&lt;li&gt;In what ways is it good for you?&lt;/li&gt;
&lt;li&gt;Why is sauna good for you? What sort of mechanistic pathway does it act over?&lt;/li&gt;
&lt;li&gt;What are health risks of sauna?&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.healthyliving.gr/wp-content/uploads/2018/08/Cardiovascular-and-Other-Health-Benefits-of-Sauna-Bathing-A-Review-of-the-Evidence.pdf&quot;&gt;Laukkanen JA, Laukkanen T, Kunutsor SK. Cardiovascular and Other Health Benefits of Sauna Bathing: A Review of the Evidence. Mayo Clin Proc. 2018 Aug;93(8):1111-1121. doi: 10.1016/j.mayocp.2018.04.008. PMID: 30077204.&lt;/a&gt;
&lt;a href=&quot;https://pubmed.ncbi.nlm.nih.gov/31102597/&quot;&gt;Laukkanen JA, Kunutsor SK. Is sauna bathing protective of sudden cardiac death? A review of the evidence. Prog Cardiovasc Dis. 2019 May-Jun;62(3):288-293. doi: 10.1016/j.pcad.2019.05.001. Epub 2019 May 16. PMID: 31102597.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to import and display Markdown files in React</title>
    <link href="https://lieuzhenghong.com/how_to_import_markdown_in_react/"/>
    <updated>2021-09-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/how_to_import_markdown_in_react/</id>
    <content type="html">&lt;p&gt;Recently I found myself in need of importing and displaying long documents
in a React SPA, but I didn&#39;t know how to do it.
I combined the answers in these StackOverflow questions here (
&lt;a href=&quot;https://stackoverflow.com/questions/42928530/how-do-i-load-a-markdown-file-into-a-react-component/53975297#53975297&quot;&gt;1&lt;/a&gt;,
&lt;a href=&quot;https://stackoverflow.com/questions/65395125/how-to-load-an-md-file-on-build-when-using-create-react-app-and-typescript&quot;&gt;2&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Three simple steps:&lt;/p&gt;
&lt;p&gt;First, install
&lt;a href=&quot;https://github.com/remarkjs/react-markdown&quot;&gt;React Markdown&lt;/a&gt;
with &lt;code&gt;yarn add react-markdown&lt;/code&gt; or your preferred package manager.&lt;/p&gt;
&lt;p&gt;Then, declare a &lt;code&gt;markdown.d.ts&lt;/code&gt; file and put it in your folder
(I believe anywhere that Typescript can see is OK):&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;*.md&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; value&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// markdown is just a string&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then import Markdown files, &lt;code&gt;fetch&lt;/code&gt; them, and parse them into a string.
Pass the parsed Markdown file into the &lt;code&gt;ReactMarkdown&lt;/code&gt; component,
which takes in a &lt;code&gt;children: string&lt;/code&gt; prop.
You can use the &lt;code&gt;useState&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt; hooks to do this cleanly:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useState&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useEffect &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ReactMarkdown &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-markdown&#39;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Terms of Use and Privacy Policy&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TermsOfUse &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./texts/terms_of_use.md&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; PrivacyPolicy &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./texts/privacy_policy.md&#39;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; TermsPage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSX&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Element &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tosText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setTosText&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;privacyPolicyText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setPrivacyPolicyText&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// Fetch Terms of Use&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TermsOfUse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setTosText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;useEffect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PrivacyPolicy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;res &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setPrivacyPolicyText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ReactMarkdown children&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;tosText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ReactMarkdown children&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;privacyPolicyText&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
		&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;div&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This means you could probably use ReactMarkdown + Router for your blog instead of a static site generator.
Maintain a map of routes to Markdown files
and fetch the file when the user navigates to the chosen route.
Maybe (most probably) I&#39;ve just reinvented the wheel, lol.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to implement role-based access control for AWS (Cognito, DynamoDB)</title>
    <link href="https://lieuzhenghong.com/how-to-do-role-based-access-control-for-aws/"/>
    <updated>2021-06-22T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/how-to-do-role-based-access-control-for-aws/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We have &lt;em&gt;projects&lt;/em&gt;. Each project can have one or more &lt;em&gt;S3 buckets&lt;/em&gt;.
Each project can have one or more &lt;em&gt;users&lt;/em&gt;. Each user can belong to one or more projects.
(There is a one-to-many mapping between projects and buckets,
and a many-to-many mapping between users and projects).&lt;/p&gt;
&lt;p&gt;We want to make sure that a user can log in and access &lt;em&gt;only the buckets that
are part of projects he belongs to&lt;/em&gt;. As Amazon AWS is a huge and very complicated system,
there were many ways to do it, all of which seemed plausible.
I worked with Chris to explore different approaches, eventually settling on the current one.
In this design document I list the five different approaches,
explore their advantages and disadvantages,
and justify why I chose the implementation we did.&lt;/p&gt;
&lt;h2 id=&quot;approaches&quot; tabindex=&quot;-1&quot;&gt;Approaches&lt;/h2&gt;
&lt;p&gt;Five different approaches were tried and four were rejected.
I eventually settled on using the &lt;code&gt;AssumeRole&lt;/code&gt; method
which I believe is the correct tradeoff.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Using IAM User/Role/Bucket policies [Rejected]&lt;/li&gt;
&lt;li&gt;Using Cognito User Groups [Rejected]&lt;/li&gt;
&lt;li&gt;Using Attribute-based access control [Rejected]&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt; [Rejected]&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;AssumeRole&lt;/code&gt; [Accepted]&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;using-iam-user%2Fiam-role%2Fbucket-policies-%5Brejected%5D&quot; tabindex=&quot;-1&quot;&gt;Using IAM User/IAM Role/Bucket policies [Rejected]&lt;/h3&gt;
&lt;p&gt;When a user is onboarded, we create an IAM User and a Cognito User in the Cognito User Pool.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When the person logs into the Cognito user pool, the identity pool will give
him this IAM Role using the JWT loop with the same policies as the
Bedrock/Talend IAM user.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On each bucket we create a policy that only allows a particular IAM Role/IAM user
to access it.&lt;/p&gt;
&lt;p&gt;The user flow is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use Session Token to assume IAM Role.&lt;/li&gt;
&lt;li&gt;Use IAM Role to access S3 Bucket.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The dealbreaker of this approach is that &lt;em&gt;every user would potentially have to have a unique IAM User/Role&lt;/em&gt;,
and we couldn&#39;t attach all of them to a bucket.
This is not scalable as there is a maximum policy length of the bucket,
and as you add more users, eventually the bucket will not be able to accommodate more users.
We need a way to do group-based authentication, which is what I turned to next.&lt;/p&gt;
&lt;h3 id=&quot;using-cognito-user-groups-%5Brejected%5D&quot; tabindex=&quot;-1&quot;&gt;Using Cognito User Groups [Rejected]&lt;/h3&gt;
&lt;p&gt;The disadvantage of the previous method is that there was no grouping.&lt;/p&gt;
&lt;p&gt;So now we institute a one-to-one-mapping between projects and Cognito user groups.
Each project will be a Cognito user group, and that user group would allow access
to all buckets in that user group.&lt;/p&gt;
&lt;p&gt;The onboarding flow is as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create bucket. Get bucket ARN.&lt;/li&gt;
&lt;li&gt;[Requires bucket ARN] Create IAM role that allows access to bucket. Get IAM role.&lt;/li&gt;
&lt;li&gt;[Requires IAM Role ARN] Create Cognito User Group, passing in IAM Role ARN.&lt;/li&gt;
&lt;li&gt;[Requires Cognito User Group ARN] Set bucket policy on S3 bucket allowing user group access.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Putting the permissions on the user group is done as follows:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;Effect&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
  &lt;span class=&quot;token literal-property property&quot;&gt;Resource&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:s3:::&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;bucketName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;arn:aws:s3:::&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;bucketName&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/*&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Users would get their IAM Role via &lt;code&gt;getCredentialsForIdentity&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The main disadvantage of this approach is that many front end requests would be required
to list all groups a user belonged to.
When a user logs in, he has to assume a role. But one role is mapped one-to-one to a project.
So what happens if a user is part of multiple projects? Then he has to get the first user group role,
list the buckets in that project, then switch to the second user group role, list the buckets in that project,
and so on. Chris and I felt that this was untenable.&lt;/p&gt;
&lt;p&gt;You could try to have a &amp;quot;super user group&amp;quot; that encompassed the permissions of multiple IAM roles.
But this could conceivably lead to an exponential number of user groups.
For example, if you have 3 projects (A, B, C), then you would need 7 user groups to cover all eventualities:
&lt;code&gt;A, B, C, AB, AC, BC, ABC&lt;/code&gt;. And if you have 4 projects then you need 15 user groups, and so on...
We decided that this approach was not feasible.&lt;/p&gt;
&lt;h3 id=&quot;attribute-based-access-control-%5Brejected%5D&quot; tabindex=&quot;-1&quot;&gt;Attribute-based access control [Rejected]&lt;/h3&gt;
&lt;p&gt;The next idea was to put attributes on Cognito users, where each attribute is a project.
For example, if the user has three different projects, then he would have
&lt;code&gt;{project1: true, project2: true, project16: true}&lt;/code&gt;.
These project names would have to be globally unique.
Then you would create a global policy
that grants permissions to the project&#39;s resources
as long as the user has that project name in his tags.&lt;/p&gt;
&lt;p&gt;This approach was recommended by the
&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_attribute-based-access-control.html&quot;&gt;AWS ABAC tutorial&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can map the membership attribute to a tag key for principal to be passed
on to the IAM permissions policy. This way you can create a single permissions
policy and conditionally allow access to premium content based on the value of
membership level and tag on the content files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This approach had several advantages.
The first advantage is that you only need one front-end request,
and you don&#39;t need an exponential number of user groups.
It would allow fine-grained user permissions: for example, you could have
&lt;code&gt;{project1dev: true, project2dev: true, project16admin: true}&lt;/code&gt;,
to make the user an admin of project 16.&lt;/p&gt;
&lt;p&gt;The key disadvantages was that for this method to work,
we would have to have one long policy document that grants
permissions to the project&#39;s resources
as long as the user has that project name in his tags.
And every time a new project was created,
we would have to append to the policy document.
But there is a maximum character limit on a single permissions policy,
which would impose a limit on the total number of projects in our system.&lt;/p&gt;
&lt;p&gt;While there&#39;s a way to get around this with a slightly different ABAC mechanism,
there is no free lunch.
We faced a dilemma: either we limit the total number of projects per user,
or you limit the total number of projects in our system.
Eventually we decided to try something else.&lt;/p&gt;
&lt;h3 id=&quot;assumerolewithwebidentity-%5Brejected%5D&quot; tabindex=&quot;-1&quot;&gt;AssumeRoleWithWebIdentity [Rejected]&lt;/h3&gt;
&lt;p&gt;Idea here is to dynamically generate access control based on the &lt;code&gt;WebIdentity&lt;/code&gt; provided.
We look up the user in the DynamoDB table, check what projects the user belongs to,
and builds a custom IAM Role that allows the user the ability to access only those buckets.&lt;/p&gt;
&lt;p&gt;User flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User signs in with Cognito User Pool to get a JWT.&lt;/li&gt;
&lt;li&gt;User calls &lt;code&gt;getId&lt;/code&gt; to get an identity pool ID.&lt;/li&gt;
&lt;li&gt;User calls &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt; with the identity pool ID.&lt;/li&gt;
&lt;li&gt;The Lambda function looks at the ID, looks up the DynamoDB table to check the
projects the user is in, and builds a custom IAM role which is the &lt;em&gt;intersection&lt;/em&gt;
of the base IAM role (allows access to all S3 buckets) and the dynamically-generated &lt;code&gt;InlinePolicy&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Advantages:&lt;/p&gt;
&lt;p&gt;The key advantage is that this allows us to &lt;em&gt;dynamically generate&lt;/em&gt; a custom IAM role
depending on the user&#39;s projects, which solves a lot of the problems of the previous
approaches:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It would require fewer requests to switch roles and access buckets from
different projects, making the frontend development much simpler. In the
role-based control approach a user has multiple roles, and the frontend needs to
make multiple &lt;code&gt;getCredentialsForidentity&lt;/code&gt; calls to switch between these roles in
order to access buckets from different projects. The new ABAC system would not
require switching roles with getCredentialsForIdentity as there is only one role
for that particular identity.&lt;/li&gt;
&lt;li&gt;It would potentially allow more fine-grained control of project resources.
For example, a user group might have &amp;quot;superusers&amp;quot; and &amp;quot;regular users&amp;quot;, and this could be
reflected in the DynamoDB. In fact, you can put any type of condition/property in the
DynamoDB and we could check for that.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The dealbreaker disadvantage is that this approach is not secure,
because &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt; is a call that does not
require credentials to make.
(This is not quite the same as an unauthenticated endpoint:
you still need a valid Cognito OpenID token).
Why is this a problem? Because this means a user could technically write their own
custom frontend and call &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt; themselves.
They could then pass in an empty inline policy, which would give them access to all S3 buckets.
While this is a bit of an edge case, we thought this was nevertheless a security flaw
and abandoned this idea.&lt;/p&gt;
&lt;h3 id=&quot;assumerole-%5Baccepted%5D&quot; tabindex=&quot;-1&quot;&gt;AssumeRole [Accepted]&lt;/h3&gt;
&lt;p&gt;Like before, the idea here is to dynamically generate the IAM role based on the user.&lt;/p&gt;
&lt;p&gt;User flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;User signs in with Cognito User Pool to get a JWT Bearer Token.&lt;/li&gt;
&lt;li&gt;User calls the &lt;code&gt;auths/resources&lt;/code&gt; endpoint using a GET request, passing in the JWT Bearer Token.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;auths/resources&lt;/code&gt; endpoint calls a Lambda function, which
looks at the user ID contained in the JWT Bearer Token,
looks up the DynamoDB table to check the projects the user is in.&lt;/li&gt;
&lt;li&gt;The Lambda function generates a custom InlinePolicy from the
information it obtains in the DynamoDB Table.&lt;/li&gt;
&lt;li&gt;The lambda function calls sts.assumeRole to generate a custom IAM role,
which is the intersection of the base IAM role (allows access to all S3 buckets)
and the dynamically-generated InlinePolicy.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The &lt;code&gt;auths/resources&lt;/code&gt; endpoint is private.
Anyone who tries to access it without a valid JWT Bearer token
will be given a &lt;code&gt;401 Forbidden&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;This approach is very similar to the previous &lt;code&gt;AssumeRoleWithWebIdentity&lt;/code&gt;.
The key difference is that the user himself cannot call &lt;code&gt;assumeRole&lt;/code&gt;.
I have given permissions only for the Lambda function to call &lt;code&gt;assumeRole&lt;/code&gt;.
So the user cannot create his own frontend like he could in AssumeRoleWithWebIdentity.&lt;/p&gt;
&lt;p&gt;Advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure&lt;/li&gt;
&lt;li&gt;No exponential number of user groups&lt;/li&gt;
&lt;li&gt;No need to switch roles&lt;/li&gt;
&lt;li&gt;Fine-grained access control&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Disadvantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There is a maximum character limit in a single permissions
policy (10240 chars). This means that we can only have at most ~50 concurrent
projects per user. We decided that this was an acceptable limit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;assumerole&#39;s-base-iam-role&quot; tabindex=&quot;-1&quot;&gt;AssumeRole&#39;s Base IAM Role&lt;/h3&gt;
&lt;p&gt;The Base IAM role allows access to all S3 buckets, and looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;AllowAccessToAllS3BucketsRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;AWS::IAM::Role&quot;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;Properties&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;RoleName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;custom.IAMRolePrefix&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;allow&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;access&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;to&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;all&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;buckets&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;role
    &lt;span class=&quot;token key atrule&quot;&gt;AssumeRolePolicyDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2012-10-17&#39;&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;Effect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Allow&#39;&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;Principal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token key atrule&quot;&gt;Fn::GetAtt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
                &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; AllowAssumeRoleRole
                &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; Arn
          &lt;span class=&quot;token key atrule&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; sts&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;AssumeRole
    &lt;span class=&quot;token key atrule&quot;&gt;PermissionsBoundary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;arn:aws:iam::052567997892:policy/GCCIAccountBoundary&#39;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;Policies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;PolicyName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;allow-access-to-all-s3-buckets&#39;&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;PolicyDocument&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;2012-10-17&#39;&lt;/span&gt;
          &lt;span class=&quot;token key atrule&quot;&gt;Statement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;GetObject
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;PutObject
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;PutObjectAcl
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;PutObjectVersionAcl
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;ListBucket
            &lt;span class=&quot;token key atrule&quot;&gt;Effect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Allow
            &lt;span class=&quot;token key atrule&quot;&gt;Resource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;aws&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;*
              &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; arn&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;aws&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;s3&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token important&quot;&gt;*/*&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
              &lt;span class=&quot;token key atrule&quot;&gt;Bool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token key atrule&quot;&gt;aws:SecureTransport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For security purposes, only the AllowAssumeRoleRole is allowed to assume this role.
This base role should not be passed to the user. Instead, we will create a new role like this:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;assumeRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; baseRoleArn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;arn:aws:iam::052567997892:role/iamrole-imda-psf-lieudev-allow-access-to-all-s3-buckets-role&#39;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inlinePolicy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// create the inline policy here after a DynamoDB query&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; assumeRoleParams &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    RoleArn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; baseRoleArn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Role the caller is assuming (base role). In this case, AllowAccessToS3Buckets&lt;/span&gt;
    RoleSessionName&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;TestUser&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// pass the name associated with the user&lt;/span&gt;
    Policy&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; inlinePolicy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    DurationSeconds&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token constant&quot;&gt;AWS&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;STS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tokenResult &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; sts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;assumeRole&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assumeRoleParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that we pass in inlinePolicy into assumeRoleParams, which creates a new role
which is the intersection of inlinePolicy and baseRoleArn. This will allow only access to resources
that are allowed inside inlinePolicy.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Solving two brainteasers 舅母 gave me</title>
    <link href="https://lieuzhenghong.com/solving_brainteasers/"/>
    <updated>2021-05-09T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/solving_brainteasers/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I was given these problems by my 舅母:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/aaren_brainteasers/question.jpg&quot; alt=&quot;/img/aaren_brainteasers/question.jpg&quot;&gt;&lt;/p&gt;
&lt;p&gt;The questions are actually quite poorly written (in the sense that they are ambiguous)
but the ambiguity actually makes them inadvertently more challenging and thus more interesting.&lt;/p&gt;
&lt;h2 id=&quot;swimmers-and-non-swimmers&quot; tabindex=&quot;-1&quot;&gt;Swimmers and non-swimmers&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The native inhabitants of a certain island country have a strange
characteristic: those who are swimmers always tell the truth. But those who are
nonswimmers always lie. Suppose that you visit the island and meet a group of
three people who are native inhabitants. You ask the first person, &amp;quot;Are you a
swimmer?&amp;quot; The answer is unintelligible. The second person immediately says,
&amp;quot;That was &#39;Yes.&#39; I am a swimmer, too.&amp;quot; The third person says, &amp;quot;They are both
lying.&amp;quot; Is each of these three people a swimmer or a nonswimmer?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Answer: It depends on how you interpret &amp;quot;nonswimmers always lie&amp;quot;. Possible answers: SSN, NNS, SNN.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Firstly, let&#39;s note that even though the answer of the first person is unintelligible,
it must always be &amp;quot;yes&amp;quot;. This is because a swimmer will always honestly answer &amp;quot;Yes&amp;quot;
and a nonswimmer will always lie and say &amp;quot;Yes&amp;quot; too.&lt;/p&gt;
&lt;p&gt;The answer to this question depends completely on how you interpret the phrase
&amp;quot;nonswimmers must always lie&amp;quot;!
Depending on your interpretation,
possible solutions to this problem are two swimmers and a nonswimmer (SSN), NNS, and even SNN.&lt;/p&gt;
&lt;p&gt;Suppose I always lie. Could I have said the statement
&amp;quot;My name is Zheng Hong. I am eight feet tall.&amp;quot;?
That depends on how you interpret &amp;quot;always lie&amp;quot;.
Does it mean that every sentence in the utterance must be false?
If so, I could not have said that, since &amp;quot;My name is Zheng Hong&amp;quot; is true.
But if you take the utterance &lt;em&gt;as a whole&lt;/em&gt;, then I &lt;em&gt;could&lt;/em&gt; have said that,
since the &lt;em&gt;utterance as a whole&lt;/em&gt; is a lie.&lt;/p&gt;
&lt;p&gt;In the same way, the sentence is &amp;quot;That was &#39;Yes&#39;. I am a swimmer, too.&amp;quot;.
If &amp;quot;must always lie&amp;quot; means &amp;quot;every sentence must be a lie&amp;quot;,
then a nonswimmer could not possibly have said that,
because &amp;quot;That was &#39;Yes&#39;&amp;quot; is true.
Hence the second person must have been a swimmer.
But if we consider two sentences as one combined utterance,
then the nonswimmer &lt;em&gt;could&lt;/em&gt; have said that,
since the combined utterance is false, and this would
still follow the rule of &amp;quot;nonswimmers always lie&amp;quot;.
Then the second person could be a nonswimmer.&lt;/p&gt;
&lt;p&gt;Let&#39;s consider the first situation
where the second person must have been a swimmer.
Then the first person must have been a swimmer.
This is because if the first person was a nonswimmer,
then the second person would not have said &amp;quot;I am a swimmer, &lt;em&gt;too&lt;/em&gt;&amp;quot;.
The word &amp;quot;too&amp;quot; implies that the first person was a swimmer,
but this would be a false statement if the first person was a nonswimmer.
Hence the first person must have been a swimmer.
But if both first and second are swimmers, then the last person must be a nonswimmer,
because &amp;quot;They are both lying&amp;quot; must be a lie, since neither of them are lying.
Hence, &lt;strong&gt;SSN&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Now let&#39;s consider the situation where the second person is a nonswimmer (&lt;code&gt;?N?&lt;/code&gt;).
In which case, the first person could have been a swimmer or nonswimmer.
Let&#39;s consider swimmer first. &lt;code&gt;SN?&lt;/code&gt;. Is the third person a swimmer or a nonswimmer?
Let&#39;s review:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;Yes&amp;quot; (true)&lt;/li&gt;
&lt;li&gt;&amp;quot;That was &#39;Yes&#39;. I am a swimmer, too&amp;quot; (false)&lt;/li&gt;
&lt;li&gt;&amp;quot;They are both lying&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sentence 3 must be a lie, since only one of them is lying. Hence, the third person
is a nonswimmer. Thus, &lt;strong&gt;SNN&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We can also consider the case where the first person is a nonswimmer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;Yes&amp;quot; (false)&lt;/li&gt;
&lt;li&gt;&amp;quot;That was &#39;Yes&#39;. I am a swimmer, too&amp;quot; (false)&lt;/li&gt;
&lt;li&gt;&amp;quot;They are both lying&amp;quot;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here Sentence 3 must be the truth, since both of them are lying.
Hence, the third person is a swimmer. Thus, &lt;strong&gt;NNS&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In fact, we can run through all 8 possible combinations of swimmers and non-swimmers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SSS: impossible, since the third person would not say that they are both lying.&lt;/li&gt;
&lt;li&gt;NSS: impossible, since the second person would not say that he &amp;quot;too&amp;quot; was a swimmer&lt;/li&gt;
&lt;li&gt;SNS: impossible, since the third person would say that only the second person is lying&lt;/li&gt;
&lt;li&gt;SSN: possible&lt;/li&gt;
&lt;li&gt;NNS: possible&lt;/li&gt;
&lt;li&gt;NSN: impossible, since the second person would not say that he &amp;quot;too&amp;quot; was a swimmer&lt;/li&gt;
&lt;li&gt;SNN: possible&lt;/li&gt;
&lt;li&gt;NNN: impossible, since the sentence &amp;quot;They are both lying&amp;quot; would be true if so.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;custom-dice&quot; tabindex=&quot;-1&quot;&gt;Custom Dice&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;What whole numbers should appear on the twelve faces of two number cubes
so that the probabilities that the top two faces show any sum from 1 to 12
inclusive are exactly the same?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Answer: There are infinitely many whole number solutions.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First of all, let&#39;s note that we can fill all the faces with &#39;0&#39;, or &#39;13&#39;, &#39;14&#39;, etc.
Then the probability that the top two faces show any sum from 1 to 12
will be 0, which is exactly the same.
So this is technically a solution. But of course this is a trivial solution.
We should look for &lt;em&gt;non-zero&lt;/em&gt; probabilities.&lt;/p&gt;
&lt;p&gt;So the idea is as follows.
Consider a &amp;quot;counter&amp;quot; that counts the number of ways each number can be rolled.
As an example, the counter for two regular 6-sided dice would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    2: 1,
    3: 2,
    4: 4,
    5: 4,
    6: 5,
    7: 6,
    8: 5,
    9: 4,
    10: 4,
    11: 2,
    12: 1,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, there are six ways to roll a 7:
&lt;code&gt;(1,6), (6,1), (2,5), (5,2), (3,4), (4,3)&lt;/code&gt;,
and that&#39;s why we have the row &lt;code&gt;7: 6&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For this question, we want a counter that looks like this:&lt;/p&gt;
&lt;p&gt;{
0: whatever, we don&#39;t care
1: X
2: X
3: X
...
11: X
12: X
13: whatever, we don&#39;t care
14: whatever, we don&#39;t care
...
...
25: whatever, we don&#39;t care
}&lt;/p&gt;
&lt;p&gt;where all the X&#39;s are the same (and ideally not 0).&lt;/p&gt;
&lt;p&gt;You can actually solve this problem by thinking about it,
and filling the dice from the smallest number onwards.
First you know that you need a 0, because you can only roll a sum of 1
if you roll a 0 and a 1.
And given that there are only 36 (6x6) possible outcomes of the dice,
you should figure that there can only be 1, 2, or 3 occurrences of
1--12.
I guessed 2, and indeed I did it by hand.
But in fact, there are infinitely many solutions!
Here is some code to find solutions:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; itertools&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; collections

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is_equal_probability&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; collections&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Counter&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
    Check if all numbers from start to end (inclusive) 
    have the same number of occurrences.
    &quot;&quot;&quot;&lt;/span&gt;
    occurrences &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;start&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; occurrences&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Generate 6-sided dice with the faces 0 to 12&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 13 choose 6: 1716 unique combinations&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; dice1 &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; itertools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;combinations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; dice2 &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; itertools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;combinations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Get all the 36 dice rolls&lt;/span&gt;
        combinations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itertools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;product&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dice1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dice2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combinations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Once we have the 36 dice rolls, &lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# sum them up and count the number of each occurrence&lt;/span&gt;
        c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; collections&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Counter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; combinations&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; is_equal_probability&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Found a pair of dice that have equal probability of summing to a value from 1 to 12!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Dice 1: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;dice1&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Dice 2: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;dice2&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;The 36 possible combinations: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;combinations&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;And their respective sums: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here&#39;s the output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(base) lieu@DESKTOP-NV19JNO:~/dev/lieuzhenghong.com/root$ python3 dice.py 
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 2, 3, 4, 10)
Dice 2: (0, 1, 5, 6, 11, 12)
The 36 possible combinations: [(0, 0), (0, 1), (0, 5), (0, 6), (0, 11), (0, 12), (1, 0), (1, 1), (1, 5), (1, 6), (1, 11), (1, 12), (2, 0), (2, 1), (2, 5), (2, 6), (2, 11), (2, 12), (3, 0), (3, 1), (3, 5), (3, 6), (3, 11), (3, 12), (4, 0), (4, 1), (4, 5), (4, 6), (4, 11), (4, 12), (10, 0), (10, 1), (10, 5), (10, 6), (10, 11), (10, 12)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 3), (16, 2), (21, 1), (22, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 2, 3, 9, 11)
Dice 2: (0, 1, 4, 5, 8, 12)
The 36 possible combinations: [(0, 0), (0, 1), (0, 4), (0, 5), (0, 8), (0, 12), (1, 0), (1, 1), (1, 4), (1, 5), (1, 8), (1, 12), (2, 0), (2, 1), (2, 4), (2, 5), (2, 8), (2, 12), (3, 0), (3, 1), (3, 4), (3, 5), (3, 8), (3, 12), (9, 0), (9, 1), (9, 4), (9, 5), (9, 8), (9, 12), (11, 0), (11, 1), (11, 4), (11, 5), (11, 8), (11, 12)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 2), (16, 1), (17, 1), (19, 1), (21, 1), (23, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 2, 3, 9, 12)
Dice 2: (0, 1, 4, 5, 8, 11)
The 36 possible combinations: [(0, 0), (0, 1), (0, 4), (0, 5), (0, 8), (0, 11), (1, 0), (1, 1), (1, 4), (1, 5), (1, 8), (1, 11), (2, 0), (2, 1), (2, 4), (2, 5), (2, 8), (2, 11), (3, 0), (3, 1), (3, 4), (3, 5), (3, 8), (3, 11), (9, 0), (9, 1), (9, 4), (9, 5), (9, 8), (9, 11), (12, 0), (12, 1), (12, 4), (12, 5), (12, 8), (12, 11)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 3), (14, 2), (16, 1), (17, 2), (20, 2), (23, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 2, 9, 10, 11)
Dice 2: (0, 1, 3, 4, 6, 7)
The 36 possible combinations: [(0, 0), (0, 1), (0, 3), (0, 4), (0, 6), (0, 7), (1, 0), (1, 1), (1, 3), (1, 4), (1, 6), (1, 7), (2, 0), (2, 1), (2, 3), (2, 4), (2, 6), (2, 7), (9, 0), (9, 1), (9, 3), (9, 4), (9, 6), (9, 7), (10, 0), (10, 1), (10, 3), (10, 4), (10, 6), (10, 7), (11, 0), (11, 1), (11, 3), (11, 4), (11, 6), (11, 7)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 2), (16, 2), (17, 2), (18, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 3, 4, 6, 7)
Dice 2: (0, 1, 2, 9, 10, 11)
The 36 possible combinations: [(0, 0), (0, 1), (0, 2), (0, 9), (0, 10), (0, 11), (1, 0), (1, 1), (1, 2), (1, 9), (1, 10), (1, 11), (3, 0), (3, 1), (3, 2), (3, 9), (3, 10), (3, 11), (4, 0), (4, 1), (4, 2), (4, 9), (4, 10), (4, 11), (6, 0), (6, 1), (6, 2), (6, 9), (6, 10), (6, 11), (7, 0), (7, 1), (7, 2), (7, 9), (7, 10), (7, 11)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 2), (16, 2), (17, 2), (18, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 4, 5, 8, 11)
Dice 2: (0, 1, 2, 3, 9, 12)
The 36 possible combinations: [(0, 0), (0, 1), (0, 2), (0, 3), (0, 9), (0, 12), (1, 0), (1, 1), (1, 2), (1, 3), (1, 9), (1, 12), (4, 0), (4, 1), (4, 2), (4, 3), (4, 9), (4, 12), (5, 0), (5, 1), (5, 2), (5, 3), (5, 9), (5, 12), (8, 0), (8, 1), (8, 2), (8, 3), (8, 9), (8, 12), (11, 0), (11, 1), (11, 2), (11, 3), (11, 9), (11, 12)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 3), (14, 2), (16, 1), (17, 2), (20, 2), (23, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 4, 5, 8, 12)
Dice 2: (0, 1, 2, 3, 9, 11)
The 36 possible combinations: [(0, 0), (0, 1), (0, 2), (0, 3), (0, 9), (0, 11), (1, 0), (1, 1), (1, 2), (1, 3), (1, 9), (1, 11), (4, 0), (4, 1), (4, 2), (4, 3), (4, 9), (4, 11), (5, 0), (5, 1), (5, 2), (5, 3), (5, 9), (5, 11), (8, 0), (8, 1), (8, 2), (8, 3), (8, 9), (8, 11), (12, 0), (12, 1), (12, 2), (12, 3), (12, 9), (12, 11)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 2), (16, 1), (17, 1), (19, 1), (21, 1), (23, 1)]
Found a pair of dice that have equal probability of summing to a value from 1 to 12!
Dice 1: (0, 1, 5, 6, 11, 12)
Dice 2: (0, 1, 2, 3, 4, 10)
The 36 possible combinations: [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 10), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 10), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 10), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 10), (11, 0), (11, 1), (11, 2), (11, 3), (11, 4), (11, 10), (12, 0), (12, 1), (12, 2), (12, 3), (12, 4), (12, 10)]
And their respective sums: [(0, 1), (1, 2), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2), (7, 2), (8, 2), (9, 2), (10, 2), (11, 2), (12, 2), (13, 2), (14, 2), (15, 3), (16, 2), (21, 1), (22, 1)]
&amp;quot;&amp;quot;&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can see that there are actually five unique solutions if you restrict your pips from 1 to 12:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Dice 1: (0, 1, 2, 3, 4, 10)
Dice 2: (0, 1, 5, 6, 11, 12)

Dice 1: (0, 1, 2, 3, 9, 11)
Dice 2: (0, 1, 4, 5, 8, 12)

Dice 1: (0, 1, 2, 3, 9, 12)
Dice 2: (0, 1, 4, 5, 8, 11)

Dice 1: (0, 1, 2, 9, 10, 11)
Dice 2: (0, 1, 3, 4, 6, 7)

Dice 1: (0, 1, 3, 4, 6, 7)
Dice 2: (0, 1, 2, 9, 10, 11)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in fact there are lots more solutions (infinitely many, actually!)
if you do not restrict the numbers you use in each face of the die from 1 to 12.
For example, this is a possible solution:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Found a pair of dice that have equal probability of summing to any value from 1 to 12!
Dice 1: (1, 2, 3, 10, 11, 14)
Dice 2: (0, 3, 6, 11, 13, 14)
The 36 possible combinations: [(1, 0), (1, 3), (1, 6), (1, 11), (1, 13), (1, 14), (2, 0), (2, 3), (2, 6), (2, 11), (2, 13), (2, 14), (3, 0), (3, 3), (3, 6), (3, 11), (3, 13), (3, 14), (10, 0), (10, 3), (10, 6), (10, 11), (10, 13), (10, 14), (11, 0), (11, 3), (11, 6), (11, 11), (11, 13), (11, 14), (14, 0), (14, 3), (14, 6), (14, 11), (14, 13), (14, 14)]
And their respective sums: [(1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 2), (14, 4), (15, 2), (16, 3), (17, 3), (20, 1), (21, 1), (22, 1), (23, 1), (24, 2), (25, 2), (27, 1), (28, 1)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can of course replace the numbers 13 and 14 by any other whole numbers that are larger,
which would not change the result.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>tl;dr of my Politics undergraduate thesis</title>
    <link href="https://lieuzhenghong.com/thesis_tldr/"/>
    <updated>2021-05-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/thesis_tldr/</id>
    <content type="html">&lt;h1 id=&quot;thesis-tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;Thesis TL;DR&lt;/h1&gt;
&lt;h2 id=&quot;abstract&quot; tabindex=&quot;-1&quot;&gt;Abstract&lt;/h2&gt;
&lt;p&gt;How should electoral districts be drawn? In the U.S., many states attempt to limit gerrymandering by requiring that districts be &amp;quot;reasonably compact&amp;quot;, but also require that plans respect &amp;quot;the integrity of communities of interest&amp;quot;. Yet mandating compactness may come at the cost of communities of interest. In order to achieve a compact district shape, one may need to disregard communities of interest and assemble highly heterogeneous districts as a result, adversely affecting democratic outcomes like representation and responsiveness. Are compactness and community fundamentally conflicting goals?&lt;/p&gt;
&lt;p&gt;I make two contributions in this work. First, I develop a new compactness metric---human compactness---that improves upon previous measures by incorporating a notion of travel times. Second, I use a Markov Chain Monte Carlo (MCMC) approach to generate a large sample of districting plans. I find mixed evidence for a trade-off between compactness and homogeneity depending on the compactness measure used. I further find that my human compactness measure consistently identifies more homogeneous districts, suggesting that a judicious choice of compactness metric can in fact encourage keeping communities of interest together.&lt;/p&gt;
&lt;h2 id=&quot;introduction-(front-part)&quot; tabindex=&quot;-1&quot;&gt;Introduction (front part)&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;We care about how districts are drawn because of representation:
formalistic and descriptive/substantial representation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Formalistic representation is about accountability: gerrymandering
lets incumbents stay in power regardless of their performance and
are thus unaccountable.
Hence legislators have tried to prevent this using compactness measures&lt;/p&gt;
&lt;p&gt;Descriptive/substantial representation is about their
elected representatives fighting for their electorate&#39;s interest:
this is usually best done when districts are homogeneous/
keep communities of interest together&lt;/p&gt;
&lt;p&gt;However, one might think that compactness and district homogeneity
would come apart: a perfect square might be very compact
but cleave a community of interest in two, that sort of stuff.
So we want to know if there&#39;s a tradeoff
and my thesis addresses this.&lt;/p&gt;
&lt;h2 id=&quot;two-key-research-questions&quot; tabindex=&quot;-1&quot;&gt;Two key research questions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Is there a tradeoff between compactness and communities of interest?&lt;/li&gt;
&lt;li&gt;Do some compactness measures better encompass communities of interest than others?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;methodology&quot; tabindex=&quot;-1&quot;&gt;Methodology&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Generate a large and representative subset of plausible districting plans&lt;/li&gt;
&lt;li&gt;Evaluate compactness and spatial diversity scores on that subset of plans&lt;/li&gt;
&lt;li&gt;Analyse the overall relationship between compactness and communities of interest (as operationalised by spatial diversity)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;human-compactness-and-why-the-inter-voter-distance-is-important&quot; tabindex=&quot;-1&quot;&gt;Human compactness and why the inter-voter distance is important&lt;/h2&gt;
&lt;p&gt;&amp;quot;Paramount to the idea of single-member districts is that there is great value in voters who live in the same area being put in the same district. Eubank and Rodden [2019] write:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Voters in the same area are likely to share political interests; voters in the same area are better able to communicate and coordinate with one another; politicians can better maintain connections with voters in the same area; voters in the same area are especially likely to belong to the same social communities --- all suggest the importance of voters being located in districts with their geographic peers.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Due to the fact that voters in the same area share many things in common, A point-wise distance measure that tries to put people together in the same district could be a remedy for the key claim levied against compactness---that it splits communities of interest. A wealth of empirical evidence supports the above statement. \cite{arzheimer2012} find that constituents support less strongly candidates that live far from them, even controlling for strong predictors of vote choice like party feeling and socio-economic distance. Similarly, \cite{dyck2005} find that voters living further away from a voting site are less likely to turn out to vote. In part, voters strongly support proximate candidates because they think that these candidates better represent their interests. If voters prefer a representative who lives close to them, then we can satisfy the most voters by drawing districts where everyone lives close to everyone else---only then can that district have a representative who lives close to everybody.&lt;/p&gt;
&lt;p&gt;In contrast, districts that put people with unrelated, faraway others carve voters out of their natural communities and are thus to be avoided. We care about whether co-districtors live in the same area and belong to the same communities of interest, not just the compactness of their electoral district. And point-wise distance metrics deliver exactly that.j&lt;/p&gt;
&lt;h2 id=&quot;why-euclidean-distance-is-insufficient&quot; tabindex=&quot;-1&quot;&gt;Why Euclidean distance is insufficient&lt;/h2&gt;
&lt;p&gt;&amp;quot;Suppose there is a city on a hill example&amp;quot;&lt;/p&gt;
&lt;p&gt;Suppose there is a city on a hill. On the West side is [a] mild, long incline toward the rest of the city, which is in a plane. On the East side is a steep cliff, either impassable or with just a narrow, winding road that very few people use. While the next residential center to the East is much closer to the hilltop on a horizontal plane, it is much further on all sorts of distances that we think might matter: transportation time, intensity of social interactions, sets of shared local public goods and common interests, etc. Thus, for all practical purposes, one probably wants to include the hilltop in a Western district rather than an Eastern one. More general notions of distance can handle this.&lt;/p&gt;
&lt;p&gt;Here we see the key problem with using Euclidean distances in point-wise distance metrics. The &amp;quot;impassable&amp;quot; region on the East would have a short Euclidean distance, and any districting plan that put the hilltop with the Eastern district would be unfairly penalised by these point-wise distance metrics. Evidently, using driving durations instead would give us more accurate scores. Using driving durations, the impassable region would have a long driving duration, accurately reflecting the political geography. In this and many other cases like it (e.g. large bodies of water), driving durations better reflect a state&#39;s unique political geographies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; let&#39;s see if we can find these in real life&lt;/p&gt;
&lt;h2 id=&quot;what-i-actually-did&quot; tabindex=&quot;-1&quot;&gt;What I actually did&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Use Recom neutral ensemble to generate 10,000 districting plans for each state&lt;/li&gt;
&lt;li&gt;Calculate spatial diversity and all compactness scores&lt;/li&gt;
&lt;li&gt;DO data analysis:
&lt;ul&gt;
&lt;li&gt;Some initial analysis looking at New Hampshire and Idaho
showing that there is a difference in the best plans under each compactness measure&lt;/li&gt;
&lt;li&gt;Correlation matrix showing that compacntess measures correlate with one another but human compactness less so:
&amp;quot;this result is encouraging because it shows that these metrics are able to get at the same concept of compactness despite having completely different theoretical backgrounds&amp;quot;.&lt;/li&gt;
&lt;li&gt;Did some scatterplots that basically say the same thing:
compactness measures are similar but not too similar&lt;/li&gt;
&lt;li&gt;Spatial diversity varies a lot between states but little within states: may be due to the fact that the plans I generate are meant to resemble plans that a non-partisan districting committee would draw&lt;/li&gt;
&lt;li&gt;KDE plot of districts and spatial diversity: the smaller (by area)
the district, the higher the diversity. Most probably an urban-rural effect.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Data analysis part 2:
&lt;ul&gt;
&lt;li&gt;Running multivariate OLS regressions with country dummies finds no effect of different compactness measures on spatial diversity; only human compactness sees a significant negative effect&lt;/li&gt;
&lt;li&gt;Previously we were doing the regression with &lt;em&gt;all&lt;/em&gt; of the plans: now consider the &lt;em&gt;subset&lt;/em&gt; of plans:
&lt;ul&gt;
&lt;li&gt;I look at Top 100/90/75/25/10%, 5% plans under each compactness measure and find similar results (5% and 2% sample size too small for significance but coefficient is the same)&lt;/li&gt;
&lt;li&gt;I look at the mean spatial diversity of the top plans under each compactness measure, performing a difference in means test.
Only human compactness has a mean spatial diversity significantly lower than the mean spatial diversity of all plans.&lt;/li&gt;
&lt;li&gt;I then perform a more robust difference in means test:
I look at the mean spatial diversity of the most compact plans &lt;em&gt;of each state&lt;/em&gt;, and compare it with the mean spatial diversity of all plans, and again, human compactness beats them all&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;what-needs-to-be-done-next&quot; tabindex=&quot;-1&quot;&gt;What needs to be done next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;One thing we could do is run all the correlations and difference-in-means tests with Euclidean distance human compactness.
I suspect that there won&#39;t be much of a difference
(possibly nothing that approaches statistical significance)&lt;/li&gt;
&lt;li&gt;The other thing we could do is after running all of them with Euclidean distance
human compactness, find states/plans where they differ a lot
and see where they differ&lt;/li&gt;
&lt;li&gt;Another thing we could do if we don&#39;t want to run it on all the plans is to pick a plan, calculate ED human compactness for each point in that plan,
and compare that to DD human compactness. See if they meaningfully differ.&lt;/li&gt;
&lt;li&gt;Either way we have to come up with the Euclidean distance metric and generate plans. If only we had a pipeline to make this faster.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>MMODiscord: Run your own virtual world on any Discord server</title>
    <link href="https://lieuzhenghong.com/building_a_virtual_world_atop_discord/"/>
    <updated>2021-04-07T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/building_a_virtual_world_atop_discord/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/juxd/discord-spatial-layer&quot;&gt;https://github.com/juxd/discord-spatial-layer&lt;/a&gt;
&lt;a href=&quot;https://devpost.com/software/mmodiscord&quot;&gt;Hackathon submission link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For NUS HackNRoll 2021
(a hackathon organised by National University of Singapore)
we set out to build
a virtual world that can sit on top of any Discord server
(working name: &lt;strong&gt;MMODiscord&lt;/strong&gt;).
This post will be in two parts:
first, I&#39;m going to share what we built,
and then I&#39;m going to share The Dream: what it could be, and why we would want it.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/RyYKZtXubXs&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h2 id=&quot;what-we-built-and-why-we-built-it&quot; tabindex=&quot;-1&quot;&gt;What we built and why we built it&lt;/h2&gt;
&lt;p&gt;In lieu of an actual childhood, I fondly recall hanging out and chatting with
my friends in Henesys Market and fishing/cutting trees together in
RuneScape&#39;s Draynor Village.&lt;/p&gt;
&lt;p&gt;There&#39;s something uniquely magical about that sort of experience, and I&#39;m
pretty sure it&#39;s not just the nostalgia talking. They seem to better fulfil
the raw and real human need for connection.&lt;/p&gt;
&lt;p&gt;While has been solved somewhat by chat/social apps
such as MSN Messenger, Telegram, and Discord,
I&#39;ve always felt that they never came close to the fun I had
just sitting around in the FM with my friends.
Useful as they are, something is missing from these apps.&lt;/p&gt;
&lt;p&gt;What is missing? What&#39;s that &lt;em&gt;je ne sais quoi&lt;/em&gt;?
I believe it&#39;s &lt;em&gt;spatiality&lt;/em&gt; and &lt;em&gt;interactiveness&lt;/em&gt;.
Hanging out in Maple or RS is especially compelling because
it has something more than just chat.
You can see your friends in the world and hang out together in a virtual space.
I&#39;ve &lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/&quot;&gt;written about this before&lt;/a&gt;. You can express yourself with your movement, fashion choices, skills, facial emotions, and so on.&lt;/p&gt;
&lt;p&gt;So we know that game worlds have advantages.
They&#39;re more spatial, more interactive, more immersive, more compelling.
So what if we could get the best of both worlds?
What if we had a spatial &amp;quot;layer&amp;quot; that sits on top of the social apps we know and love?&lt;/p&gt;
&lt;p&gt;The &amp;quot;spatial layer&amp;quot; we built has the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Connects seamlessly to your Discord account&lt;/li&gt;
&lt;li&gt;Move around and chat&lt;/li&gt;
&lt;li&gt;Chat appears above your head&lt;/li&gt;
&lt;li&gt;Use number keys 1-5 to change your mood (corresponds to MapleStory)&lt;/li&gt;
&lt;li&gt;Available both as a standalone webpage and as a Google Chrome extension (see submitted links)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My thinking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/planning_to_build_discord_server_layer/&quot;&gt;Planning to build a Discord server layer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/gameworlds_for_hyperlocal_communities/&quot;&gt;Gameworlds for hyperlocal commmunities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-to-use&quot; tabindex=&quot;-1&quot;&gt;How to use&lt;/h2&gt;
&lt;p&gt;We came up with a custom authentication solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Type !joinspace into the server you&#39;d like to; our bot DMs a secret to the user&lt;/li&gt;
&lt;li&gt;Navigate to our GitHub Pages link
&lt;a href=&quot;https://juxd.github.io/discord-spatial-layer/&quot;&gt;here&lt;/a&gt;
IF ON FIREFOX type in &lt;code&gt;about:config&lt;/code&gt; in the URL bar,
&lt;code&gt;and set &lt;/code&gt;network.websocket.allowInsecureFromHTTPS&lt;code&gt;to&lt;/code&gt;true`&lt;/li&gt;
&lt;li&gt;Enter secret into the GitHub Pages link&lt;/li&gt;
&lt;li&gt;You have now joined the spatial layer and can move around, chat and use emojis.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;technical-details&quot; tabindex=&quot;-1&quot;&gt;Technical details&lt;/h2&gt;
&lt;p&gt;We used a couple of libraries:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Discord API for the Discord bot&lt;/li&gt;
&lt;li&gt;Nengi for the multiplayer networking&lt;/li&gt;
&lt;li&gt;PixiJS for the rendering engine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We built the server auth flow ourselves. The primary challenge is how to match the Discord user with the person who joins the game, so when you type !joinspace our bot will DM you a secret (e.g. &amp;quot;chubby-flappy-bird&amp;quot;). The server knows which secret it&#39;s given to which Discord user, so when you enter the secret and join the server we can then assign you the right avatar.&lt;/p&gt;
&lt;h2 id=&quot;difficulties-and-things-we&#39;ve-learned&quot; tabindex=&quot;-1&quot;&gt;Difficulties and things we&#39;ve learned&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dexter: &amp;quot;I wasted a day on a Chrome Extension&amp;quot;&lt;/li&gt;
&lt;li&gt;Vignesh: &amp;quot;Bro it&#39;s a hackathon there&#39;s nothing to think you just do&amp;quot;&lt;/li&gt;
&lt;li&gt;Julius: We adapted well but we could have a better job at understanding what we wanted.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;why-would-anyone-use-this%3F-what-is-the-point-of-it-all%3F&quot; tabindex=&quot;-1&quot;&gt;Why would anyone use this? What is the point of it all?&lt;/h2&gt;
&lt;p&gt;There are lots of startups in this space like Gather Town, but (in my opinion) they won&#39;t get much traction because they aim to be a tool, not a community. We want to build something that piggybacks on--supplants--the communities already existing in groups like Discord and Telegram.&lt;/p&gt;
&lt;p&gt;Why not just play a game instead? Our spatial layer is really lightweight and
doesn&#39;t require a download: good luck getting the 1,000 people on your server
to download 20GB of game.&lt;/p&gt;
&lt;h2 id=&quot;extensions&quot; tabindex=&quot;-1&quot;&gt;Extensions&lt;/h2&gt;
&lt;p&gt;We&#39;ve built a base of movement and chat, the two most important features. We want to give more activities for users to do and increase Discord integration. For instance, we want to allow users to play games with Discord bots like catch Pokemon, farm, fish, etc. We want to build persistent user and server storage. We also want to allow each server to place objects in and customise the look of their server.&lt;/p&gt;
&lt;p&gt;We might want to give players of this gameworld something to do:
the equivalent of Maki Bot in Discord servers.&lt;/p&gt;
&lt;p&gt;Different servers would have different tilesets (like server-specific emoji)
and construct their gameworld differently.
One server might use a generic tileset to build a massive mediaeval castle
while another might use a cyberpunk-inspired tileset to build Night City.
This would allow for easy customisation of the space.&lt;/p&gt;
&lt;p&gt;It would be really cool if we could allow fellow HnR participants
to code their own equivalent of Bots:
maybe expose some API where we allow squares and players to have
arbitrary metadata associated with them,
and allow getters and setters on that arbitrary metadata.&lt;/p&gt;
&lt;p&gt;At the most basic and boring level, for instance,
a bot could be written to assign players a &amp;quot;Fame&amp;quot; score (just an integer).
And players could interact by faming or defaming other players.
But more complicated interactions could exist.
What if a bot assigned each square a &lt;code&gt;terrain&lt;/code&gt; metadata type
and you could fish on squares with &lt;code&gt;terrain:water&lt;/code&gt;?
This would be an API call to a Discord bot
which would then update your player&#39;s &lt;code&gt;inventory&lt;/code&gt; metadata field
to have a random fish?
What if you wrote a bot that could trade items between players?
There are tons of possibilities.&lt;/p&gt;
&lt;h2 id=&quot;why-not-just-play-an-mmo%3F-or-use-second-life%3F&quot; tabindex=&quot;-1&quot;&gt;Why not just play an MMO? Or use Second Life?&lt;/h2&gt;
&lt;p&gt;(WIP section)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A discord server is already a community and you want to
build something on top of it, not try to transplant/supplant
the existing community&lt;/li&gt;
&lt;li&gt;zero friction is important! how can you possibly convince
everyone in your server to move to a game&lt;/li&gt;
&lt;li&gt;very lightweight layer not a entire game is a feature&lt;/li&gt;
&lt;li&gt;the layer is completely optional so you can
still have the same community even when not in the game&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-stuff-we-could-do&quot; tabindex=&quot;-1&quot;&gt;Other stuff we could do&lt;/h2&gt;
&lt;p&gt;This is an instantiation of the following meta-level principle of building
&lt;em&gt;worlds for hyperlocal communities&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meta-level: build X ( tinder, facebook, twitter, a game world, etc... ) for a hyperlocal community (the HnR discord server, Telegram group)&lt;/li&gt;
&lt;li&gt;meta-meta-level: build Y that allows us to build some X for any hyperlocal community&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like the meta idea of building something over the hyperlocal community.
Weineng suggested something like Tinder or FB but only for HnR participants.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Some ways to deal with big(-ish) data: &#39;why do we get an OutOfMemory error in FPGrowth?&#39;</title>
    <link href="https://lieuzhenghong.com/handling_bigish_data/"/>
    <updated>2021-03-31T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/handling_bigish_data/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#solution-1%3A-use-a-bigger-machine-(vertical-scaling)&quot;&gt;Solution 1: use a bigger machine (vertical scaling)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#solution-2%3A-use-apache-spark-(horizontal-scaling)&quot;&gt;Solution 2: use Apache Spark (horizontal scaling)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#solution-3%3A-replace-mlxtend&#39;s-source-code-(software-solution)&quot;&gt;Solution 3: replace mlxtend&amp;#39;s source code (software solution)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#conclusions&quot;&gt;Conclusions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/handling_bigish_data/#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;p&gt;(Written for work)&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Xin Zheng mentioned that she was running out of memory
when running the &lt;em&gt;a priori&lt;/em&gt; and &lt;em&gt;FP Growth&lt;/em&gt; algorithms
for the recommender systems project.&lt;/p&gt;
&lt;p&gt;After some research, I found the reason for the error,
and here I present a few solutions
which might help other data scientists too.&lt;/p&gt;
&lt;p&gt;Thanks also to Siyang for being a sounding board for my ideas.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;Xin Zheng mentioned that she was running out of memory
when running the &lt;em&gt;a priori&lt;/em&gt; and &lt;em&gt;FP Growth&lt;/em&gt; algorithms
These algorithms are used to generate frequent itemsets
(items that are frequently bought together by customers)
so that we can recommend similar items to purchase.&lt;/p&gt;
&lt;p&gt;This is the section of her code that was throwing the error:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
FP growth algo for product association rules calculation
* input item order-product name matrix
* output rules
&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pandas &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; pd
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; mlxtend&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frequent_patterns &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; fpgrowth
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; mlxtend&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frequent_patterns &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; association_rules
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; time

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FPGrowthRules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; df_matrix&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min_support&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min_confidence&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        frequent_itemsets &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fpgrowth&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df_matrix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min_support&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;min_support&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; use_colnames&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# ... stuff elided ...&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; rules&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In particular, it was this invocation of &lt;code&gt;fpgrowth&lt;/code&gt; from the &lt;code&gt;mlxtend&lt;/code&gt; package:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;frequent_itemsets &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fpgrowth&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df_matrix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min_support&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;min_support&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; use_colnames&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;fpgrowth&lt;/code&gt; takes in a DataFrame and returns a DataFrame.
In particular, it gets frequent itemsets for a one-hot DataFrame.
A one-hot DataFrame looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        Apple  Bananas   Beer  Chicken   Milk   Rice
    0   True    False   True     True  False   True
    1   True    False   True    False  False   True
    2   True    False   True    False  False  False
    3   True     True  False    False  False  False
    4  False    False   True     True   True   True
    5  False    False   True    False   True   True
    6  False    False   True    False   True  False
    7   True     True  False    False  False  False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;fpgrowth&lt;/code&gt; returns a pandas DataFrame with columns [&#39;support&#39;, &#39;itemsets&#39;]
of all itemsets that are &amp;gt;= &lt;code&gt;min_support&lt;/code&gt; and &amp;lt; &lt;code&gt;max_len&lt;/code&gt;.
You can find usage examples
&lt;a href=&quot;http://rasbt.github.io/mlxtend/user_guide/frequent_patterns/fpgrowth/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After looking at her code and the source code of the &lt;code&gt;mlxtend&lt;/code&gt; library,
I found the error and came up with three plausible solutions,
each having their own set of advantages and disadvantages.&lt;/p&gt;
&lt;h2 id=&quot;solution-1%3A-use-a-bigger-machine-(vertical-scaling)&quot; tabindex=&quot;-1&quot;&gt;Solution 1: use a bigger machine (vertical scaling)&lt;/h2&gt;
&lt;p&gt;The simplest way to solve the out-of-memory issue is to use a larger machine.
XZ&#39;s machine (27GB of RAM and 10GB of disk) runs out of memory,
but 27GB is not that much memory in the grand scheme of things;
we can get instances with much more memory.&lt;/p&gt;
&lt;p&gt;The pros of this solution is that it requires no developer effort.
The cons are that this will incur additional cost,
and the TP we pass it to may not be able to spin up larger machines.
And of course, this solution is not very scalable because
there&#39;s a hard cap on the amount of memory we can provision.
So if the out-of-memory issue is caused by some &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(n^2)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; scaling or worse,
this would not be a good solution.&lt;/p&gt;
&lt;h2 id=&quot;solution-2%3A-use-apache-spark-(horizontal-scaling)&quot; tabindex=&quot;-1&quot;&gt;Solution 2: use Apache Spark (horizontal scaling)&lt;/h2&gt;
&lt;p&gt;One more complicated way is to use Apache Spark to scale out.
This involves rewriting Xin Zheng&#39;s code as a Spark job
and using a parallel, Spark-friendly version of &lt;code&gt;fpgrowth&lt;/code&gt;.
We would then find some way to spin up a Spark cluster and
run the Spark job.&lt;/p&gt;
&lt;p&gt;The pros of this solution is that it can scale to much larger datasets.
The cons are that it introduces a lot of technical complexity
both in the code, and in the deployment.
It will also make testing more difficult.
Additionally, TPs may not have the technical chops to provision
their own spark cluster.&lt;/p&gt;
&lt;h2 id=&quot;solution-3%3A-replace-mlxtend&#39;s-source-code-(software-solution)&quot; tabindex=&quot;-1&quot;&gt;Solution 3: replace mlxtend&#39;s source code (software solution)&lt;/h2&gt;
&lt;p&gt;The last solution requires us to actually understand the problem.
Let&#39;s figure out exactly what is causing the OOM error.&lt;/p&gt;
&lt;p&gt;Recall that &lt;code&gt;fpgrowth&lt;/code&gt; takes in a one-hot DataFrame that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;        Apple  Bananas   Beer  Chicken   Milk   Rice
    0   True    False   True     True  False   True
    1   True    False   True    False  False   True
    2   True    False   True    False  False  False
    3   True     True  False    False  False  False
    4  False    False   True     True   True   True
    5  False    False   True    False   True   True
    6  False    False   True    False   True  False
    7   True     True  False    False  False  False
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and returns a pandas DataFrame with columns [&#39;support&#39;, &#39;itemsets&#39;]
of all itemsets that are &amp;gt;= &lt;code&gt;min_support&lt;/code&gt; and &amp;lt; &lt;code&gt;max_len&lt;/code&gt;.
It&#39;s clear that the smaller &lt;code&gt;min_support&lt;/code&gt; is, the more itemsets will be returned.
If &lt;code&gt;min_support&lt;/code&gt; is small enough we will get an &lt;code&gt;OutOfMemory&lt;/code&gt; error.&lt;/p&gt;
&lt;p&gt;But how are these itemsets generated?
Can we pin down the exact line that is causing the error?
How do we fix the &lt;code&gt;OutOfMemory&lt;/code&gt; error?&lt;/p&gt;
&lt;p&gt;Let&#39;s dive into the &lt;code&gt;fpgrowth&lt;/code&gt; source code
&lt;a href=&quot;https://github.com/rasbt/mlxtend/blob/f2ce3b2ba5692fbb44c2894b99f0d59b80d056eb/mlxtend/frequent_patterns/fpgrowth.py#L11&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;We can see that the &lt;code&gt;fpgrowth&lt;/code&gt; function calls &lt;code&gt;fpc.setup_fptree&lt;/code&gt; on line 84
to create a class called an &lt;code&gt;FPTree&lt;/code&gt;,
then uses this tree class to run &lt;code&gt;fgp_step&lt;/code&gt; recursively.&lt;/p&gt;
&lt;p&gt;I did some additional digging and found the most likely cause:
line &lt;code&gt;113&lt;/code&gt; inside &lt;code&gt;fpg_step&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fpg_step&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; max_len&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    size_remain &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; max_len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tree&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cond_items&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_remain&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; itemset &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; itertools&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;combinations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# &amp;lt;-- this line!&lt;/span&gt;
        count &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
        support &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;tree&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;count &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; itemset&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; support&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tree&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cond_items &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;itertools.combinations(items,i)&lt;/code&gt; is almost certainly causing the OOM error.&lt;br&gt;
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac linethickness=&quot;0px&quot;&gt;&lt;mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;items \choose i&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.2557em;vertical-align:-0.35em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9057em;&quot;&gt;&lt;span style=&quot;top:-2.355em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.144em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.345em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; where &lt;code&gt;items&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt; are large
will give a very big number,
on the order of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;Θ&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\Theta(items^i).&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0747em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;Θ&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8247em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
(see the Appendix for an explanation).
So &lt;code&gt;itemsets&lt;/code&gt; grows non-polynomially with the size of the DataFrame.
But this itself is not the problem, because &lt;code&gt;itertools&lt;/code&gt;
returns a generator, which will not OOM.
Rather, it&#39;s the line immediately &lt;em&gt;after&lt;/em&gt; it,
&lt;code&gt;fpc.generate_itemsets&lt;/code&gt;,
that is the issue:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fpgrowth.py&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fpgrowth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# ....&lt;/span&gt;
    generator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fpg_step&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tree&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; minsup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colname_map&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max_len&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; verbose&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; fpc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;generate_itemsets&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;generator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colname_map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# &amp;lt;- this line&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# fpcommon.py&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generate_itemsets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;generator&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_itemsets&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colname_map&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    itemsets &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    supports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; sup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; iset &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; generator&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        itemsets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;frozenset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        supports&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sup &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; num_itemsets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    res_df &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataFrame&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;support&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; supports&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;itemsets&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; itemsets&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; colname_map &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        res_df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;itemsets&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; res_df&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;itemsets&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; \
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;lambda&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;frozenset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;colname_map&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; res_df&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the &lt;code&gt;generate_itemsets&lt;/code&gt; function
we can see that &lt;code&gt;itemsets&lt;/code&gt; and &lt;code&gt;supports&lt;/code&gt;
are appended to for each itemset.
And we know that there are &lt;em&gt;a lot&lt;/em&gt; of itemsets.
This causes the OOM error.&lt;/p&gt;
&lt;p&gt;So what can we do? There are several possible solutions.
First is simply to use a higher &lt;code&gt;min_support&lt;/code&gt; value so that we don&#39;t run out of memory.
But this is of course not a solution so much as it is giving up.
I think one &lt;em&gt;real&lt;/em&gt; solution is to generate the DataFrame in chunks,
and persist it in disk.
This way we don&#39;t have to append all itemsets to &lt;code&gt;itemsets&lt;/code&gt; before generating the DataFrame.&lt;/p&gt;
&lt;p&gt;What are the pros and cons of this solution?
This solution does not need any additional hardware or cost:
this is a pure software solution.
This would also be the easiest to hand over to the TP,
as it introduces no additional technical complexity.&lt;/p&gt;
&lt;p&gt;The con is that this would require us to make a pull request
to the &lt;code&gt;mlxtend&lt;/code&gt; repo, which may or may not be accepted.
We must also find a way to make the returned chunked DataFrame compatible
with just a regular, non-chunked DataFrame.
But if accepted this would be a public service to others using the repo too.
I know Siyang has made PRs to an open-source library in the past
that have been well-received by the community.&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot; tabindex=&quot;-1&quot;&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I think one key takeaway here is to understand the problem domain well,
and not to be afraid to dig into the source code.
Knowing what we now know about the problem domain,
it&#39;s clear that solution 1 would not be sufficient
as the output size explodes with an increase in input size.
Solution 2 does work but involves significant technical complexity.
In my opinion solution 3 is probably best.&lt;/p&gt;
&lt;p&gt;We could also sidestep the problem entirely:
reduce &lt;code&gt;size_remain&lt;/code&gt; or &lt;code&gt;items&lt;/code&gt; by setting a larger &lt;code&gt;min_support&lt;/code&gt; threshold.
I know this is what XZ has been working on.
This does come at the expense of accuracy/not having enough recommendations, however.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to Siyang and XZ for telling me about this problem.&lt;/p&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;items&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt; grow as &lt;code&gt;min_support&lt;/code&gt; shinks.&lt;/p&gt;
&lt;p&gt;We can see this by looking at the source code for &lt;code&gt;setup_fptree&lt;/code&gt;
(&lt;a href=&quot;https://github.com/rasbt/mlxtend/blob/f2ce3b2ba5692fbb44c2894b99f0d59b80d056eb/mlxtend/frequent_patterns/fpcommon.py#L28&quot;&gt;here&lt;/a&gt;).
The line is &lt;code&gt;items = np.nonzero(item_support &amp;gt;= min_support)[0]&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Notes on AWS&#39;s serverless framework</title>
    <link href="https://lieuzhenghong.com/aws_serverless_guide/"/>
    <updated>2021-03-24T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/aws_serverless_guide/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#api-gateway%2Faws-lambda&quot;&gt;API Gateway/AWS Lambda&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#the-api-gateway&#39;s-request-response-cycle-in-detail&quot;&gt;The API Gateway&amp;#39;s request-response cycle in detail&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-does-it-mean-to-%22configure-as-proxy-resource%22%3F&quot;&gt;What does it mean to &amp;quot;configure as proxy resource&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-%22api-gateway-cors%22%3F&quot;&gt;What is &amp;quot;API Gateway CORS&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-%22lambda-proxy-integration%22%3F&quot;&gt;What is &amp;quot;Lambda Proxy Integration&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#how-do-i-see-what-the-integration-receives%2Flogs%3F&quot;&gt;How do I see what the integration receives/logs?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-are-%22body-mapping-templates%22-and-why-would-we-use-this%3F&quot;&gt;What are &amp;quot;body mapping templates&amp;quot; and why would we use this?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-are-%22variable-path-parameters%22%3F&quot;&gt;What are &amp;quot;variable path parameters&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#how-does-aws-custom-authorisation-work%3F&quot;&gt;How does AWS Custom authorisation work?&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#api-gateway-lambda-authorization-workflow&quot;&gt;API Gateway Lambda authorization workflow&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#gotchas&quot;&gt;Gotchas&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-do-i-do-if-i-get-an-%22unsupported-media-type-error%22-on-the-client-side%3F&quot;&gt;What do I do if I get an &amp;quot;Unsupported Media Type Error&amp;quot; on the client side?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#things-to-learn&quot;&gt;Things to learn&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#how-do-iam-policies-work%3F-what-happens-when-the-lambda-authoriser-returns-an-iam-policy%3F&quot;&gt;How do IAM policies work? What happens when the Lambda authoriser returns an IAM policy?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#how-do-cors-headers-work%3F&quot;&gt;How do CORS headers work?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what&#39;s-a-swagger-definition%3F&quot;&gt;What&amp;#39;s a Swagger definition?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what&#39;s-the-difference-between-the-integration-response-step-and-the-method-response-step%3F&quot;&gt;What&amp;#39;s the difference between the Integration Response step and the Method Response step?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#dynamodb&quot;&gt;DynamoDB&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-a-partition-key%3F&quot;&gt;What is a Partition Key?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-a-global-secondary-index%3F-what&#39;s-a-local-secondary-index%3F&quot;&gt;What is a Global Secondary Index? What&amp;#39;s a Local Secondary Index?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-read-and-write-capacity%3F&quot;&gt;What is read and write capacity?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what&#39;s-the-difference-between-scan()-and-getitem()%3F&quot;&gt;What&amp;#39;s the difference between scan() and getItem()?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#gotchas-1&quot;&gt;Gotchas&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#why-do-i-get-an-access-denied-exception%3F&quot;&gt;Why do I get an Access Denied Exception?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#aws-cognito&quot;&gt;AWS Cognito&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#cognito-flow&quot;&gt;Cognito flow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what-is-a-cognito-user-pool%3F&quot;&gt;What is a Cognito User Pool?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what&#39;s-an-app-client%3F&quot;&gt;What&amp;#39;s an App Client?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#authenticationdetails-object&quot;&gt;AuthenticationDetails object&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#cognitouser-object&quot;&gt;CognitoUser object&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#cognitousersession-object%3F&quot;&gt;CognitoUserSession object?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#what&#39;s-the-difference-between-cognitoaccesstoken%2C-cognitoidtoken%2C-and-cognitorefreshtoken%3F&quot;&gt;What&amp;#39;s the difference between CognitoAccessToken, CognitoIdToken, and CognitoRefreshToken?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#this.getauthenticateduser().signout()&quot;&gt;this.getAuthenticatedUser().signOut()&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#this.authservice.getauthenticateduser().getsession()&quot;&gt;this.authService.getAuthenticatedUser().getSession()&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#cognitoidentityserviceprovider&quot;&gt;CognitoIdentityServiceProvider&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#why-would-you-use-query-string-parameters-to-pass-tokens%3F&quot;&gt;Why would you use query string parameters to pass tokens?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#gotchas-2&quot;&gt;Gotchas&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#why-do-i-receive-a-empty-userid-when-using-cognito-authoriser%3F&quot;&gt;Why do I receive a empty userId when using Cognito authoriser?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#security&quot;&gt;Security&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aws_serverless_guide/#bibliography&quot;&gt;Bibliography&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;p&gt;(written for work)&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;On Hui Lim&#39;s recommmendation,
I&#39;m working through the following courses to familiarise myself
with the AWS Serverless framework:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://learncsc.udemy.com/course/aws-serverless-a-complete-introduction/learn/lecture/7275232#overview&quot;&gt;Get into serverless computing with API Gateway, AWS Lambda and other Amazon Web Services! Zero server config APIs &amp;amp; SPAs, by Maximilian Schwartzmuller&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learncsc.udemy.com/course/aws-serverless-a-complete-introduction/learn/lecture/7275232#overview&quot;&gt;Learn how to develop reliable and scalable back-end applications effortlessly using Serverless Framework, by Ariel Weinberger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&#39;m learning a lot from these courses and I don&#39;t want to forget this stuff,
so I&#39;m writing it down as notes.&lt;/p&gt;
&lt;p&gt;Maximilian&#39;s course covers the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Gateway&lt;/li&gt;
&lt;li&gt;AWS Lambda&lt;/li&gt;
&lt;li&gt;DynamoDB&lt;/li&gt;
&lt;li&gt;AWS Cognito&lt;/li&gt;
&lt;li&gt;S3&lt;/li&gt;
&lt;li&gt;AWS Route53&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of the course focuses on manual setup of the API Gateway
and DynamoDB via the web portal
which is of course automatable by AWS&#39;s CLI.
But going through the UI and doing the manual setup
actually helps a lot to understand the &amp;quot;big picture&amp;quot;:
the structure of the entire AWS ecosystem,
the API gateway, and so on.&lt;/p&gt;
&lt;p&gt;Ariel&#39;s course covers some of the same ground of
Maximilian&#39;s.
I&#39;ll be working through it very shortly and writing my notes here too.&lt;/p&gt;
&lt;h2 id=&quot;api-gateway%2Faws-lambda&quot; tabindex=&quot;-1&quot;&gt;API Gateway/AWS Lambda&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.alexdebrie.com/posts/api-gateway-elements/#step-0-protecting-your-api-with-authorization-and-usage-plans&quot;&gt;Alex de Brie&#39;s &amp;quot;A Detailed Overview of AWS API Gateway&lt;/a&gt;
is a great overview, and is the source of the following image:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/aws_serverless/gateway_architecture.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are six main steps in the AWS Gateway request-response cycle.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Method Request: in this step we validate the incoming request
to make sure it corresponds to a particular JSON schema.
This simplifies the backend/error handling code.&lt;/li&gt;
&lt;li&gt;Integration Request: transforms the client&#39;s request into a
shape that the server/Lambda function can read.&lt;/li&gt;
&lt;li&gt;Integration: the API gateway sends the request to
the backend server/Lambda function, which receives the request
and does stuff with it (sends an email, reads/writes a DB,
performs a calculation...).&lt;/li&gt;
&lt;li&gt;Integration Response: this replaces the result of the lambda
function with a function that the API Gateway can receive.&lt;/li&gt;
&lt;li&gt;Method Response: this returns a response with a proper HTTP
response code.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-api-gateway&#39;s-request-response-cycle-in-detail&quot; tabindex=&quot;-1&quot;&gt;The API Gateway&#39;s request-response cycle in detail&lt;/h3&gt;
&lt;p&gt;Six steps, five if you ignore the actual integration
because it&#39;s not part of the API Gateway:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Method Request&lt;/li&gt;
&lt;li&gt;Integration Request&lt;/li&gt;
&lt;li&gt;(actual integration -- lambda function or other backend service)&lt;/li&gt;
&lt;li&gt;Integration Response&lt;/li&gt;
&lt;li&gt;Method Response&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first gatekeeper is authentication:
this can use a custom (lambda) authoriser,
or use Amazon&#39;s Cognito authoriser. More on this later.&lt;/p&gt;
&lt;p&gt;The Method Request step
validates the incoming request to make sure it
adheres to a particular model
(has particular fields, etc).&lt;/p&gt;
&lt;p&gt;If it does then we move to the Integration Request:
transforming incoming
data into a shape we want to use on the action
we&#39;re about to trigger.
A transformation can be done using the
Velocity Template Language (VTL)
to add headers, metadata, auth info, and so on.
One good usecase for this is in retrofitting
a new JSON API to an existing older backend.
For example, your server might accept only &lt;code&gt;application/xml&lt;/code&gt;
while your requests are in &lt;code&gt;application/json&lt;/code&gt;.
This is where you would translate your incoming
request inoto a format the server can read.&lt;/p&gt;
&lt;p&gt;Then of course you move on to the actual integration
step, where a backend (or Lambda function of your choice)
is run. This Lambda function&lt;/p&gt;
&lt;p&gt;Integration response: this is the return of the lambda
function, resolved calculation/db look up etc.&lt;/p&gt;
&lt;p&gt;Method Response shapes the response received by the client&lt;/p&gt;
&lt;h3 id=&quot;what-does-it-mean-to-%22configure-as-proxy-resource%22%3F&quot; tabindex=&quot;-1&quot;&gt;What does it mean to &amp;quot;configure as proxy resource&amp;quot;?&lt;/h3&gt;
&lt;p&gt;Means catch-all: catch all requests.&lt;/p&gt;
&lt;p&gt;If you catch all incoming requests,
you can create your own router&lt;/p&gt;
&lt;h3 id=&quot;what-is-%22api-gateway-cors%22%3F&quot; tabindex=&quot;-1&quot;&gt;What is &amp;quot;API Gateway CORS&amp;quot;?&lt;/h3&gt;
&lt;p&gt;CORS: cross origin resource sharing.&lt;/p&gt;
&lt;p&gt;Imagine your SPA runs on example.com
and the API runs on api.com.
When the SPA tries to ask for a request from &lt;code&gt;api.com&lt;/code&gt;,
the browser will prevent this request from being handled,
so api.com needs to send some &amp;quot;preflight headers&amp;quot;
that will convince the browser that it&#39;s OK
(but what if api.com is malicious?)
before this cross-domain request will be allowed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;Access-Control-Allow-Headers&amp;quot; allow&lt;/li&gt;
&lt;li&gt;&amp;quot;Access-Control-Allow-Origin&amp;quot;: all domains may send these requests and therefore we&#39;re good to go.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-is-%22lambda-proxy-integration%22%3F&quot; tabindex=&quot;-1&quot;&gt;What is &amp;quot;Lambda Proxy Integration&amp;quot;?&lt;/h3&gt;
&lt;p&gt;use incoming metadata like headers and authentication etc
to pass that unfiltered data over to the lambda&lt;/p&gt;
&lt;p&gt;This also means that the Lambda function will be responsible for handling the authentication
rather than the integration request&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-see-what-the-integration-receives%2Flogs%3F&quot; tabindex=&quot;-1&quot;&gt;How do I see what the integration receives/logs?&lt;/h3&gt;
&lt;p&gt;Use AWS Cloudwatch.&lt;/p&gt;
&lt;h3 id=&quot;what-are-%22body-mapping-templates%22-and-why-would-we-use-this%3F&quot; tabindex=&quot;-1&quot;&gt;What are &amp;quot;body mapping templates&amp;quot; and why would we use this?&lt;/h3&gt;
&lt;p&gt;We can use body mapping templates to transform the result
of a lambda function into a more standardised form.
Why would we do this?
If you have a lambda function that returns a value
but your client is expecting a particular response schema,
you can use the body mapping template inside the integration response step
to transform it.&lt;/p&gt;
&lt;p&gt;Similarly in the integration request step we can also use this template language
to edit the request body your integration receives.
I&#39;ve given an example above:&lt;/p&gt;
&lt;h3 id=&quot;what-are-%22variable-path-parameters%22%3F&quot; tabindex=&quot;-1&quot;&gt;What are &amp;quot;variable path parameters&amp;quot;?&lt;/h3&gt;
&lt;p&gt;Variable path parameters allow you to run the same Lambda function
with different input parameters (path parameters).
For example, GET request to &lt;code&gt;/all&lt;/code&gt; vs GET request to &lt;code&gt;/single&lt;/code&gt;
can be handled with the path parameter on resource &lt;code&gt;/{type}&lt;/code&gt;
and then in the Integration Request
we can get this path parameter by doing &lt;code&gt;$input.type&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can use query parameters too &lt;code&gt;?someParam=someValue&lt;/code&gt;;
use them for validation and extract them with templates.&lt;/p&gt;
&lt;h3 id=&quot;how-does-aws-custom-authorisation-work%3F&quot; tabindex=&quot;-1&quot;&gt;How does AWS Custom authorisation work?&lt;/h3&gt;
&lt;p&gt;We can create a custom authoriser (also called Lambda authoriser)
on the Method Request step.&lt;/p&gt;
&lt;p&gt;The custom authoriser is a Lambda function
that takes in some information from the incoming request
(specifically, an authorisation token).
That function will run some code to validate/identify that user,
and returns an IAM policy to us + a user ID + optional &amp;quot;context&amp;quot;.&lt;/p&gt;
&lt;p&gt;If the auth token is missing or invalid the IAM policy will
give a rejection via a Gateway Response.
A Gateway Response is a &amp;quot;short-circuit&amp;quot; response
returned by the API Gateway; it&#39;s a response that is returned
before the request hits the backend.&lt;/p&gt;
&lt;p&gt;If it is a success then this 3-tuple will then
be passed it into the next step, the Method Request step.
(? Is it the Method Request step ?)
&amp;quot;This context will be added to the event object in your backing Lambda function&amp;quot;&lt;/p&gt;
&lt;h4 id=&quot;api-gateway-lambda-authorization-workflow&quot; tabindex=&quot;-1&quot;&gt;API Gateway Lambda authorization workflow&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/aws_serverless/lambda_auth_workflow.png&quot; alt=&quot;Lambda authorizer Auth workflow&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html#api-gateway-lambda-authorizer-flow&quot;&gt;source: AWS docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;First, the client calls a method on an API Gateway API method,
passing a bearer token or request parameters.
The API Gateway checks whether a Lambda authorizer is configured for the method.
If it is, API Gateway calls the Lambda function.&lt;/p&gt;
&lt;p&gt;The Lambda function authenticates the caller by means such as the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calling out to an OAuth provider to get an OAuth access token.&lt;/li&gt;
&lt;li&gt;Calling out to a SAML provider to get a SAML assertion.&lt;/li&gt;
&lt;li&gt;Generating an IAM policy based on the request parameter values.&lt;/li&gt;
&lt;li&gt;Retrieving credentials from a database.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the call succeeds, the Lambda function grants access by returning an output object containing at least an IAM policy and a principal identifier.&lt;/p&gt;
&lt;p&gt;API Gateway evaluates the policy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If access is denied, API Gateway returns a suitable HTTP status code, such as 403 ACCESS_DENIED.&lt;/li&gt;
&lt;li&gt;If access is allowed, API Gateway executes the method. If caching is enabled in the authorizer settings, API Gateway also caches the policy so that the Lambda authorizer function doesn&#39;t need to be invoked again.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;gotchas&quot; tabindex=&quot;-1&quot;&gt;Gotchas&lt;/h3&gt;
&lt;h4 id=&quot;what-do-i-do-if-i-get-an-%22unsupported-media-type-error%22-on-the-client-side%3F&quot; tabindex=&quot;-1&quot;&gt;What do I do if I get an &amp;quot;Unsupported Media Type Error&amp;quot; on the client side?&lt;/h4&gt;
&lt;p&gt;Make sure to set content-type to &lt;code&gt;application/json&lt;/code&gt; rather than &lt;code&gt;text/plain&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;things-to-learn&quot; tabindex=&quot;-1&quot;&gt;Things to learn&lt;/h3&gt;
&lt;h4 id=&quot;how-do-iam-policies-work%3F-what-happens-when-the-lambda-authoriser-returns-an-iam-policy%3F&quot; tabindex=&quot;-1&quot;&gt;How do IAM policies work? What happens when the Lambda authoriser returns an IAM policy?&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html&quot;&gt;IAM policy docs&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;how-do-cors-headers-work%3F&quot; tabindex=&quot;-1&quot;&gt;How do CORS headers work?&lt;/h4&gt;
&lt;h4 id=&quot;what&#39;s-a-swagger-definition%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a Swagger definition?&lt;/h4&gt;
&lt;h4 id=&quot;what&#39;s-the-difference-between-the-integration-response-step-and-the-method-response-step%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between the Integration Response step and the Method Response step?&lt;/h4&gt;
&lt;p&gt;Integration responses transform the response from the
backend lambda function (which can be any value at all)
into a response that &lt;em&gt;API Gateway&lt;/em&gt; can handle.&lt;/p&gt;
&lt;p&gt;Method responses validate the &lt;em&gt;output&lt;/em&gt; to the client.
You must first create your method repsonses before you can use a
given status code in an integration response.
(source: Alex de Brie)&lt;/p&gt;
&lt;p&gt;You can use a VTL template to transform the response
in both the integration response step
and the method response step (? is this true?)&lt;/p&gt;
&lt;h2 id=&quot;dynamodb&quot; tabindex=&quot;-1&quot;&gt;DynamoDB&lt;/h2&gt;
&lt;h3 id=&quot;what-is-a-partition-key%3F&quot; tabindex=&quot;-1&quot;&gt;What is a Partition Key?&lt;/h3&gt;
&lt;p&gt;A partition key must be unique.&lt;/p&gt;
&lt;p&gt;DynamoDB allows you to use a partition key PLUS a sort key
as a primary key, where the combination has to be unique.&lt;/p&gt;
&lt;p&gt;Why is it called a partition key?
Because these keys are assigned to different partitions.
(Are they hashed?)&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-global-secondary-index%3F-what&#39;s-a-local-secondary-index%3F&quot; tabindex=&quot;-1&quot;&gt;What is a Global Secondary Index? What&#39;s a Local Secondary Index?&lt;/h3&gt;
&lt;h3 id=&quot;what-is-read-and-write-capacity%3F&quot; tabindex=&quot;-1&quot;&gt;What is read and write capacity?&lt;/h3&gt;
&lt;p&gt;You provision certain read and write capacity units: kilobytes read/written per second.
You can also just use on demand.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-scan()-and-getitem()%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between &lt;code&gt;scan()&lt;/code&gt; and &lt;code&gt;getItem()&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;scan()&lt;/code&gt; returns an array, &lt;code&gt;getItem&lt;/code&gt; returns only one item.&lt;/p&gt;
&lt;h3 id=&quot;gotchas-1&quot; tabindex=&quot;-1&quot;&gt;Gotchas&lt;/h3&gt;
&lt;h4 id=&quot;why-do-i-get-an-access-denied-exception%3F&quot; tabindex=&quot;-1&quot;&gt;Why do I get an Access Denied Exception?&lt;/h4&gt;
&lt;p&gt;You haven&#39;t set permissions right:
you need to give your lambda function the correct DynamoDB policy.&lt;/p&gt;
&lt;h2 id=&quot;aws-cognito&quot; tabindex=&quot;-1&quot;&gt;AWS Cognito&lt;/h2&gt;
&lt;h3 id=&quot;cognito-flow&quot; tabindex=&quot;-1&quot;&gt;Cognito flow&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Initialise &lt;code&gt;UserPoolId&lt;/code&gt; and &lt;code&gt;ClientId&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a new &lt;code&gt;CognitoUserPool&lt;/code&gt;. It is this object that will be used behind the scenes.&lt;/li&gt;
&lt;li&gt;Create a new attribute object (standard attribute)&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;CognitoUserAttribute&lt;/code&gt; array&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;userPool.signUp&lt;/code&gt; method with username, password, attributeList, and callback function that gets executed once Cognito is done.&lt;/li&gt;
&lt;li&gt;Cognito should actually send you an email and you should be able to verify.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After signup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialise a &lt;code&gt;CognitoUser&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;CognitoUser.authenticateUser()&lt;/code&gt; with &lt;code&gt;AuthenticationDetails&lt;/code&gt;
and a callback function.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-is-a-cognito-user-pool%3F&quot; tabindex=&quot;-1&quot;&gt;What is a Cognito User Pool?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools.html&quot;&gt;Amazon Cognito user pools documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A user pool is a user directory in Amazon Cognito.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-an-app-client%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s an App Client?&lt;/h3&gt;
&lt;p&gt;App clients have access to the user pool.
Neither user pool ID nor app client ID are secrets.&lt;/p&gt;
&lt;h3 id=&quot;authenticationdetails-object&quot; tabindex=&quot;-1&quot;&gt;AuthenticationDetails object&lt;/h3&gt;
&lt;p&gt;Should contain username and password&lt;/p&gt;
&lt;h3 id=&quot;cognitouser-object&quot; tabindex=&quot;-1&quot;&gt;CognitoUser object&lt;/h3&gt;
&lt;p&gt;should be initialised with a username and userPool.&lt;/p&gt;
&lt;h3 id=&quot;cognitousersession-object%3F&quot; tabindex=&quot;-1&quot;&gt;CognitoUserSession object?&lt;/h3&gt;
&lt;p&gt;CognitoUserSession will give you JWTs:
CognitoAccessToken,
CognitoIdToken,
and CognitoRefreshToken.&lt;/p&gt;
&lt;p&gt;authIsLoading&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-cognitoaccesstoken%2C-cognitoidtoken%2C-and-cognitorefreshtoken%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between CognitoAccessToken, CognitoIdToken, and CognitoRefreshToken?&lt;/h3&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h3 id=&quot;this.getauthenticateduser().signout()&quot; tabindex=&quot;-1&quot;&gt;this.getAuthenticatedUser().signOut()&lt;/h3&gt;
&lt;p&gt;will actually delete the localstorage tokens&lt;/p&gt;
&lt;h3 id=&quot;this.authservice.getauthenticateduser().getsession()&quot; tabindex=&quot;-1&quot;&gt;this.authService.getAuthenticatedUser().getSession()&lt;/h3&gt;
&lt;p&gt;checks if tokens are still valid&lt;/p&gt;
&lt;h3 id=&quot;cognitoidentityserviceprovider&quot; tabindex=&quot;-1&quot;&gt;CognitoIdentityServiceProvider&lt;/h3&gt;
&lt;h3 id=&quot;why-would-you-use-query-string-parameters-to-pass-tokens%3F&quot; tabindex=&quot;-1&quot;&gt;Why would you use query string parameters to pass tokens?&lt;/h3&gt;
&lt;p&gt;Rather than passing it in the body request/headers?
It seems like that would be bad because this would allow MITMs
to use your token&lt;/p&gt;
&lt;h3 id=&quot;gotchas-2&quot; tabindex=&quot;-1&quot;&gt;Gotchas&lt;/h3&gt;
&lt;h4 id=&quot;why-do-i-receive-a-empty-userid-when-using-cognito-authoriser%3F&quot; tabindex=&quot;-1&quot;&gt;Why do I receive a empty userId when using Cognito authoriser?&lt;/h4&gt;
&lt;p&gt;When using Cognito user authoriser,
our existing body mapping template will not get the userId with
&lt;code&gt;$context.authorizer.principalId&lt;/code&gt;.
Instead, we need to use &lt;code&gt;$context.authorizer.claims.sub&lt;/code&gt;
to get the userID.&lt;/p&gt;
&lt;h2 id=&quot;security&quot; tabindex=&quot;-1&quot;&gt;Security&lt;/h2&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to Hui Lim for sending me these excellent courses.&lt;/p&gt;
&lt;h2 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/chegg/creating-an-api-gateway-lambda-authorizer-985b4f011770&quot;&gt;Singh, 2020. Creating an API Gateway Lambda Authorizer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alexdebrie.com/posts/api-gateway-elements/#step-0-protecting-your-api-with-authorization-and-usage-plans&quot;&gt;Alex de Brie&#39;s &amp;quot;A Detailed Overview of AWS API Gateway&lt;/a&gt;
is a great overview, and is the source of the following image:&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.alexdebrie.com/posts/lambda-custom-authorizers/&quot;&gt;de Brie. Lambda custom authorizers.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@markpgreen10/using-vtl-in-api-gateway-to-restructure-data-bc9dd6573630&quot;&gt;Green 2018&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Notes on Dynamo (2007)</title>
    <link href="https://lieuzhenghong.com/dynamo_notes/"/>
    <updated>2021-03-20T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/dynamo_notes/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#the-big-picture&quot;&gt;The big picture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#big-ideas&quot;&gt;Big ideas&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#consistent-hashing-allows-incremental-scalability&quot;&gt;Consistent hashing allows incremental scalability&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#why-do-we-need-to-hash%3F&quot;&gt;Why do we need to hash?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#what-is-consistent-hashing-and-how-does-it-allow-for-incremental-scalability%3F&quot;&gt;What is consistent hashing and how does it allow for incremental scalability?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-do-we-use-consistent-hashing%3F&quot;&gt;How do we use consistent hashing?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-are-nodes-assigned-to-keys&quot;&gt;How are nodes assigned to keys&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-does-consistent-hashing-allow-scalability%3F&quot;&gt;How does consistent hashing allow scalability?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-does-consistent-hashing-allow-replication%3F&quot;&gt;How does consistent hashing allow replication?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#having-virtual-nodes-(tokens)-improves-on-consistent-hashing&quot;&gt;Having virtual nodes (tokens) improves on consistent hashing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-does-one-assign-nodes-to-keys%3F&quot;&gt;How does one assign nodes to keys?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#vector-clocks-and-hinted-handoff-allows-for-an-always-writable-database&quot;&gt;Vector clocks and hinted handoff allows for an always-writable database&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#so-what-exactly-happens-in-a-read%2Fwrite%3F&quot;&gt;So what exactly happens in a read/write?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-vector-clocks-are-used-in-reads%2Fwrites&quot;&gt;How vector clocks are used in reads/writes&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#handling-failures&quot;&gt;Handling failures&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#hinted-handoff&quot;&gt;Hinted handoff&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#replica-synchronisation&quot;&gt;Replica synchronisation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#membership-and-failure-detection&quot;&gt;Membership and failure detection&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-this-relates-to-other-database-designs&quot;&gt;How this relates to other database designs&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#dynamo-vs-aurora&quot;&gt;Dynamo vs Aurora&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#dynamo-vs-memcached&quot;&gt;Dynamo vs Memcached&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#what-are-the-three-different-partitioning-strategies-and-why-is-the-third-one-best%3F&quot;&gt;What are the three different partitioning strategies and why is the third one best?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#what-are-the-parameters-r%2C-w%2C-and-n%3F-assuming-there&#39;s-no-%22hinted-handoff%22%2C-how-many-node-failures-can-the-system-tolerate-while-still-ensuring-that-successful-read-operations-return-up-to-date-data%3F&quot;&gt;What are the parameters R, W, and N? Assuming there&amp;#39;s no &amp;quot;hinted handoff&amp;quot;, how many node failures can the system tolerate while still ensuring that successful read operations return up-to-date data?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#what&#39;s-%22eventual-consistency%22%2C-and-what-are-some-advantages-and-disadvantages%3F-what&#39;s-a-specific-example-of-behaviour-that-could-happen-under-this-consistency-model%3F&quot;&gt;What&amp;#39;s &amp;quot;eventual consistency&amp;quot;, and what are some advantages and disadvantages? What&amp;#39;s a specific example of behaviour that could happen under this consistency model?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-does-%22consistent-hashing%22-(compared-to%2C-say%2C-~hash(key)-%25-n~)-reduce-the-amount-of-data-that-needs-to-be-moved-when-a-node-joins-or-leaves-the-cluster%3F&quot;&gt;How does &amp;quot;consistent hashing&amp;quot; (compared to, say, ~hash(key) % N~) reduce the amount of data that needs to be moved when a node joins or leaves the cluster?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#where-is-the-configuration-information-stored%3F-how-is-it-kept-consistent%3F&quot;&gt;Where is the configuration information stored? How is it kept consistent?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#why-is-dynamo-only-eventually-consistent%3F-how-can-divergent-histories-form-even-with-a-3-2-2-quorum-setup%3F&quot;&gt;Why is Dynamo only eventually consistent? How can divergent histories form even with a 3-2-2 quorum setup?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#questions-in-the-lecture-notes&quot;&gt;Questions in the lecture notes&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#suppose-dynamo-server-s1-is-perfectly-healthy-with-a-working-network-connection.-by-mistake%2C-an-administrator-instructs-server-s2-to-remove-s1-using-the-mechanisms-described-in-4.8.1-and-4.9.-it-takes-a-while-for-the-membership-change-to-propagate-from-s2-to-the-rest-of-the-system-(including-s1)%2C-so-for-a-while-some-clients-and-servers-will-think-that-s1-is-still-part-of-the-system.-will-dynamo-operate-correctly-in-this-situation%3F-why%2C-or-why-not%3F&quot;&gt;Suppose Dynamo server S1 is perfectly healthy with a working network connection. By mistake, an administrator instructs server S2 to remove S1 using the mechanisms described in 4.8.1 and 4.9. It takes a while for the membership change to propagate from S2 to the rest of the system (including S1), so for a while some clients and servers will think that S1 is still part of the system. Will Dynamo operate correctly in this situation? Why, or why not?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#how-does-dynamo-recover-from-permanent-failure----what-is-anti-entropy-using-merkle-trees%3F&quot;&gt;How does Dynamo recover from permanent failure -- what is anti-entropy using Merkle trees?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#some-deeper-questions&quot;&gt;Some deeper questions&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#considerations%2Fimplications-for-database-design%3F&quot;&gt;Considerations/implications for database design?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/#bibliography&quot;&gt;Bibliography&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I read the following the paper as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This week we discussed the paper
&lt;a href=&quot;https://files.lieu.gg/docs/DeCandia%20et%20al.%20(2007).%20Dynamo--Amazon&#39;s%20Highly%20Available%20Key-Value%20Store.pdf&quot;&gt;DeCandia et al. (2007). Dynamo: Amazon&#39;s Highly Available Key-value Store&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some useful links are the
&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/notes/l-dynamo.txt&quot;&gt;6.824 lecture notes&lt;/a&gt;
and the
&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/papers/dynamo-faq.txt&quot;&gt;6.824 lecture FAQ&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-big-picture&quot; tabindex=&quot;-1&quot;&gt;The big picture&lt;/h2&gt;
&lt;p&gt;Dynamo is trying to build a distributed key-value store
focusing on &lt;em&gt;write availability&lt;/em&gt; and &lt;em&gt;write latency&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Motivation:
Amazon doesn&#39;t need a RDBMS for many of its services,
only a key-value store:
&amp;quot;There are many services on Amazon&#39;s platform that only need primary-key access to a data store... for many services... the common pattern of using a relational database &lt;em&gt;would lead to inefficiencies and limit scale and availability&lt;/em&gt;.&amp;quot;&lt;/p&gt;
&lt;p&gt;So we have a more relaxed operations model:
we only require getting and setting keys.
However, there are two things we care about a lot:&lt;/p&gt;
&lt;p&gt;Firstly, Amazon cares a lot about latency,
because any weak link in the chain will result in cascading latencies on the rest of the services.&lt;/p&gt;
&lt;p&gt;Secondly, we want it to be always writeable
despite failures.
In traditional systems, &amp;quot;writes may be rejected
if the data store cannot reach a majority of the replicas
at a given time.&amp;quot; This is unacceptable to Amazon:
e.g. you can&#39;t have Amazon reject adding items to shopping carts.
Here Amazon allows you to tweak the parameters:
if you &lt;em&gt;always&lt;/em&gt; want writes to succeed,
you can set &lt;code&gt;W&lt;/code&gt; to 1, which ensures that a write
is accepted as long as a single node in the system
has durably written the key to its local store.
&amp;quot;However, in practice, most Amazon services in production
set a higher W to meet the desired level of durability.&amp;quot;&lt;/p&gt;
&lt;p&gt;Also, we don&#39;t care about consistency so much:
&amp;quot;data stores that provide ACID guarantees tend to have
poor availability.&amp;quot;
Instead DynamoDB guarantees &lt;em&gt;eventual&lt;/em&gt; consistency.&lt;/p&gt;
&lt;h2 id=&quot;big-ideas&quot; tabindex=&quot;-1&quot;&gt;Big ideas&lt;/h2&gt;
&lt;h3 id=&quot;consistent-hashing-allows-incremental-scalability&quot; tabindex=&quot;-1&quot;&gt;Consistent hashing allows incremental scalability&lt;/h3&gt;
&lt;p&gt;Dynamo uses consistent hashing,
which allows nodes to be added and removed on-demand
very quickly. Let&#39;s see how it does this.&lt;/p&gt;
&lt;h4 id=&quot;why-do-we-need-to-hash%3F&quot; tabindex=&quot;-1&quot;&gt;Why do we need to hash?&lt;/h4&gt;
&lt;p&gt;Before talking about consistent hashing,
let&#39;s talk about hashing.
Why hash?
We hash in order to allocate keys evenly to nodes.
Each node is responsible for only a small set
of keys (called its &lt;em&gt;range&lt;/em&gt;),
because the number of keys is too large
for any single node to hold.&lt;/p&gt;
&lt;p&gt;When a node receives a read or write request
for a key,
it will hash it,
then check if that hash is in its range.
If it is then it will service that request.
If it receives a request for a key
not in its range, it will forward the request
to the correct node.
(How does it know who to forward the request to?
More on this later.)&lt;/p&gt;
&lt;h4 id=&quot;what-is-consistent-hashing-and-how-does-it-allow-for-incremental-scalability%3F&quot; tabindex=&quot;-1&quot;&gt;What is consistent hashing and how does it allow for incremental scalability?&lt;/h4&gt;
&lt;p&gt;OK, so that&#39;s hashing.
What about &lt;em&gt;consistent&lt;/em&gt; hashing?
The idea of consistent hashing is to simply
wrap the range around, so the largest value
wraps around to the smallest value.
Wikipedia says that consistent hashing
is a special kind of hashing such that
when a hash table is resized,
only a few keys need to be remapped on average.&lt;/p&gt;
&lt;p&gt;Why is this necessary?
We&#39;ll soon see that consistent hashing
allows incremental scaling
in the sense that adding a new node only
changes the keys of N nodes (where N is small -- 3),
while using non-consistent hashing would
require all keys to be remapped on average.&lt;/p&gt;
&lt;h4 id=&quot;how-do-we-use-consistent-hashing%3F&quot; tabindex=&quot;-1&quot;&gt;How do we use consistent hashing?&lt;/h4&gt;
&lt;p&gt;So in consistent hashing the key space is mapped to
a big circle where the largest hash value
(in this case, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msup&gt;&lt;mn&gt;28&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2^128 - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8974em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) wraps back to zero.&lt;/p&gt;
&lt;p&gt;Note that consistent hashing is a different
thing from &lt;em&gt;replicating the data on multiple nodes&lt;/em&gt;.
Consistent hashing &lt;em&gt;allows for&lt;/em&gt; replication
and scalability,
but you can use consistent hashing without replication.&lt;/p&gt;
&lt;h4 id=&quot;how-are-nodes-assigned-to-keys&quot; tabindex=&quot;-1&quot;&gt;How are nodes assigned to keys&lt;/h4&gt;
&lt;p&gt;Each node is randomly assigned a point on the
consistent hashing circle,
and it&#39;s responsible for
&lt;em&gt;all points between it and the previous node on the circle&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/dynamo/strategy1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The above figure illustrates.
Here the key k1
lies between the node to its left (not labeled)
and the node to its right (A).
So A is responsible for key k1.&lt;/p&gt;
&lt;h4 id=&quot;how-does-consistent-hashing-allow-scalability%3F&quot; tabindex=&quot;-1&quot;&gt;How does consistent hashing allow scalability?&lt;/h4&gt;
&lt;p&gt;Recall that nodes are assigned to a key range
using random assignment.
What happens when we have to add or remove a node?
If we remove a node then we must make sure that
that node&#39;s key range is somehow given to the remaining nodes.
And conversely if we add a node then we must
&amp;quot;steal&amp;quot; some keys from all the nodes to give to the new node.
Consistent hashing allows us to do this affecting the minimum amount of nodes.&lt;/p&gt;
&lt;p&gt;Let&#39;s compare what happens when we add a node under
consistent hashing versus non-consistent hashing.
Suppose you had a 3-bit hash function &lt;code&gt;hash(key)&lt;/code&gt; that mapped keys
uniformly to an integer in range[0, 7] inclusive.
And suppose that you had three nodes so each &lt;code&gt;hash(key) mod 3&lt;/code&gt;
would give a key of 0, 1 or 2.
Let&#39;s look at how each of the keys maps in mod3:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 : 0
1 : 1
2 : 2
3 : 0
4 : 1
5 : 2
6 : 0
7 : 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now suppose a new node enters the cluster
The key insight is that almost all of the hashes have changed
(I&#39;ve marked the keys that have changed with &lt;strong&gt;asterisks&lt;/strong&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0 : 0
1 : 1
2 : 2
3 : **3**
4 : **0**
5 : **1**
6 : **2**
7 : **3**
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will mean that a vast majority of data (those which mapped to 3--8)
has to be moved from one cluster to another.
In fact, if N is small and the domain of the hash function, K, is large
such that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;msup&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N &amp;lt;&amp;lt; 2^K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7224em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8413em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8413em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, almost all of the data will have to be moved.
The same is true if we remove a node from the cluster.&lt;/p&gt;
&lt;p&gt;Consistent hashing avoids this problem.
In the basic version of consistent hashing each hash is assigned
to a node with the first ID larger than it,
and each node is randomly assigned a key value.
Again we&#39;ll use the three-bit hash function with three machines.
Here&#39;s a very badly-drawn circle with the three nodes denoted with asterisks.
In this case the three nodes have been assigned 0, 2 and 5 respectively.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     *0
  7     1
6        *2 
  *5   3
     4

0 : 2
1 : 2
2 : 5
3 : 5
4 : 5
5 : 0
6 : 0
7 : 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now let&#39;s insert a new node with value (say) 4:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     *0
  7     1
6        *2 
  *5   3
     *4

0 : 2
1 : 2
2 : **4**
3 : **4**
4 : 5
5 : 0
6 : 0
7 : 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, only the nodes in between 2 and 5
need to be moved.&lt;/p&gt;
&lt;p&gt;In general, using consistent hashing means that
adding or removing a new node only requires minimal
inter-node communication/key range changes,
which allows for scalability.&lt;/p&gt;
&lt;h4 id=&quot;how-does-consistent-hashing-allow-replication%3F&quot; tabindex=&quot;-1&quot;&gt;How does consistent hashing allow replication?&lt;/h4&gt;
&lt;p&gt;In order to ensure durability/availability,
you can&#39;t have only one node save the data.
The data must be replicated over multiple nodes:
&lt;code&gt;N&lt;/code&gt; nodes, to be exact.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/dynamo/fig2.png&quot; alt=&quot;Figure 2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2 illustrates how this is done.
The N-1 nodes clockwise of the key range
replicate the keys of that node.
The keys that fall within &lt;code&gt;(A, B]&lt;/code&gt;
are the purview of B.
The two other nodes C and D that lie &lt;em&gt;clockwise&lt;/em&gt;
of B will replicate this key range too.&lt;/p&gt;
&lt;p&gt;There&#39;s the idea of a &lt;em&gt;preference list&lt;/em&gt;:
a preference list is the list of &lt;em&gt;physical&lt;/em&gt; nodes
responsible for storing a particular key.
(We&#39;ll see why I mention the word &lt;em&gt;physical&lt;/em&gt; later.)&lt;/p&gt;
&lt;h4 id=&quot;having-virtual-nodes-(tokens)-improves-on-consistent-hashing&quot; tabindex=&quot;-1&quot;&gt;Having virtual nodes (tokens) improves on consistent hashing&lt;/h4&gt;
&lt;p&gt;Section 4.2 of the Dynamo paper:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The basic consistent hashing algorithm presents some challenges.
First, the random position assignment of each node on the
ring leads to non-uniform data and load distribution.
Second, the basic algorithm is oblivious to the hetereogeneity
in the performance of nodes.
To address this issues... instead of mapping a node to a single
point in the circle, each node gets assigned to multiple points
in the ring... Dynamo uses the concept of &amp;quot;virtual nodes&amp;quot;.
A virtual node looks like a single node in the system, but each node
can be responsible for more than one virtual node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why is this an improvement? The MIT Aurora FAQ says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;They are a scheme to balance the keys nicely across all nodes.
If you throw N
balls in B bins, you get on average B/N balls in a bin but
some bins may have
many balls. To ensure that all bins are close to the average,
you can place
multiple virtual bins in each real bin.
The average of multiple random variables
has lower variance than a single random variable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;how-does-one-assign-nodes-to-keys%3F&quot; tabindex=&quot;-1&quot;&gt;How does one assign nodes to keys?&lt;/h4&gt;
&lt;p&gt;Amazon actually iterated over three versions of assigning nodes to keys.&lt;/p&gt;
&lt;h3 id=&quot;vector-clocks-and-hinted-handoff-allows-for-an-always-writable-database&quot; tabindex=&quot;-1&quot;&gt;Vector clocks and hinted handoff allows for an always-writable database&lt;/h3&gt;
&lt;p&gt;The next big idea is to allow reads to return not just
a value, but a &lt;em&gt;tree&lt;/em&gt; of possibly-inconsistent values.
This is in effect giving up the consistency property
of &amp;quot;reads must observe the latest write&amp;quot;:
now reads may observe lots of different writes,
one of which is the latest.
If you allow this then you can make your database
always writeable, which is Amazon&#39;s explicit design goal.
We&#39;ll also see how nodes make sense of the different writes.&lt;/p&gt;
&lt;h4 id=&quot;so-what-exactly-happens-in-a-read%2Fwrite%3F&quot; tabindex=&quot;-1&quot;&gt;So what exactly happens in a read/write?&lt;/h4&gt;
&lt;p&gt;Read and write operations involve the first N
healthy nodes in the preference list,
skipping over those that are down or inaccessible.
Whenever a node receives a read or write request on an object,
it will increment its own sequence number.
For a &lt;code&gt;get()&lt;/code&gt; request, the coordinator
requests all existing versions of data for that key
from the N highest-ranked reachable nodes,
then waits for R responses before returning the result
to the client.
&lt;strong&gt;If the coordinator ends up gathering multiple versions
of the data, it returns all the versions it deems to be
causally unrelated.
The divergent versions are then reconciled and
the reconciled version superseding the current versions
is written back&lt;/strong&gt;.
Note that with eventual consistency,
it&#39;s not guaranteed that the data it gets back
reflects all the writes!&lt;/p&gt;
&lt;p&gt;For a &lt;code&gt;put()&lt;/code&gt; request, the coordinator generates
the vector clock for the new version
and writes the new version locally.
In Dynamo, all objects are immutable,
so the only way to change an object is to generate
a new version.
It then sends the new version (along with the new vector clock)
to the N highest ranked &lt;em&gt;reachable&lt;/em&gt; notes.
If at least W-1 nodes respond then the write is considered
successful.&lt;/p&gt;
&lt;h4 id=&quot;how-vector-clocks-are-used-in-reads%2Fwrites&quot; tabindex=&quot;-1&quot;&gt;How vector clocks are used in reads/writes&lt;/h4&gt;
&lt;p&gt;So what&#39;s a vector clock?
A vector clock is effectively a list of &lt;code&gt;(node, counter)&lt;/code&gt;
pairs. &lt;code&gt;List[Tuple[Node, Counter]]&lt;/code&gt;
One vector clock is associated with every version of every object.
(Objects are immutable).
One can determine whether two versions of an object are on parallel branches or have a causal ordering by examining their vector clocks.&lt;/p&gt;
&lt;p&gt;How do we use vector clocks to determine if two versions
of an object are causally ordered or are diverging branches?
&amp;quot;If the counters on the first object&#39;s clock are less-than-or-equal
to all of the nodes in the second clock, then the first
is an ancestor of the second and can be forgotten.
Otherwise, the two changes are considered to be in conflict
and require reconciliation.&amp;quot;&lt;/p&gt;
&lt;h2 id=&quot;handling-failures&quot; tabindex=&quot;-1&quot;&gt;Handling failures&lt;/h2&gt;
&lt;h3 id=&quot;hinted-handoff&quot; tabindex=&quot;-1&quot;&gt;Hinted handoff&lt;/h3&gt;
&lt;p&gt;Dynamo allows writes to return to the caller
before the update has been applied at all the replicas:
&amp;quot;Upon receiving a &lt;code&gt;put()&lt;/code&gt; request for a key,
the coordinator generates the vector clock for the new version
and writes the new version locally. The coordinator
then sends the new version (along with the new vector clock)
to the N highest-ranked &lt;em&gt;reachable&lt;/em&gt; nodes.
If at least &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;W-1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; nodes respond
then the write is considered successful.&amp;quot;&lt;/p&gt;
&lt;p&gt;Note the word &lt;em&gt;reachable&lt;/em&gt; here.
This is what &lt;em&gt;hinted handoff&lt;/em&gt; is:
some less-preferred nodes will help keep some data
meant for the preferred, unreachable node.
and try to periodically re-deliver it to the preferred node
which is temporarily down.
Once the transfer succeeds the less-preferred node
will delete the object from its local store.
This is used for temporary node failures.&lt;/p&gt;
&lt;p&gt;This gives us the &lt;em&gt;eventual consistency&lt;/em&gt; property
any read request will eventually
read all of the values that were written
because the less-preferred nodes will deliver it
to the preferred nodes
as long as fewer than W nodes fail.&lt;/p&gt;
&lt;p&gt;But note that hinted handoff loses consistency.
See the FAQ for this: in particular,
&amp;quot;Why is Dynamo only eventually consistent?&amp;quot;&lt;/p&gt;
&lt;h3 id=&quot;replica-synchronisation&quot; tabindex=&quot;-1&quot;&gt;Replica synchronisation&lt;/h3&gt;
&lt;p&gt;Basically Dynamo compares nodes using Merkle trees,
which allows &lt;code&gt;log(N)&lt;/code&gt; comparisons in the average case.&lt;/p&gt;
&lt;h3 id=&quot;membership-and-failure-detection&quot; tabindex=&quot;-1&quot;&gt;Membership and failure detection&lt;/h3&gt;
&lt;p&gt;Used for permanent node failures.
An administrator manually adds and removes.
Not that interesting IMO.&lt;/p&gt;
&lt;h2 id=&quot;how-this-relates-to-other-database-designs&quot; tabindex=&quot;-1&quot;&gt;How this relates to other database designs&lt;/h2&gt;
&lt;h3 id=&quot;dynamo-vs-aurora&quot; tabindex=&quot;-1&quot;&gt;Dynamo vs Aurora&lt;/h3&gt;
&lt;p&gt;The biggest difference is that
Aurora is a RDBMS, Dynamo is a key-value store.
Although it seems to me that Aurora could easily
be made into a kv-store as well;
since &amp;quot;the log is the database&amp;quot;,
just restrict the set of transactions to be only
get and put.&lt;/p&gt;
&lt;p&gt;In Dynamo every node is capable of receiving a write,
while in Aurora there&#39;s only a single write-capable
replica. This may have scalability implications,
since Aurora is fundamentally limited to one writer.&lt;/p&gt;
&lt;p&gt;In Aurora each storage segment stores
10GB segments of the log;
here each node stores a partition of the entire
key space.
Aurora supports a storage volume up to 64TB;
this is pretty big,
but Dynamo can do even bigger.
Since each node has its own storage,
the storage limit its limited only to the key space.
The key space is 128-bit.
2&lt;strong&gt;32 is 4GB,
2&lt;/strong&gt;64 is 18.4 exabytes, and
2**128 is a ridiculous number.&lt;/p&gt;
&lt;h3 id=&quot;dynamo-vs-memcached&quot; tabindex=&quot;-1&quot;&gt;Dynamo vs Memcached&lt;/h3&gt;
&lt;p&gt;Memcached and Dynamo are both key-value stores.
But they solve very different problems.
Memcached is trying to make reads very fast:
Dynamo is trying to make &lt;em&gt;writes&lt;/em&gt; very fast
(and always available).&lt;/p&gt;
&lt;p&gt;Memcached&#39;s writes are going to be very slow because the writes have to propagate to all the regions
(? is that true?).&lt;/p&gt;
&lt;p&gt;Again there may be differences in storage:
for memcached there must be a single database
instance and that probably bounds the number
of keys you can have,
whereas for Dynamo you could have loads of keys
since each node only holds a small subset of keys.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot; tabindex=&quot;-1&quot;&gt;FAQ&lt;/h2&gt;
&lt;h3 id=&quot;what-are-the-three-different-partitioning-strategies-and-why-is-the-third-one-best%3F&quot; tabindex=&quot;-1&quot;&gt;What are the three different partitioning strategies and why is the third one best?&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/dynamo/three_strategies_for_node_placement.png&quot; alt=&quot;Figure 7&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is the trickiest part of the paper, IMO.
So here we&#39;re talking about how to assign nodes (both real and virtual)
onto the hash space. And there are three approaches.&lt;/p&gt;
&lt;p&gt;The first version and the one that&#39;s explained in section 4.2
is that each node is assigned several virtual nodes (tokens)
and each token is randomly placed on the entire hash space.
Each token is responsible for the keys between it and the token anticlockwise of it. We call this a &lt;em&gt;key range&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But there&#39;s a problem with this.
Section 4.7, Replica synchronisation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The disadvantage with this scheme is that many key ranges change when a
node joins or leaves the system thereby requiring the tree(s) to be
recalculated. This issue is addressed, however, by the refined partitioning
scheme described in Section 6.2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&#39;s explain this a little bit more.
Let&#39;s take a look at Strategy 1 in the diagram.
Let&#39;s call the node to the left of A node O.
When say node A is removed,
the new key range will stretch from O to B.
And that means that node C has to change its key range,
looking up all the new keys individually
and grabbing the keys and so on.
This takes a long time.
As the paper writes, the fundamental issue is that
adding and removing nodes changes the data partitioning.
So let&#39;s try to decouple these things.&lt;/p&gt;
&lt;p&gt;The second approach is a middle-of-the road approach.
You place the tokens exactly where you would in the first version,
(random assignment).
But the difference is in how you assign keys to tokens.
Here the key ranges never change:
instead, the key space is divided into equal-size partitions
and these partitions are then assigned to tokens.
A key is assigned to a token by walking from the &lt;em&gt;end&lt;/em&gt; of its partition.
This approach is better because when a node leaves or is added
the key ranges don&#39;t change,
so you can actually copy and move over partitions wholesale
from one node to another.
Also, you can simply add more nodes without changing the key range,
thus decoupling the partitioning from the number of nodes.&lt;/p&gt;
&lt;p&gt;The third approach is actually really simple.
Again you divide the key space into equal-size partitions,
but the difference here is that instead of placing tokens&lt;br&gt;
randomly along the ring, here you place tokens
&lt;em&gt;uniformly&lt;/em&gt; (but not randomly!) along the ring.
In fact, you assign Q/S tokens to each node,
where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the number of nodes.
And when nodes are added or removed you simply
randomly distribute tokens to or from the nodes
such that each node maintains &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Q&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Q/S&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tokens.
So instead of transferring key ranges from node to node,
you simply transfer &lt;em&gt;token ownership&lt;/em&gt; from node to node
(which of course transfers the attendant tokens as well).&lt;/p&gt;
&lt;h3 id=&quot;what-are-the-parameters-r%2C-w%2C-and-n%3F-assuming-there&#39;s-no-%22hinted-handoff%22%2C-how-many-node-failures-can-the-system-tolerate-while-still-ensuring-that-successful-read-operations-return-up-to-date-data%3F&quot; tabindex=&quot;-1&quot;&gt;What are the parameters R, W, and N? Assuming there&#39;s no &amp;quot;hinted handoff&amp;quot;, how many node failures can the system tolerate while still ensuring that successful read operations return up-to-date data?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;N&lt;/strong&gt; is the number of nodes any data item is replicated to.
&amp;quot;In addition to locally storing each key within its range,
the coordinator replicates these keys at the N-1 clockwise successor nodes
in the ring. This results in a system where each node is responsible for the
region of the ring between it and its Nth predecessor&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;R&lt;/strong&gt; is the minimum number of nodes that must participate in a successful read operation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;W&lt;/strong&gt; is the number of nodes that must participate in a successful write operation.&lt;/p&gt;
&lt;p&gt;&amp;quot;hinted handoff&amp;quot;: a node stores some data that isn&#39;t meant for it,
but keeps a record who it&#39;s &lt;em&gt;meant&lt;/em&gt; to be for, and will
deliver the replica to the intended recipient once
the recipient has recovered.&lt;/p&gt;
&lt;p&gt;Suppose we are looking at the following sequence of events:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;get() call&lt;/li&gt;
&lt;li&gt;put() call&lt;/li&gt;
&lt;li&gt;get() call &amp;lt;--- successful, but must return up-to-date data.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I think the answer to the question depends on
&lt;strong&gt;when&lt;/strong&gt; the nodes fail.
If the nodes fail after the successful put call, then
as little as &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;W&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; nodes need to fail (where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;W &amp;lt; N-W&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7224em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)
in order for subsequent successful get() calls
to no longer be up-to-date.
In the worst-case scenario, all
W nodes that held the latest version of the object written to
have failed, and you lose your updated data
(until you can bring it up again).&lt;/p&gt;
&lt;p&gt;Call this the &lt;em&gt;durability condition&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If however the nodes fail &lt;em&gt;before&lt;/em&gt; the put call
(or even before the first get call),
the maximum number of node failures the system can tolerate is&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;R&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;min(N-W, N-R).
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0077em;&quot;&gt;R&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Call this the &lt;em&gt;availability condition.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why is this?
Suppose there is no hinted handoff and we have consistent data
replicated over N nodes.
In order to perform a successful read there must be at least R
nodes participating. So the maximum number of nodes
that can fail and still allow a successful read is N-R.&lt;/p&gt;
&lt;p&gt;Suppose we have a successful read and we now want to write the
data. In order to perform a successful write we must have
at least W nodes participating.
So the maximum number of nodes that can fail and still
allow a successful write is N-W.&lt;/p&gt;
&lt;p&gt;And if you have no more nodes failing after the put()
call, it is guaranteed that the W nodes
that have successfully written the updated data
are the highest W nodes in the priority list,
which means that they will be selected in the next get()
call, so you are guaranteed to get the latest version of the data.&lt;/p&gt;
&lt;p&gt;The interesting thing here is that there&#39;s a &lt;em&gt;fundamental trade-off
between durability and availability.&lt;/em&gt; You can increase &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;W&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
and decrease the likelihood of a failure of the first kind,
but increase the likelihood of a failure of the second kind.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-%22eventual-consistency%22%2C-and-what-are-some-advantages-and-disadvantages%3F-what&#39;s-a-specific-example-of-behaviour-that-could-happen-under-this-consistency-model%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s &amp;quot;eventual consistency&amp;quot;, and what are some advantages and disadvantages? What&#39;s a specific example of behaviour that could happen under this consistency model?&lt;/h3&gt;
&lt;p&gt;Eventual consistency means that the database &lt;em&gt;eventually&lt;/em&gt;
reaches a valid state.
I understand this as meaning that each of the N nodes must
&lt;em&gt;eventually&lt;/em&gt; hold the same copy of every key.
More formally,
there exists some time t in the future where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t &amp;gt; t_0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6542em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7651em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; such that
for each key in each of the N nodes &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;key_t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
each key&#39;s value is the same:
that is, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;J&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;I(key_t) == J(key_t)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0962em;&quot;&gt;J&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; for each &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;J&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;∈&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(I, J) \in N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0962em;&quot;&gt;J&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Advantages: you get asynchronous propagation. &lt;code&gt;put()&lt;/code&gt; calls
are always available (provided you have at least W nodes),
subsequent &lt;code&gt;get()&lt;/code&gt; calls can return without waiting for
&lt;code&gt;put()&lt;/code&gt; calls to replicate themselves over N nodes,
which is good if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;W &amp;lt;&amp;lt; N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7224em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; or if we have server outages.&lt;/p&gt;
&lt;p&gt;Disadvantages: subsequent &lt;code&gt;get()&lt;/code&gt; calls are not guaranteed to
return the latest version of the data,
and reconciliation must be performed.&lt;/p&gt;
&lt;p&gt;Specific example of behaviour that could happen under this
consistency model:
deleted items resurfacing in a &amp;quot;delete item from cart&amp;quot;
if one chooses to merge the two different objects.&lt;/p&gt;
&lt;h3 id=&quot;how-does-%22consistent-hashing%22-(compared-to%2C-say%2C-~hash(key)-%25-n~)-reduce-the-amount-of-data-that-needs-to-be-moved-when-a-node-joins-or-leaves-the-cluster%3F&quot; tabindex=&quot;-1&quot;&gt;How does &amp;quot;consistent hashing&amp;quot; (compared to, say, ~hash(key) % N~) reduce the amount of data that needs to be moved when a node joins or leaves the cluster?&lt;/h3&gt;
&lt;p&gt;See front bit for the full explanation.&lt;/p&gt;
&lt;h3 id=&quot;where-is-the-configuration-information-stored%3F-how-is-it-kept-consistent%3F&quot; tabindex=&quot;-1&quot;&gt;Where is the configuration information stored? How is it kept consistent?&lt;/h3&gt;
&lt;p&gt;It&#39;s kept by each node and kept consistent by gossiping.&lt;/p&gt;
&lt;h3 id=&quot;why-is-dynamo-only-eventually-consistent%3F-how-can-divergent-histories-form-even-with-a-3-2-2-quorum-setup%3F&quot; tabindex=&quot;-1&quot;&gt;Why is Dynamo only eventually consistent? How can divergent histories form even with a 3-2-2 quorum setup?&lt;/h3&gt;
&lt;p&gt;It would seem on the face of it that Dynamo can be completely
consistent and histories can never diverge if one uses a
3-2-2 setup. Any write must have a quorum of two,
and regardless of which two you choose (AB, BC, AC),
they must have at least one node in common with the latest write, right?
So how can inconsistency occur even in the presence of network partitions?
The key (thanks Bernard) is that &lt;strong&gt;hinted hand-off loses consistency!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Recall that hinted hand-off allows nodes that are
&lt;em&gt;not in the first N nodes of the preference list&lt;/em&gt;
to receive and temporarily store write requests for a node that&#39;s
temporarily unreachable.&lt;/p&gt;
&lt;p&gt;But this of course introduces inconsistency.
Suppose I make a write request.
I walk down the preference list to find the first two reachable nodes.
Suppose I get quorum from AB.
The vector clock looks like this: &lt;code&gt;[SA, 1]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then I make a second write request, and
let&#39;s say this time A was unreachable so I get quorum from BC instead.
C is updated with B&#39;s latest version of the data,
so everything is consistent.
We get &lt;code&gt;([SA, 1], [SB, 2]).&lt;/code&gt;
The second vector clock subsumes the first
so when A receives this new vector clock it knows to override its own.&lt;/p&gt;
&lt;p&gt;But what if during the second write request A and B were &lt;em&gt;both&lt;/em&gt; unreachable?
Then I would reach C, and by hinted handoff D would take over
keeping a message for A.
C would be holding a vector clock &lt;code&gt;([SC, 1])&lt;/code&gt;
and A would be holding the vector clock &lt;code&gt;([SA, 1])&lt;/code&gt;.
Now when A reconciles it has two different vector clocks
and no way to resolve them as they have nothing in common.&lt;/p&gt;
&lt;h2 id=&quot;questions-in-the-lecture-notes&quot; tabindex=&quot;-1&quot;&gt;Questions in the lecture notes&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/papers/dynamo-faq.txt&quot;&gt;source&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;suppose-dynamo-server-s1-is-perfectly-healthy-with-a-working-network-connection.-by-mistake%2C-an-administrator-instructs-server-s2-to-remove-s1-using-the-mechanisms-described-in-4.8.1-and-4.9.-it-takes-a-while-for-the-membership-change-to-propagate-from-s2-to-the-rest-of-the-system-(including-s1)%2C-so-for-a-while-some-clients-and-servers-will-think-that-s1-is-still-part-of-the-system.-will-dynamo-operate-correctly-in-this-situation%3F-why%2C-or-why-not%3F&quot; tabindex=&quot;-1&quot;&gt;Suppose Dynamo server S1 is perfectly healthy with a working network connection. By mistake, an administrator instructs server S2 to remove S1 using the mechanisms described in 4.8.1 and 4.9. It takes a while for the membership change to propagate from S2 to the rest of the system (including S1), so for a while some clients and servers will think that S1 is still part of the system. Will Dynamo operate correctly in this situation? Why, or why not?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/questions.html?q=q-dynamo&amp;amp;lec=20&quot;&gt;source&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Don&#39;t see why not: when S1 node is removed,
S1 should offer and upon confirmation from
the nodes clockwise to it
transfer the appropriate set of keys.
Call these nodes say S3, S4, and S5
given N=3.&lt;/p&gt;
&lt;p&gt;One issue is if some nodes who think
that S1 has been deleted contact the nodes in
the new preference list who think S1 has
yet to be deleted.
So a node who thinks S1 has been deleted
will contact S3, S4 and S5 for a write/read
request.
S3 and S4 will acknowledge and agree.
However, S5 will believe it&#39;s not in its key range
and will return false.
But here there&#39;s still a quorum of 2 out of 3,
and so there will be no problem in this scenario.
Eventually the node removal will be gossiped to all
alive nodes.&lt;/p&gt;
&lt;h3 id=&quot;how-does-dynamo-recover-from-permanent-failure----what-is-anti-entropy-using-merkle-trees%3F&quot; tabindex=&quot;-1&quot;&gt;How does Dynamo recover from permanent failure -- what is anti-entropy using Merkle trees?&lt;/h3&gt;
&lt;p&gt;A: In this paper, anti-entropy is a big word for synchronizing two replicas. To determine what is different between two replicas, Dynamo traverses a Merkle
representation of the two replicas. If a top-level node matches, then Dynamo
doesn&#39;t descend that branch. If a node in the tree don&#39;t match, they copy the
branch of the new version to the old one. The use of Merkle trees allows the
authors to copy only the parts of the tree that are different. Wikipedia has a
picture to illustrate: https://en.wikipedia.org/wiki/Merkle_tree.&lt;/p&gt;
&lt;h2 id=&quot;some-deeper-questions&quot; tabindex=&quot;-1&quot;&gt;Some deeper questions&lt;/h2&gt;
&lt;h3 id=&quot;considerations%2Fimplications-for-database-design%3F&quot; tabindex=&quot;-1&quot;&gt;Considerations/implications for database design?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Is symmetry (lack of leader) important?&lt;/li&gt;
&lt;li&gt;Is it really important for every node to be able to service a write?&lt;/li&gt;
&lt;li&gt;Can you achieve low latency and high write availability with just one RW replica?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to Zongran, Bernard, Thomas, Gary, and Melodies for asking excellent questions
and for answering them when I could not :P&lt;/p&gt;
&lt;h2 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/notes/l-dynamo.txt&quot;&gt;6.824 lecture notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2018/papers/dynamo-faq.txt&quot;&gt;6.824 lecture FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>MIT&#39;s 6.824 Distributed Systems, Lab 2: Raft</title>
    <link href="https://lieuzhenghong.com/mit_6.824_lab_2_raft/"/>
    <updated>2021-03-16T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/mit_6.824_lab_2_raft/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Went out on&lt;/p&gt;
&lt;p&gt;See my notes on the paper
&lt;a href=&quot;https://lieuzhenghong.com/raft_notes/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;lab-2a%3A-leader-election-(moderate)&quot; tabindex=&quot;-1&quot;&gt;Lab 2A: Leader election (moderate)&lt;/h2&gt;
&lt;p&gt;Finished on Sunday 21st Feb 2021.&lt;/p&gt;
&lt;p&gt;Moderate difficulty.&lt;/p&gt;
&lt;h2 id=&quot;lab-2b%3A-log-(hard)&quot; tabindex=&quot;-1&quot;&gt;Lab 2B: log (hard)&lt;/h2&gt;
&lt;p&gt;Started Saturday 27th Feb 2021.
Went to NUS and worked from 3pm to 3am with a lot of breaks in between.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Log is 1-indexed&lt;/strong&gt;: add a dummy element inside &lt;code&gt;log&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;28th Feb 2021: 12:30pm&lt;/strong&gt;: Passed TestBasicAgree2B and TestRPCBytes2B, failed the rest.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tuesday 2nd March 2021&lt;/strong&gt;: Consistently passes all tests. 2B is now complete.&lt;/p&gt;
&lt;p&gt;Some of the bugs I inadvertently introduced:&lt;/p&gt;
&lt;p&gt;In TestFailAgree2B one of the servers is disconnected. Since it is disconnected it becomes a candidate and starts to increment its own term again and again. The other two servers happily stay at term 1 and replicate log entries. When it is reconnected, it rejects the AppendEntries because its term is higher. Then the leader immediately becomes a follower,
and leader election should occur.
Since the disconnected server does not have any of its logs&lt;/p&gt;
&lt;p&gt;This is all correct behaviour so far, but for&lt;/p&gt;
&lt;p&gt;In my helper function &lt;code&gt;logAtLeastUpToDate&lt;/code&gt; I wrote &lt;code&gt;&amp;lt;&lt;/code&gt;
when I meant to write  &lt;code&gt;&amp;gt;&lt;/code&gt;.
This mea&lt;/p&gt;
&lt;p&gt;So the issue is that if let&#39;s say you have a node 1 that is a follower and has randomly initialised with some high election timeout, and has some logs, and you have a node 2 that has not up-to-date logs but has initialised with a low election timeout. You can have a situation where node 1 keeps rejecting node 2, but node 2 keeps refreshing / incrementing term and randomly initialising state, and because node 1&#39;s election timeout is quite high, node 2 will keep asking, and we&#39;ll be unlikely to reach a consensus. This isn&#39;t a deterministic bug, it only happens sometimes, we need node1 to have a high election timeout&lt;/p&gt;
&lt;p&gt;Solution: Don&#39;t reset &lt;code&gt;lastHeardFrom&lt;/code&gt; if I receive a &lt;code&gt;RequestVote&lt;/code&gt; entry
and I do not grant a vote: only refresh lastHeardFrom if
i) I grant a vote to a candidate in a RequestVote RPC call, or
ii) I receive an AppendEntries RPC call with the same or greater term.&lt;/p&gt;
&lt;h2 id=&quot;lab-2c%3A-persistence-(hard)&quot; tabindex=&quot;-1&quot;&gt;Lab 2C: persistence (hard)&lt;/h2&gt;
&lt;p&gt;Before I implement Lab 3&lt;/p&gt;
&lt;h2 id=&quot;lab-2d%3A-log-compaction-(hard)&quot; tabindex=&quot;-1&quot;&gt;Lab 2D: log compaction (hard)&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>Memcached at Facebook (2013)</title>
    <link href="https://lieuzhenghong.com/memcached_at_facebook/"/>
    <updated>2021-03-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/memcached_at_facebook/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#the-big-picture&quot;&gt;The big picture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#guarantees&quot;&gt;Guarantees&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#glossary&quot;&gt;Glossary&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#three-techniques-to-reduce-latency&quot;&gt;Three techniques to reduce latency&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#preventing-incast-congestion&quot;&gt;Preventing incast congestion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#reducing-load&quot;&gt;Reducing Load&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#using-lease-to-minimise-application-wait-time.&quot;&gt;Using lease to minimise application wait time.&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#memcache-pools&quot;&gt;Memcache pools&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#replication-between-pools&quot;&gt;Replication between pools&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#handling-failures&quot;&gt;Handling failures&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#gutter-servers-are-spun-up-when-memcache-servers-fail&quot;&gt;Gutter servers are spun up when memcache servers fail&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#how-do-we-deal-with-multiple-regions%3F&quot;&gt;How do we deal with multiple regions?&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#regional-pool&quot;&gt;Regional pool&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#cold-cluster-warm-up&quot;&gt;Cold cluster warm up&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#what&#39;s-the-difference-between-look-aside-vs-look-through-cache%3F&quot;&gt;What&amp;#39;s the difference between look-aside vs look-through cache?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#what-facebook-needs&quot;&gt;What Facebook needs&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#read&quot;&gt;READ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#invalidate-scheme-vs-update-scheme%3F&quot;&gt;Invalidate scheme vs update scheme?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#partition-vs-replication%3F&quot;&gt;Partition vs replication?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#why-do-you-need-the-delete-done-by-the-client%3F&quot;&gt;Why do you need the delete done by the client?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#bibliography&quot;&gt;Bibliography&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/#why-memcached-at-fb-is-not-consistent&quot;&gt;Why Memcached at FB is not consistent&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I read the following the paper as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This week I watched the 6.824 lecture video
&lt;a href=&quot;https://www.youtube.com/watch?v=Myp8z0ybdzM&quot;&gt;Lecture 16: Cache Consistency: Memcached at Facebook&lt;/a&gt;.
and we discussed the paper
&lt;a href=&quot;https://files.lieu.gg/docs/Nishtala%20et%20al.%20(2013).%20Scaling%20Memcache%20at%20Facebook..pdf&quot;&gt;Nishtala et al. (2013). Scaling Memcache at Facebook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Memcached is an in-memory hash table providing storage at low cost.&lt;/p&gt;
&lt;h2 id=&quot;the-big-picture&quot; tabindex=&quot;-1&quot;&gt;The big picture&lt;/h2&gt;
&lt;p&gt;The idea is to reduce the load on the database layer by caching reads.
For FB&#39;s usecase they have orders of magnitude more reads than writes,
and so caching can have significant advantages.&lt;/p&gt;
&lt;p&gt;Additionally, it&#39;s OK that reads don&#39;t necessarily observe the latest writes. So consistency
(the condition that all reads observe the latest write)
can be relaxed.
e.g. a write can be an edit to a post, or a new post.
It&#39;s OK if you refresh the page a few seconds after a new post has been made and don&#39;t see anything.
What we want to avoid is &lt;em&gt;unbounded&lt;/em&gt; inconsistency:
after some time period &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6151em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; we want to guarantee
that all users see the latest version of the data.&lt;/p&gt;
&lt;p&gt;Second, read operations fetch data from a variety of sources,
e.g. MySQL, HDFS, backend services:
this points to a separate storage layer that can handle
heterogeneous&lt;/p&gt;
&lt;p&gt;Memcached provides &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, and &lt;code&gt;delete&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Memcache&lt;/code&gt; is a &amp;quot;demand-filled look aside cache.&amp;quot;
in contrast to an inline, or &amp;quot;look-through&amp;quot; cache.&lt;/p&gt;
&lt;p&gt;(Look-aside means you&#39;re aware of the cache,
you decide which data paths you want to cache.
Look-through means you can&#39;t choose to cache or not.)&lt;/p&gt;
&lt;p&gt;Get: retrieve from cache: if miss, get from DB.
Set: update DB, then invalidate the cache.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generic cache:&lt;/strong&gt; use it as a general key-value store,
storing pre-computed results from ML algorithms.&lt;/p&gt;
&lt;p&gt;As is, &lt;code&gt;memcached&lt;/code&gt; runs only on a single server:
FB scaled it out to run on a distributed system.&lt;/p&gt;
&lt;p&gt;Two key design goals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;any change must impact a user-facing or operational issue: optimisations not considered.&lt;/li&gt;
&lt;li&gt;The probability of reading transient stale data as a parameter to be tuned, similar to responsiveness.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Web servers must communicate with &lt;em&gt;many&lt;/em&gt; memcached servers,
all web servers communicate with all memcached server in a short period.&lt;/p&gt;
&lt;p&gt;This all-to-all communication pattern can cause &lt;em&gt;incast congestion&lt;/em&gt; or  allow a
single server to become the bottleneck for many web servers.  Data replication
alleviates the single-server bottleneck but leads to significant memory
inefficiencies in the common case.&lt;/p&gt;
&lt;h2 id=&quot;guarantees&quot; tabindex=&quot;-1&quot;&gt;Guarantees&lt;/h2&gt;
&lt;p&gt;Memcached at Facebook promises &amp;quot;best-effort&amp;quot; eventual consistency.
Without the cold cluster warm up (more on this later),
Memcached guarantees eventual consistency in the absence of network partitions,
and loses consistency in the presence of network partitions.&lt;/p&gt;
&lt;p&gt;Eventual consistency means that after some bounded time,
all reads will eventually return the latest write.&lt;/p&gt;
&lt;p&gt;Memcached does not guarantee eventual consistency due to the cold
Cold cluster: The two-second holdoff rule fails eventual consistency
and results instead in &amp;quot;best-effort&amp;quot; eventual consistency:
if the DB hasn&#39;t deleted the cache entry in the warm cluster
within 2 seconds, then the cold cluster will read a stale value
from the warm cluster
and that value will be indefinitely inconsistent.&lt;/p&gt;
&lt;p&gt;It also doesn&#39;t guarantee eventual consistency in the presence
of network partitions, because a put request can fail/be partitioned
after updating the DB but before invalidating the cache.
Then that value will again be indefinitely inconsistent.&lt;/p&gt;
&lt;h2 id=&quot;glossary&quot; tabindex=&quot;-1&quot;&gt;Glossary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fan-out&lt;/strong&gt;:
one web server needs to talk to lots of memcache servers to get the data they need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;consistent hashing&lt;/strong&gt;: reduces the need for rehashing when the number of buckets grows or shrinks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;incast congestion&lt;/strong&gt;: problem at the web server side. When all the responses from the memcache layer are coming back, they get stuck.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;single server becoming the bottleneck&lt;/strong&gt;: when you have a hot key.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;load-link/store-conditional&lt;/em&gt;:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hold-off-time&lt;/strong&gt;: Hold of period of two seconds. If a miss is detected in the cold-cluster C, the
It can get the stale value, but it won&#39;t &lt;em&gt;store&lt;/em&gt; the stale value in C.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;system V shared memory&lt;/strong&gt;: just generic shared memory&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;three-techniques-to-reduce-latency&quot; tabindex=&quot;-1&quot;&gt;Three techniques to reduce latency&lt;/h3&gt;
&lt;p&gt;How to reduce latency? Parallelise and batch, connection coalescing,
and sliding window.
They build a DAG representing the dependencies, then batch them.&lt;/p&gt;
&lt;p&gt;Each server has a library&lt;/p&gt;
&lt;p&gt;Standalone proxy (web server)
&lt;code&gt;mcrouter&lt;/code&gt;: presents a memcached server interface and routes requests/replies to/from other servers.&lt;/p&gt;
&lt;p&gt;--&amp;gt; why would u use a proxy.&lt;/p&gt;
&lt;p&gt;Clients use UDP and TCP, favouring &lt;code&gt;UDP&lt;/code&gt; for get requests
to reduce latency and overhead.&lt;/p&gt;
&lt;p&gt;(UDP use memcache to do amplification attack)&lt;/p&gt;
&lt;p&gt;UDP might detect packets that are dropped or received out of order,
we just call it a cache miss.&lt;/p&gt;
&lt;p&gt;For set and delete, we need reliability. So we need TCP.
Since TCP are stateful, each of these threads must have a separate connection.
We use &lt;code&gt;mcrouter&lt;/code&gt;to coalesce connections within a machine/server,
so instead of in a per-thread basis it&#39;s per-machine basis.&lt;/p&gt;
&lt;h3 id=&quot;preventing-incast-congestion&quot; tabindex=&quot;-1&quot;&gt;Preventing incast congestion&lt;/h3&gt;
&lt;p&gt;Each server will send multiple requests to different memcache servers,
and this may overload the server when the memcache responses
all hit the server at the same time.
To prevent this, we limit the number of open connections.&lt;/p&gt;
&lt;p&gt;Strike a balance where you have too small window size,
vs incast congestion with too large a window size.&lt;/p&gt;
&lt;h3 id=&quot;reducing-load&quot; tabindex=&quot;-1&quot;&gt;Reducing Load&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Leases&lt;/strong&gt; address two problems: stale sets and thundering herds.
A stale set&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thundering herd&lt;/em&gt;: a specific key undergoes heavy read and write activity,
which repeatedly invalidates the recently set values,
causing all of them to default to the more costly path.&lt;/p&gt;
&lt;p&gt;What&#39;s a lease: when you as client 1 get a cache miss,
the memcached server gives you a 64-bit token.
This 64-bit token is a &lt;em&gt;lease&lt;/em&gt;: it allows you and you only
to&lt;/p&gt;
&lt;p&gt;There must be a timeout for this lease
Each token lasts only for 10 seconds:
subseuquent&lt;/p&gt;
&lt;p&gt;Requests for a key&#39;s value within 10 seconds of a token being issued
results in o&lt;/p&gt;
&lt;p&gt;So if the client crashes, it will issue a new token after ten seconds
to the next client who sends in a read request.&lt;/p&gt;
&lt;p&gt;... explain this section better;&lt;/p&gt;
&lt;h4 id=&quot;using-lease-to-minimise-application-wait-time.&quot; tabindex=&quot;-1&quot;&gt;Using lease to minimise application wait time.&lt;/h4&gt;
&lt;p&gt;We can further reduce this wait time (10s) by identifying situations
in which returning slightly out-of-date data is acceptable.
When a key is deleted we put it in a temporary store,
and if clients are happy to receive stale data,
we can give them this recently deleted data.&lt;/p&gt;
&lt;h3 id=&quot;memcache-pools&quot; tabindex=&quot;-1&quot;&gt;Memcache pools&lt;/h3&gt;
&lt;p&gt;There&#39;s different types of data:
some data is frequently accessed but cache misses are inexpensive,
and&lt;/p&gt;
&lt;p&gt;Many high churn items will eventually evict low churn items,
so we separate different pools.&lt;/p&gt;
&lt;h3 id=&quot;replication-between-pools&quot; tabindex=&quot;-1&quot;&gt;Replication between pools&lt;/h3&gt;
&lt;p&gt;storing multiple copies of the same data; they only replicate when
the data set is small, requests ask for many keys simultaneously,
and the request rate is much higher.
They can either do replication or do key-space partitioning.
Given the fact that the difference in &lt;code&gt;memcached&lt;/code&gt; overhead for
retrievin
With partitioning&lt;/p&gt;
&lt;h3 id=&quot;handling-failures&quot; tabindex=&quot;-1&quot;&gt;Handling failures&lt;/h3&gt;
&lt;h4 id=&quot;gutter-servers-are-spun-up-when-memcache-servers-fail&quot; tabindex=&quot;-1&quot;&gt;Gutter servers are spun up when memcache servers fail&lt;/h4&gt;
&lt;p&gt;Clients don&#39;t invalidate keys in a gutter server&lt;/p&gt;
&lt;p&gt;You hit the DB once and store it in the gutter server.
Gutter server prevents lots of DB hits.&lt;/p&gt;
&lt;h2 id=&quot;how-do-we-deal-with-multiple-regions%3F&quot; tabindex=&quot;-1&quot;&gt;How do we deal with multiple regions?&lt;/h2&gt;
&lt;p&gt;Web server writes to the database directly.&lt;/p&gt;
&lt;p&gt;Each webserver has one MCRouter, each CLUSTER also has multiple additional
MCRouters&lt;/p&gt;
&lt;p&gt;Since cross-cluster communication is expensive, we want to reduce this as far as possible. Hence the cluster-wide &lt;code&gt;mcrouter&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;regional-pool&quot; tabindex=&quot;-1&quot;&gt;Regional pool&lt;/h3&gt;
&lt;p&gt;We store cold keys in a shared memcached&lt;/p&gt;
&lt;h3 id=&quot;cold-cluster-warm-up&quot; tabindex=&quot;-1&quot;&gt;Cold cluster warm up&lt;/h3&gt;
&lt;p&gt;We let cold clusters read from the warm cluster,
but this introduces the possibility of inconsistency.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-look-aside-vs-look-through-cache%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between look-aside vs look-through cache?&lt;/h3&gt;
&lt;p&gt;Look-aside means you&#39;re aware of the cache,
you decide which data paths you want to cache.
Look-through means you can&#39;t choose to cache or not.&lt;/p&gt;
&lt;h2 id=&quot;what-facebook-needs&quot; tabindex=&quot;-1&quot;&gt;What Facebook needs&lt;/h2&gt;
&lt;p&gt;You don&#39;t need linearisability, but you cannot cache stale data indefinitely.&lt;/p&gt;
&lt;p&gt;Also, user cannot see stale data if they update their own data.&lt;/p&gt;
&lt;p&gt;Key concern: we want the user who writes the data not to see their stale data.&lt;/p&gt;
&lt;p&gt;Also, we must never expose the database layer
to the full brunt of the read requests.&lt;/p&gt;
&lt;h3 id=&quot;read&quot; tabindex=&quot;-1&quot;&gt;READ&lt;/h3&gt;
&lt;p&gt;v = get(k). Client hashes the data into &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# READ &lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# where get_cache and set_cache are RPC calls to the Memcached layer&lt;/span&gt;
v &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; get_cache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    v &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; db_fetch&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    set_cache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    
    
&lt;span class=&quot;token comment&quot;&gt;# WRITE(k, v)&lt;/span&gt;
send &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; to DB
delete_cache&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When FE sends a write to the DB,
it will send a &lt;code&gt;DELETE&lt;/code&gt; to the rest of the replicated DB&lt;/p&gt;
&lt;h3 id=&quot;invalidate-scheme-vs-update-scheme%3F&quot; tabindex=&quot;-1&quot;&gt;Invalidate scheme vs update scheme?&lt;/h3&gt;
&lt;p&gt;What&#39;s the difference? Why does FB use invalidate instead of delete?&lt;/p&gt;
&lt;p&gt;(37:00)&lt;/p&gt;
&lt;h3 id=&quot;partition-vs-replication%3F&quot; tabindex=&quot;-1&quot;&gt;Partition vs replication?&lt;/h3&gt;
&lt;p&gt;(38:00)&lt;/p&gt;
&lt;p&gt;Partition is RAM efficient but not good for hot keys. Clients need to talk to every partition.
Replication: good if hot keys, few TCP connections (each client only needs to talk to one partition), but less total data stored.&lt;/p&gt;
&lt;h3 id=&quot;why-do-you-need-the-delete-done-by-the-client%3F&quot; tabindex=&quot;-1&quot;&gt;Why do you need the delete done by the client?&lt;/h3&gt;
&lt;p&gt;The front-end needs to be the one to do it to ensure
that writes by the user are not stale.
(The user observes non-stale data).&lt;/p&gt;
&lt;h2 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://pdos.csail.mit.edu/6.824/notes/l-memcached.txt&quot;&gt;MIT 6.824 Memcached lecture notes&lt;/a&gt;
&lt;a href=&quot;https://pdos.csail.mit.edu/6.824/papers/memcache-faq.txt&quot;&gt;MIT 6.824 Memcached FAQ&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;h3 id=&quot;why-memcached-at-fb-is-not-consistent&quot; tabindex=&quot;-1&quot;&gt;Why Memcached at FB is not consistent&lt;/h3&gt;
&lt;p&gt;First let&#39;s talk about the key invariant of any database.
A database must give the following guarantees (invariants):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Once something is written, it must be readable;&lt;/li&gt;
&lt;li&gt;All reads must observe the latest writes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We say a system is consistent if
for every &lt;em&gt;valid concurrent history&lt;/em&gt;
(a history of interleaving concurrent events
that could happen in normal operation)
there exists &lt;em&gt;some&lt;/em&gt; rearrangement
under the consistency rules that preserves the invariants
of the database.&lt;/p&gt;
&lt;p&gt;So let&#39;s consider a particular concurrent history that is problematic.
Any write needs to do two separate steps: update the DB,
then invalidate the cache entry.
But suppose there&#39;s another read request that comes in
before you can invalidate the cache entry.
Then you&#39;ll end up serving a stale value to the read.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;write1 db start
write1 db end
write1 cache start
write1 cache end
read start
read end (now the cache is filled up)
write2 db start
write2 db end
read start
read end
write2 cache start
write2 cache end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here the last read does not observe the latest DB write
because the second write has yet to delete the cached entry
by the time the last read reads from the cache.
This breaks the invariant.&lt;/p&gt;
&lt;p&gt;Now the challenge is to rearrange this history by the rules
allowed by various concurrency models&lt;/p&gt;
&lt;p&gt;This history will result in a stale read, thus breaking the invariant.
This is obviously not linearisable, since
there&#39;s nothing to rearrange without changing the real-time ordering.&lt;/p&gt;
&lt;p&gt;Might the system be serialisable? I think it is, pathologically.
A serialisable database can always reorder all the reads in front
and put all the writes after all the reads, so all reads return 0.
This is an incredibly weak condition for a system that only allows
reads and writes as atomic transactions!
See &lt;a href=&quot;https://fauna.com/blog/serializability-vs-strict-serializability-the-dirty-secret-of-database-isolation-levels&quot;&gt;Fauna blog post&lt;/a&gt;
on why serialisability is useless:&lt;/p&gt;
&lt;p&gt;But let&#39;s assume that we don&#39;t allow that. Let&#39;s use strict serialisability.
But then of course it isn&#39;t strict serialisable for the same reason it isn&#39;t linearisable.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Notes on Amazon Aurora (2017, 2018)</title>
    <link href="https://lieuzhenghong.com/aurora_notes/"/>
    <updated>2021-03-07T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/aurora_notes/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#glossary&quot;&gt;Glossary&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#the-big-picture&quot;&gt;The big picture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-aurora-is-and-what-makes-it-special&quot;&gt;What Aurora is and what makes it special&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#in-more-detail&quot;&gt;In more detail&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#write-requests&quot;&gt;Write requests&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#read-requests&quot;&gt;Read requests&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#commit-requests&quot;&gt;Commit requests&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#recovery&quot;&gt;Recovery&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#epoch-numbers&quot;&gt;Epoch numbers&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#how-a-database-works&quot;&gt;How a database works&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-is-a-write-ahead-log%3F&quot;&gt;What is a write-ahead log?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what&#39;s-a-data-page%3F&quot;&gt;What&amp;#39;s a data page?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#if-the-aurora-db-doesn&#39;t-write-a-lot-of-this-stuff-to-disk%2C-why-do-these-old-dbs-need-to-write-to-disk%3F-what-is-the-tradeoff-that-we&#39;re-making-here%3F&quot;&gt;If the Aurora DB doesn&amp;#39;t write a lot of this stuff to disk, why do these old DBs need to write to disk? What is the tradeoff that we&amp;#39;re making here?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#why-might-read-replicas-get-stale-reads%3F&quot;&gt;Why might read replicas get stale reads?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#why-don&#39;t-database-instances-have-to-flush-dirty-pages%3F&quot;&gt;Why don&amp;#39;t database instances have to flush dirty pages?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-is-the-yellow-arrow-in-figure-2-point-to-amazon-s3%3F-what-is-a-binary-(statement)-log%3F&quot;&gt;What is the yellow arrow in Figure 2 point to Amazon S3? What is a binary (statement) log?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#how-does-the-storage-service-scale-out-i%2Fos-in-an-%22embarassingly-parallel-fashion%22%3F&quot;&gt;How does the storage service scale out I/Os in an &amp;quot;embarassingly parallel fashion&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#why-don&#39;t-you-need-a-quorum-read%3F-how-does-aurora-ensure-that-it-gets-the-latest-version-of-the-read-without-a-quorum-read%3F&quot;&gt;Why don&amp;#39;t you need a quorum read? How does Aurora ensure that it gets the latest version of the read without a quorum read?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-is-a-read-replica%3F&quot;&gt;What is a read replica?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-happens-when-a-storage-node-fails-after-acknowledging-the-primary-instance-(e.g.-written-to-update-queue)%2C-but-before-it-persists-that-data-to-disk%3F&quot;&gt;What happens when a storage node fails after acknowledging the primary instance (e.g. written to Update Queue), but before it persists that data to disk?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what&#39;s-the-difference-between-a-write-and-a-commit%3F&quot;&gt;What&amp;#39;s the difference between a write and a commit?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-are-the-differences-between-aurora-and-raft%3F&quot;&gt;What are the differences between Aurora and Raft?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#what-are-the-similarities-and-differences-between-aurora-and-memcache%3F&quot;&gt;What are the similarities and differences between Aurora and Memcache?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#do-replicas-apply-log-records-above-or-below-the-vdl%3F&quot;&gt;Do replicas apply log records ABOVE or BELOW the VDL?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/#bibliography&quot;&gt;Bibliography&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I read the following two papers as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The two papers I read are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Verbitski%20et%20al.%20(2017).%20Amazon%20Aurora--Design%20Considerations%20for%20High%20Throughput%20Cloud-Native%20Relational%20Databases.pdf&quot;&gt;Verbitski et al. (2017). Amazon Aurora--Design Considerations for High Throughput Cloud-Native Relational Databases&lt;/a&gt; and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Verbitski%20et%20al.%20(2018).%20Amazon%20Aurora--On%20Avoiding%20Distributed%20Consensus%20for%20IOs,%20Commits,%20and%20Membership%20Changes.pdf&quot;&gt;Verbitski et al. (2018). Amazon Aurora--On Avoiding Distributed Consensus for IOs, Commits, and Membership Changes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While the papers were great, they were not detailed enough for my taste.
They kind of gloss over the details of how the system is implemented,
and they don&#39;t really give a step-by-step breakdown of how
reads and writes are done and what state is being kept/sent/propagated.&lt;/p&gt;
&lt;p&gt;So here I want to first give a big-picture view:
what Aurora does and why it&#39;s important,
then a step-by-step breakdown of how writes, reads, and commits
are performed in Amazon Aurora.&lt;/p&gt;
&lt;p&gt;Here I assume that you have already read the Aurora paper
and I&#39;m not going to mention things that can be easily looked up in the paper.
I will instead try to explain what I believe to be
their motivations for building this system,
the key contributions of the papers
and elaborate on some things I believe are underspecified.&lt;/p&gt;
&lt;h2 id=&quot;glossary&quot; tabindex=&quot;-1&quot;&gt;Glossary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;AZ: availability zone&lt;/li&gt;
&lt;li&gt;OLTP: Online transaction processing&lt;/li&gt;
&lt;li&gt;PG: protection group.
An Aurora storage service is divided into six protection groups
that replicate the data six-way.&lt;/li&gt;
&lt;li&gt;MVCC: Multi-view concurrency control.
This ensures that read replicas always read the freshest possible
version of the databases.&lt;/li&gt;
&lt;li&gt;MTR: Mini-transaction.
Each database transaction in MySQL is a sequence of ordered
mini-transaction (MTRs) that are performed atomically.
A mini-transaction is made up of multiple log entries.&lt;/li&gt;
&lt;li&gt;VCL: Volume Complete LSN. This is the highest LSN on the storage node
for which all previous logs are available.&lt;/li&gt;
&lt;li&gt;CPL: Consistency Point LSNs.
This is a point where it&#39;s safe to commit, and the point that will be reached
after recovering from a crash.&lt;/li&gt;
&lt;li&gt;VDL: Volume Durable LSN. This is the highest CPL that is smaller
than the VCL.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-big-picture&quot; tabindex=&quot;-1&quot;&gt;The big picture&lt;/h2&gt;
&lt;p&gt;Amazon is trying to make its normal SQL database more &lt;em&gt;fault tolerant&lt;/em&gt;.
The easiest way to make databases fault tolerant is to have three replicated databases,
and have a quorum of 2 for all writes/reads.
But this isn&#39;t good enough for Amazon&#39;s purposes:
Amazon wants fault tolerance at the level of
one availability zone (AZ) failure + one additional node failure.
(An availability zone is a geographic region:
the idea is that if say the entire US blacks out,
you can use the Asia and South America replicas.)
With three nodes in different AZs, you can&#39;t reach quorum if two nodes fail.
Hence we need to use six replicas.&lt;/p&gt;
&lt;p&gt;But if we use six replicas,
the problem that results is that
i) databases are chatty and
ii) write requests in traditional DB systems are synchronous
and the bottleneck quickly becomes network I/O.
In a traditional database system this would mean large
latencies in write requests.&lt;/p&gt;
&lt;p&gt;So the key question Aurora aims to answer is:
&lt;strong&gt;how can we get greater fault-tolerance while keeping read/write latencies low?&lt;/strong&gt;
Aurora aims to reduce these latencies while giving
us the guarantees of a traditional relational DB.&lt;/p&gt;
&lt;h2 id=&quot;what-aurora-is-and-what-makes-it-special&quot; tabindex=&quot;-1&quot;&gt;What Aurora is and what makes it special&lt;/h2&gt;
&lt;p&gt;Amazon Aurora is a CP system. It gives you the guarantees of a relational DB,
while being much quicker. But it&#39;s not available,
because if there&#39;s a network partition, it can&#39;t reach quorum (more on this later).
This is different from Amazon&#39;s DynamoDB, which is AP and eventually consistent.&lt;/p&gt;
&lt;p&gt;How does Aurora do it?
In my opinion, Aurora makes two key contributions:
&lt;strong&gt;separating the database layer from the storage layer,&lt;/strong&gt;
and &lt;strong&gt;making the log the database.&lt;/strong&gt;
Aurora separates the database layer from the storage layer,
which allows writes to be done asynchronously without having
to wait for the data to be replicated to disk.
The database layer applies writes to its own buffer cache after it receives
confirmation from the storage layer.
This allows the database to service client requests (with its cache)
while previous write requests are written and replicated asynchronously on the storage layer.
Pages are (again, asynchronously) generated by the storage layer
and surfaced when needed in response to a read request.
This solves the latency issue.&lt;/p&gt;
&lt;p&gt;Another way they reduce latency is by decreasing
the amount of data that needs to be replicated by
sending only the write-ahead logs:
&lt;strong&gt;&amp;quot;the log is the database.&amp;quot;&lt;/strong&gt;
They use a strictly increasing log number
called the Log Sequence Number (LSN)
to make sure logs are consistently
replicated across the six replicas.&lt;/p&gt;
&lt;h2 id=&quot;in-more-detail&quot; tabindex=&quot;-1&quot;&gt;In more detail&lt;/h2&gt;
&lt;p&gt;There&#39;s one primary read-write instance (leader) and
multiple replica read-only database instances.
There&#39;s only one storage volume, replicated six ways
(each replica is called a PG, or &amp;quot;protection group&amp;quot;)
in three different AZsf.&lt;/p&gt;
&lt;h3 id=&quot;write-requests&quot; tabindex=&quot;-1&quot;&gt;Write requests&lt;/h3&gt;
&lt;p&gt;What exactly happens when Aurora needs to service a write request?&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;The primary replica is the main source of truth.
It keeps some important state.
The most important number is the Log Sequence Number (LSN).
It also keeps volume durable log (VDL) records and
current epoch number.&lt;/li&gt;
&lt;li&gt;The primary replica receives a write request, which is a database transaction.&lt;/li&gt;
&lt;li&gt;The database-level transaction is broken up into multiple mini-transactions
that are ordered and must be performed automically.&lt;/li&gt;
&lt;li&gt;Each mini-transaction is itself composed of multiple &lt;strong&gt;contiguous&lt;/strong&gt; log records.
Because the primary replica is the main source of truth,
it knows exactly what LSNs it needs to issue for each log record:
this is important because of failure recovery and truncation range.&lt;/li&gt;
&lt;li&gt;These log records are sent asynchronously to the storage service.
Each storage node persists the log records to an update queue,
and responds with an acknowledgement,
along with the Segment Complete LSN (SCL).
All of this is asynchronous.&lt;/li&gt;
&lt;li&gt;When the primary replica receives a quorum acknowledgement
from 4 out of 6 storage nodes,
that write is considered done.
When the replica observes SCL advance at four of six members,
it locally advances the &amp;quot;Protection Group Complete LSN&amp;quot; (PGCL),
which is the point at which the protection group has made all writes durable.&lt;/li&gt;
&lt;li&gt;If an MTR is complete (the quorum SCL &amp;gt; the LSN of the last log entry in the MTR),
The primary instance may ship the MTR chunks and the new VDL to its read replicas,
which applies them sequentially to generate its own cached version of the pages.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/aurora/aurora_storage_node.png&quot; alt=&quot;Figure 4: I/O traffic in Aurora storage nodes&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The database instance acquires latches for each data block, allocates a batch
of contiguously ordered LSNs,generates the log records, issues a write, shards
then into writebuffers for each protection group associated with the blocks,
andwrites them to the various storage nodes for the segments in theprotection
group. We use an additional consistency point, the Vol-ume Durable LSN (VDL),
to represent the last LSN below VCLrepresenting an MTR completion.&lt;/p&gt;
&lt;p&gt;Replicas do not have the benefit of the latching used at thewriter instance to
prevent read requests from seeing non-atomic structural updates. To create
equivalent ordering, we ensure that log records are only shipped from the
writer instance in MTR chunks. At the replica, they must be applied in LSN
order, applied only if above the VDL in the writer as seen in the replica, and
applied atomically in MTR chunks to the subset of blocks in the cache.
Read requests are made relative to VDL points to avoid seeing structurally
inconsistent data&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;read-requests&quot; tabindex=&quot;-1&quot;&gt;Read requests&lt;/h3&gt;
&lt;p&gt;Aurora cleverly avoids quorum reads
(that is, querying all six PGs, and waiting for the quorum of 3).
Why would you ever need a quorum read?
If you don&#39;t do a quorum read you run the risk of querying a node that has stale data:
e.g. you read from a node that&#39;s one of the two nodes that wasn&#39;t included in the write quorum.
The primary replica never needs to do a quorum read, obviously,
because it knows exactly which PGs have the latest writes.&lt;/p&gt;
&lt;p&gt;But how do the read replicas avoid quorum reads?
The read replicas are sent the VDL by the primary replica,
and I&#39;m guessing if they query a node whose CPL (Consistency Point LSN)
is lower than the VDL (the VDL is the highest CPL that is smaller than equal to VCL),
they retry with another node?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When reading a page from disk, the database establishes a &lt;em&gt;read-point&lt;/em&gt;,
representing a VDL at the time the request was issued.
The database can then select a storage node that is &lt;em&gt;complete&lt;/em&gt;
with respect to the read point,
knowing that it will therefore receive an up to date version&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;commit-requests&quot; tabindex=&quot;-1&quot;&gt;Commit requests&lt;/h3&gt;
&lt;h3 id=&quot;recovery&quot; tabindex=&quot;-1&quot;&gt;Recovery&lt;/h3&gt;
&lt;h4 id=&quot;epoch-numbers&quot; tabindex=&quot;-1&quot;&gt;Epoch numbers&lt;/h4&gt;
&lt;p&gt;The idea of &amp;quot;epochs&amp;quot; are very similar to the term value in Raft.
Epochs are used to invalidate stale requests after a crash in the database instance.&lt;/p&gt;
&lt;h2 id=&quot;how-a-database-works&quot; tabindex=&quot;-1&quot;&gt;How a database works&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Traditional relational databases organize data in pages, and as pages are
modified, they must be periodically flushed to disk. For resilience against
failures and maintenance of ACID semantics, page modifications are also
recorded in redo log records, which are written to disk in a continuous
stream. While this architecture provides the basic functionality needed to
support a relational database management system, it&#39;s rife with
inefficiencies. For example, a single logical database write turns into
multiple (up to five) physical disk writes, resulting in performance problems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I don&#39;t really understand how databases work,
and why they need to write so many things.&lt;/p&gt;
&lt;p&gt;Thankfully the
&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2020/notes/l-aurora.txt&quot;&gt;6.824 lecture notes on Aurora&lt;/a&gt;
has a very helpful explanation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Paper assumes you know how DB works, how it uses storage.
here&#39;s an overview of a generic transactional DB
single machine
example bank transaction -- transfer $10 from x&#39;s account to y&#39;s account
x = x + 10
y = y - 10
locks x and y, released after commit finishes
data in b-tree on disk
cached data pages
DB server modifies only cached data pages as transaction runs
and appends update info to WAL (Write-Ahead Log)
the paper&#39;s &amp;quot;redo log&amp;quot; == MySQL&#39;s INNODB transaction log.
log entries:
LSID  TID  key  old  new
101     7    x  500  510     (generated by x = x + 10)
102     7    y  750  740     (generated by y = y - 10)
103     7  commit            (transaction finished)
commit once WAL safe on disk
release locks on x and y
reply to client
later write modified data pages from cache to disk
to free log space, allow cache eviction
crucial to performance to delay -- write absorbtion, since pages are big
crash recovery
replay &amp;quot;new&amp;quot; values for all committed xactions in log (redo)
replay &amp;quot;old&amp;quot; values for uncommitted xactions in log (undo)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Traditional databases have to write so many things over the network
because there is no compute in your storage:
the storage is dumb.
It can&#39;t generate the pages from the redo log.&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-write-ahead-log%3F&quot; tabindex=&quot;-1&quot;&gt;What is a write-ahead log?&lt;/h3&gt;
&lt;p&gt;From &lt;a href=&quot;https://en.wikipedia.org/wiki/Write-ahead_logging&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, write-ahead logging (WAL) is a family of techniques for
providing atomicity and durability (two of the ACID properties) in database
systems. The changes are first recorded in the log, which must be written to
stable storage, before the changes are written to the database.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In Aurora the write replica sends a write request to the storage service,
which writes it to an update queue (&lt;strong&gt;this is the write ahead log!&lt;/strong&gt;).
Only this step is synchronous, and responsible for the write latency.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/aurora/aurora_storage_node.png&quot; alt=&quot;I/O traffic in Aurora storage nodes&quot;&gt;&lt;/p&gt;
&lt;p&gt;But once it&#39;s written to the four update queues (you need four nodes for quorum),
the database service can be assured that this write &lt;em&gt;will&lt;/em&gt; succeed,
and can return the client a result.
The results can then be slowly persisted to disk asynchronously by the storage service,
freeing up the database service to service more requests.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-a-data-page%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a data page?&lt;/h3&gt;
&lt;p&gt;Databases store data in terms of pages, pages tend to be 4KB.
In general, each row is in a page (barring very large rows)
and is written to disk.&lt;/p&gt;
&lt;h3 id=&quot;if-the-aurora-db-doesn&#39;t-write-a-lot-of-this-stuff-to-disk%2C-why-do-these-old-dbs-need-to-write-to-disk%3F-what-is-the-tradeoff-that-we&#39;re-making-here%3F&quot; tabindex=&quot;-1&quot;&gt;If the Aurora DB doesn&#39;t write a lot of this stuff to disk, why do these old DBs need to write to disk? What is the tradeoff that we&#39;re making here?&lt;/h3&gt;
&lt;p&gt;The key tradeoff is that your storage now needs compute.
Your storage has to do the job of taking the log and building pages from it,
where previously this was done by the database instance.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot; tabindex=&quot;-1&quot;&gt;FAQ&lt;/h2&gt;
&lt;h3 id=&quot;why-might-read-replicas-get-stale-reads%3F&quot; tabindex=&quot;-1&quot;&gt;Why might read replicas get stale reads?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;The redo log seen by a read replica does not carry the stateneeded to
establish SCL, PGCL, VCL, or VDL consistency points.Nor is the read replica in
the communication path between thewriter and storage nodes to establish this
state on its own. Notethat VDL advances based on acknowledgements from storage
nodes,not redo issuance from the writer. The writer instance sends VDL update
control records as part of its replication stream. Althoughthe active
transaction list can be reconstructed at the replica us-ing redo records and
VDL advancement, for efficiency reasons weship commit notifications and
maintain transaction commit history.Read views at the replica are built based
on these VDL points andtransaction commit history&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;VDL on the replica may lag the writer -- hence read replicas may get stale reads.
How? This may happen if the primary instance has already written and
committed and advanced the VDL locally
but hasn&#39;t sent &amp;quot;VDL update control records&amp;quot; yet as part of its replication stream
to the secondary replica.&lt;/p&gt;
&lt;h3 id=&quot;why-don&#39;t-database-instances-have-to-flush-dirty-pages%3F&quot; tabindex=&quot;-1&quot;&gt;Why don&#39;t database instances have to flush dirty pages?&lt;/h3&gt;
&lt;h3 id=&quot;what-is-the-yellow-arrow-in-figure-2-point-to-amazon-s3%3F-what-is-a-binary-(statement)-log%3F&quot; tabindex=&quot;-1&quot;&gt;What is the yellow arrow in Figure 2 point to Amazon S3? What is a binary (statement) log?&lt;/h3&gt;
&lt;p&gt;[TODO] not sure..&lt;/p&gt;
&lt;h3 id=&quot;how-does-the-storage-service-scale-out-i%2Fos-in-an-%22embarassingly-parallel-fashion%22%3F&quot; tabindex=&quot;-1&quot;&gt;How does the storage service scale out I/Os in an &amp;quot;embarassingly parallel fashion&amp;quot;?&lt;/h3&gt;
&lt;p&gt;Firstly, the storage nodes are divided into independent storage segments of 10GB each,
this means that nodes can spin up and down very quickly and segments can be repaired
in 10 seconds over a 10 Gbps connection. So this scales very well.
What I think they mean by &amp;quot;embarassingly parallel&amp;quot; is that each storage node (or PG, I suppose)
is independent, and there&#39;s no additional bookkeeping to keep each node in sync.
Hence the database isntance can send to all these PGs simultaneously and all of them
can process the writes in parallel.&lt;/p&gt;
&lt;h3 id=&quot;why-don&#39;t-you-need-a-quorum-read%3F-how-does-aurora-ensure-that-it-gets-the-latest-version-of-the-read-without-a-quorum-read%3F&quot; tabindex=&quot;-1&quot;&gt;Why don&#39;t you need a quorum read? How does Aurora ensure that it gets the latest version of the read without a quorum read?&lt;/h3&gt;
&lt;p&gt;See the top section on this&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-read-replica%3F&quot; tabindex=&quot;-1&quot;&gt;What is a read replica?&lt;/h3&gt;
&lt;p&gt;Section 3.2 of the 2018 paper (&amp;quot;Scaling Reads using Read Replicas&amp;quot;):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many database systems scale reads by replicating updates froma writer instance
to a set of read replica instances. Typically, thisinvolves transporting
either logical statement updates or physicalredo log records from the writer
to the readers. Replication is donesynchronously if the replicas are intended
as failover targets with-out data loss and asynchronously if replica lag or
data loss duringfailover is acceptable&lt;/p&gt;
&lt;p&gt;Aurora supports logical replication to communicate with non-Aurora systems and
in cases where the application does not wantphysical consistency – for
example, when schemas differ. Internally,within an Aurora cluster, we use
physical replication. Aurora readreplicas attach to the same storage volume as
the writer instance.They receive a physical redo log stream from the writer
instanceand use this to update only data blocks present in their local
caches.Redo records for uncached blocks can be discarded, as they can beread
from the shared storage volume&lt;/p&gt;
&lt;p&gt;This approach allows Aurora customers to quickly set up and teardown replicas
in response to sharp demand spikes, since durablestate is shared. Adding
replicas does not change availability ordurability characteristics, since
durable state is independent fromthe number of instances accessing that state.
There is little latencyadded to the write path on the writer instance since
replicationis asynchronous. Since we only update cached data blocks on
thereplicas, most resources on the replica remain available for read
re-quests. And most importantly, if a commit has been marked durableand
acknowledged to the client, there is no data loss when a replica&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;what-happens-when-a-storage-node-fails-after-acknowledging-the-primary-instance-(e.g.-written-to-update-queue)%2C-but-before-it-persists-that-data-to-disk%3F&quot; tabindex=&quot;-1&quot;&gt;What happens when a storage node fails after acknowledging the primary instance (e.g. written to Update Queue), but before it persists that data to disk?&lt;/h3&gt;
&lt;p&gt;This doesn&#39;t happen, because the update queue is persisted to disk.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-a-write-and-a-commit%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between a write and a commit?&lt;/h3&gt;
&lt;p&gt;A write is a single write operation, while
a commit is committing an entire transaction,
which can contain multiple write and read transactions.
Committing a transaction means making it atomic:
saying that ALL the operations in that transaction have&lt;br&gt;
passed (or failed).&lt;/p&gt;
&lt;h3 id=&quot;what-are-the-differences-between-aurora-and-raft%3F&quot; tabindex=&quot;-1&quot;&gt;What are the differences between Aurora and Raft?&lt;/h3&gt;
&lt;p&gt;Obviously, Raft is a consensus algorithm,
while Aurora is a database deployment.
It&#39;s more accurate to ask the question:
how does Aurora manage to maintain a consistent state
and how does it compare to the way that Raft does it?&lt;/p&gt;
&lt;p&gt;At first glance they seem quite similar.
There is one leader which is the source of truth.
This leader writes to a log, which is then applied to get the state.
Aurora&#39;s &amp;quot;epoch&amp;quot; is a monotonically increasing value,
much like the &amp;quot;term&amp;quot; in Raft:
it&#39;s provided as part of every read or write to a storage node,
and storage nodes will not accept requests at stale volume epochs.&lt;/p&gt;
&lt;p&gt;The key assumption Aurora can make is that there is
&lt;em&gt;a common shared state&lt;/em&gt;.
In Raft we can&#39;t assume that we have e.g.
the provably correct term number,
the provably correct leader,
even the provably correct log.
and what not.
So there&#39;s a difficult problem of consensus;
we need to agree on a leader, agree on the term,
without a single source of truth.
In Aurora there&#39;s no &lt;em&gt;need&lt;/em&gt; for consensus:
you literally just read the log from the storage service,
and read the VDL/epoch/etc. directly from the metadata store.&lt;/p&gt;
&lt;p&gt;In this sense, Aurora isn&#39;t really a distributed system at all!
We always know the VDL, largest LSN, and epoch,
because these are all persisted in the metadata store.
And once we have quorum from the four out of six storage nodes,
we&#39;re guaranteed that we will always know the correct VCL.
The only distributed bit is the storage service,
but again there&#39;s no issue with consensus because each storage service
HAS to append its logs as long as the epoch number is valid.
The storage service has to query the storage metadata service
before servicing any read or write request (page 792 of 2018 paper).
(what happens when the storage service receives a stale volume epoch though?)&lt;/p&gt;
&lt;h3 id=&quot;what-are-the-similarities-and-differences-between-aurora-and-memcache%3F&quot; tabindex=&quot;-1&quot;&gt;What are the similarities and differences between Aurora and Memcache?&lt;/h3&gt;
&lt;h3 id=&quot;do-replicas-apply-log-records-above-or-below-the-vdl%3F&quot; tabindex=&quot;-1&quot;&gt;Do replicas apply log records ABOVE or BELOW the VDL?&lt;/h3&gt;
&lt;p&gt;2017 paper section 4.2.4, &amp;quot;Replicas&amp;quot; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The replica obeys the following two important rules while applying log
records: (a) the only log records that will be applied are those &lt;strong&gt;whose LSN is
less than or equal to the VDL&lt;/strong&gt;, and (b) the log records that are part of a
single mini-transaction are applied atomically in the replica&#39;s cache to
ensure that the replica sees a consistent view of all database objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;2018 paper section 3.3, &amp;quot;Structural Consistency in Aurora Replicas&amp;quot; says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To create equivalent ordering, we ensure that log records are only shipped
from the writer instance in MTR chunks. At the replica, they must be applied
in LSN order, &lt;strong&gt;applied only if above the VDL in the writer as seen in the
replica&lt;/strong&gt;, and applied atomically in MTR chunks to the subset of blocks in
the cache. Read requests are made relative to VDL points to avoid seeing
structurally inconsistent data.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So is it &amp;quot;less than or equal to&amp;quot;, or &amp;quot;above&amp;quot; the VDL??&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: Thanks Zongran:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So the 2017 statement means that you only apply the redo logs whose LSN is below VDL as they are considered durable by quorum; 2018’s statement has this context that the read instance’s view of the write’s VDL is lagging, and hence you only need to make up using those redo logs from write instance whose LSN is higher than your current view of the writer’s VDL&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;https://blog.acolyer.org/2019/03/25/amazon-aurora-design-considerations-for-high-throughput-cloud-native-relational-databases/&lt;/li&gt;
&lt;li&gt;https://www.allthingsdistributed.com/2019/03/Amazon-Aurora-design-cloud-native-relational-database.html&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2020/notes/l-aurora.txt&quot;&gt;MIT Lecture Notes on Aurora&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nil.csail.mit.edu/6.824/2020/papers/aurora-faq.txt&quot;&gt;MIT Aurora FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>FLP Impossibility Theorem</title>
    <link href="https://lieuzhenghong.com/flp_theorem/"/>
    <updated>2021-03-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/flp_theorem/</id>
    <content type="html">&lt;p&gt;What does asychronous mean?&lt;/p&gt;
&lt;p&gt;You have a distributed system&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We work under message passing model
Asynchronous: clocks are unreliable, non bounded clock skew
no assumptions on timing&lt;/p&gt;
&lt;p&gt;Question: N nodes have a value between 0 and 1.
Eventually all nodes must agree on a value
that is meaningful (non-vacuous).
If all nodes were given 0, then we have to agree on 0,
and if all nodes were given 1, then we have to agree on 1.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a set of processors, each with an initial value:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All non-faulty processes eventually decide on a value&lt;/li&gt;
&lt;li&gt;All processes that decide do so on the same value&lt;/li&gt;
&lt;li&gt;The value that has been decided must have proposed by some process&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These three properties are referred to as termination, agreement and validity. Any algorithm that has these three properties can be said to solve the consensus problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What is the relation with the two generals problem?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The FLP is a generalisation of the two generals problem, for N.&lt;/li&gt;
&lt;li&gt;If the two generals have a shared clock, this is possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Impossibility theorem:&lt;/p&gt;
&lt;p&gt;Also your messages will always be delivered.
I may crash any one of you guys.&lt;/p&gt;
&lt;p&gt;From your perspec&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Processors are allowed to fail according to the fail-stop model - this
simply means that processors that fail do so by ceasing to work correctly.
There are more general failure models, such as Byzantine failures where
processors fail by deviating arbitrarily from the algorithm they are
executing. Again, by strengthening the model - by making strong assumptions
about what is possible - the authors make their result much more general. The
argument is as follows: if a given problem is proven unsolvable in a very
restricted environment where only a few things can go wrong, it will
certainly be unsolvable in an environment where yet more things can go wrong.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Any such algorithm that tries to give an answer in bounded time &lt;em&gt;must sometimes be wrong&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;statement-of-the-theorem&quot; tabindex=&quot;-1&quot;&gt;Statement of the theorem&lt;/h2&gt;
&lt;p&gt;There is no algorithm that solves the problem ==&amp;gt; any algorithm
that terminates in finite time is&lt;/p&gt;
&lt;h2 id=&quot;terminology&quot; tabindex=&quot;-1&quot;&gt;Terminology&lt;/h2&gt;
&lt;p&gt;We have a vector of states &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S_1, ... S_n&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0576em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
We allow nodes to send or receive messages:
the conent of the message, and the recipient of the message.
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(p, m)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the recipient and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;m&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the message.&lt;/p&gt;
&lt;p&gt;Messages are always delivered in finite time.&lt;/p&gt;
&lt;p&gt;Univalent and bivalent: 0-valent, 1-valent.&lt;/p&gt;
&lt;p&gt;0-valent means&lt;/p&gt;
&lt;p&gt;Bi-valent: if you have a state &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;M&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;Processes can do one of two things: they can&lt;/p&gt;
&lt;p&gt;Allowed operations:&lt;/p&gt;
&lt;p&gt;At every step: you may either take a message from the message pile
and apply it to the state list,
or you may throw a message into the message pile.&lt;/p&gt;
&lt;p&gt;Claim: There is no algorithm that starts off in a bivalent state
and ends up in a univalent state.&lt;/p&gt;
&lt;p&gt;Assume there is a god algorithm that starts with any state list
and gives you some output. Ergo, every state you feed it is a univalent state.&lt;/p&gt;
&lt;p&gt;Gray Coding: one where you lay out the sequence of n bits
and every step you go down you only change one bit.
Between any two rows or wrap over back around, you only flip one bit.&lt;/p&gt;
&lt;p&gt;There must be two rows that differ in exactly one bit,
and have different values 0 and 1 (Proof is trivial.)
But if you have to tolerate one crash, then&lt;/p&gt;
&lt;p&gt;=&amp;gt; Ergo, there must be some state that is bivalent for any algorithm&lt;/p&gt;
&lt;p&gt;And the idea is that we feed in a bivalent state,
and keep it bivalent while passing the messages.&lt;/p&gt;
&lt;p&gt;we have a message &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;e = (p, m)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; in the message pile,
and there&#39;s a way to keep it bivalent&lt;/p&gt;
&lt;p&gt;Let C denote the set of states that can be reached from T without delivering this message.&lt;/p&gt;
&lt;p&gt;And let D as the set of states that can be reached from T with delivering this message.&lt;/p&gt;
&lt;p&gt;In order to keep the entire system bivalent, there must be one bivalent state in D.&lt;/p&gt;
&lt;p&gt;Assume by contradiction. So every state in D must be univalent&lt;/p&gt;
&lt;p&gt;If a configuration in C is zero valent, delivering a message
in C0 will result in a state that is also zero valent.
Ditto with one-valent.&lt;/p&gt;
&lt;p&gt;If &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;msup&gt;&lt;mrow&gt;&lt;/mrow&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{&amp;#x27;}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1369em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9425em;&quot;&gt;&lt;span style=&quot;top:-2.9425em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5795em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8278em;&quot;&gt;&lt;span style=&quot;top:-2.931em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  are different (different receivers),
we can reorder the message order, ... F0 to F1
because there will be&lt;/p&gt;
&lt;p&gt;It cannot be the case that they are different.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Notes on technical mentorship</title>
    <link href="https://lieuzhenghong.com/technical_mentorship/"/>
    <updated>2021-02-21T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/technical_mentorship/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I thought Richard Artoul&#39;s post
&lt;a href=&quot;https://medium.com/@richardartoul/from-coding-bootcamp-graduate-to-building-distributed-databases-29acbb723d8&quot;&gt;From coding bootcamp graduate to building distributed databases&lt;/a&gt;
on HN today was excellent.&lt;/p&gt;
&lt;p&gt;What can I learn from it and how can I maximise my own technical mentorship?&lt;/p&gt;
&lt;h2 id=&quot;take-responsibility-for-your-career-trajectory&quot; tabindex=&quot;-1&quot;&gt;Take responsibility for your career trajectory&lt;/h2&gt;
&lt;p&gt;At some point in your career you’ll have to start taking responsibility for your career trajectory. The key insight is that you should make decisions about what projects to work on and which teams and companies to join strategically, not tactically. Think long term.&lt;/p&gt;
&lt;p&gt;In the grand scheme of things, a 10% to 30% difference in compensation for a few years is small in the grand scheme of your career. After my first two years at Uber I could have switched companies for an easy 30% to 40% boost in my compensation, but instead I made a strategic decision to position myself on a team where I was paid “below market”, but where I was developing skills that I would leverage to achieve a 3x jump in my compensation later.&lt;/p&gt;
&lt;p&gt;In particular, there are two areas that you should pay particular attention to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Finding good mentors&lt;/li&gt;
&lt;li&gt;Developing a valuable and unique skill set&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;do-whatever-it-takes-to-find-good-mentors&quot; tabindex=&quot;-1&quot;&gt;Do whatever it takes to find good mentors&lt;/h2&gt;
&lt;p&gt;Nothing will accelerate your growth faster than spending all day working with
other very good engineers. The moment you start to feel like you’re not learning
from the engineers around you is the moment you should start looking for a new
team.&lt;/p&gt;
&lt;p&gt;Keep in mind that when I use the term “mentor” I mean engineers that you work
with everyday, participate in design discussions with, and who review your code
on a regular basis. This is very different from a “mentor” that you solicit
career advice from once a month over coffee.&lt;/p&gt;
&lt;p&gt;There is no exact formula for finding good mentors. The key is having the
humility to recognize those people when you meet them, and to be willing to
make sacrifices to be around them.&lt;/p&gt;
&lt;p&gt;If you work at a large company, this process shouldn’t be too difficult. Start
asking around and try to identify a high performing team with very good
engineers doing impactful work, and then do whatever you can to start working
with them. Offer to help out on their projects on your own time, or if you’ve
been at the company long enough and have built up some social capital, try and
transfer to that team. Your manager may not be happy about it, but hiring is
hard and the manager of the team that you want to join will likely extend the
necessary political cover to make the transfer happen if they think they can
get a coachable and motivated junior engineer with a proven track record “for
cheap”.&lt;/p&gt;
&lt;p&gt;In my case, I was working at Uber and had been working on the same team for 18
months and was stagnating technically. I told my manager that I was going to
start looking for a new team and then I spoke with the managers of 15 different
teams at the company. The team that seemed to have the most skilled engineers
doing the most technically interesting and impactful work was located in New
York, a city I had no interest in moving to, but I flew to NY on my own dime
and spent 3 days working with their team on a small task. After meeting the
team and seeing how skilled they were, I knew I had to move to New York even
though I didn’t know anyone there. In hindsight, that decision completely
altered the trajectory of my career and I have no doubt that I wouldn’t be
where I am today if I hadn’t prioritized technical mentorship over everything
else that was going on in my life at the time.&lt;/p&gt;
&lt;p&gt;Obviously dropping everything and moving across the country isn’t an option for
everyone, but if your goal is to get dramatically better then finding mentors
should be one of your top priorities.&lt;/p&gt;
&lt;p&gt;It’s also worth emphasizing that I interviewed with 15 different teams. That’s
a lot of opportunities to investigate! For context, after I graduated from my
bootcamp I had 3 onsite interviews before landing at Uber. If you assume that
opportunities follow some kind of power law distribution such that some
opportunities are significantly more valuable than others, then going through
this exercise whenever possible will likely lead to much better outcomes. If
you then factor into the equation that these types of decisions compound over
the lifetime of your career it starts to seem grossly negligent to not take
this exercise seriously everytime you’re gearing up for a major change.&lt;/p&gt;
&lt;h3 id=&quot;how-to-find-good-mentors-if-i&#39;m-not-in-a-large-company-with-very-good-engineers%3F&quot; tabindex=&quot;-1&quot;&gt;How to find good mentors if I&#39;m not in a large company with very good engineers?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;If you work at a large company, this process shouldn’t be too difficult. Start
asking around and try to identify a high performing team with very good
engineers doing impactful work, and then do whatever you can to start working
with them.&lt;/p&gt;
&lt;p&gt;In hindsight, that decision completely
altered the trajectory of my career and I have no doubt that I wouldn’t be
where I am today if I hadn’t prioritized technical mentorship over everything
else that was going on in my life at the time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In his telling, technical mentorship is very important.
It&#39;s great that he was at Uber. I am not at Uber. What can I do instead?&lt;/p&gt;
&lt;p&gt;Here&#39;s Atul Gawande on finding a coach for his surgery
(got his old professor to observe his surgeries)
&lt;a href=&quot;https://www.newyorker.com/magazine/2011/10/03/personal-best&quot;&gt;Personal Best&lt;/a&gt;
This is bootstrapping technical mentorship, in a way.
What can I learn from this?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Some rough notes on React after playing with it for a day</title>
    <link href="https://lieuzhenghong.com/react_notes/"/>
    <updated>2021-02-19T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/react_notes/</id>
    <content type="html">&lt;div class=&quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#how-do-you-pass-parameters-into-a-callback-function%3F&quot;&gt;How do you pass parameters into a callback function?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#hooks-tl%3Bdr&quot;&gt;Hooks TL;DR&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#what-is-the-dispatch-method-in-the-usereducer-hook%3F&quot;&gt;What is the dispatch method in the useReducer hook?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#what&#39;s-usereducer-for%3F-why-use-it-over-usestate&quot;&gt;What&amp;#39;s useReducer for? Why use it over useState&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#what-is-context%3F&quot;&gt;What is context?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/react_notes/#bibliography&quot;&gt;Bibliography&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&#39;m preparing for an upcoming interview where I&#39;m expected to know React.
As practice I built a very ugly, very silly
&lt;a href=&quot;https://lieuzhenghong.com/react-practice&quot;&gt;page that allows you to customise your food to the gram&lt;/a&gt;
(some names considered and rejected: &amp;quot;Food for Autists&amp;quot;, &amp;quot;Macro Madlads&amp;quot;)
last night in a couple of hours.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/react_practice/v1.jpg&quot; alt=&quot;Screenshot of the very ugly page&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;lieu, [19.02.21 13:06]
A website that allows you to build your own bowl (carbs, protein, veg, etc) but the macros are automatically updated&lt;/p&gt;
&lt;p&gt;lieu, [19.02.21 13:06]
so you can pick exactly how many grams of chicken breast and pasta you want&lt;/p&gt;
&lt;p&gt;lieu, [19.02.21 13:06]
Then pay and then we offer islandwide delivery within an hour&#39;s time&lt;/p&gt;
&lt;p&gt;lieu, [19.02.21 13:06]
Carbs: rice (brown/white), pasta (0g is an option)
Protein: chicken breast, oven baked salmon, beef steak, tofu, egg
Vegetables: random salad vegetable, kimchi, broccoli, edamame, cherry tomatoes.
Price: base bowl/delivery cost + all items sold by weight, carbs and protein accurate to the gram.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The idea is not that important:
the main objective here is to practice writing clean, idiomatic, modern React code.
&lt;a href=&quot;https://github.com/lieuzhenghong/react-practice/tree/master/src&quot;&gt;GH repo here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-do-you-pass-parameters-into-a-callback-function%3F&quot; tabindex=&quot;-1&quot;&gt;How do you pass parameters into a callback function?&lt;/h2&gt;
&lt;p&gt;Suppose you have the following React components
where a child element calls a callback function
&lt;code&gt;onChange&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Parent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// do something...&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Child handleChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleChange&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input onChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;handleChange&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what happens if you want to pass some parameters to the parent function?
I was stuck on this for quite a while until Nick pointed this out to me.
Don&#39;t think of passing parameters into a callback function per se;
rather, create a higher-order function that &lt;em&gt;then&lt;/em&gt; calls the parent&#39;s callback function.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Parent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// do something with the value&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Child handleChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;handleChange&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Child&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;input onChange&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleChange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[?] Although I wonder if &lt;code&gt;handleChange&lt;/code&gt; would be already implicitly called
with &lt;code&gt;e&lt;/code&gt; as the argument...&lt;/p&gt;
&lt;h2 id=&quot;hooks-tl%3Bdr&quot; tabindex=&quot;-1&quot;&gt;Hooks TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;useState: takes in an initial state object,
returns a &lt;code&gt;state&lt;/code&gt; object and a &lt;code&gt;setState&lt;/code&gt; function that mutates that &lt;code&gt;state&lt;/code&gt; object.&lt;/li&gt;
&lt;li&gt;useEffect: takes in a function that usually performs side effects.
That function may return a function. If so, the _returned _function is run
when the&lt;/li&gt;
&lt;li&gt;useReducer: takes in an initial &lt;code&gt;reducer&lt;/code&gt; function and an initial state
and returns &lt;code&gt;[state, dispatch]&lt;/code&gt;. &lt;code&gt;state&lt;/code&gt; is straightforward, just like
the one in &lt;code&gt;useState&lt;/code&gt;. What&#39;s &lt;code&gt;dispatch&lt;/code&gt; and how is it different from &lt;code&gt;setState&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Internally, Hooks are implemented as linked lists. When you call useState, we
move the pointer to the next item. When we exit the component’s “call tree”
frame, we save the resulting list there until the next render.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(source: &lt;a href=&quot;https://overreacted.io/react-as-a-ui-runtime/&quot;&gt;React as a UI runtime&lt;/a&gt;)&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-dispatch-method-in-the-usereducer-hook%3F&quot; tabindex=&quot;-1&quot;&gt;What is the &lt;code&gt;dispatch&lt;/code&gt; method in the &lt;code&gt;useReducer&lt;/code&gt; hook?&lt;/h3&gt;
&lt;p&gt;The
&lt;a href=&quot;https://reactjs.org/docs/hooks-reference.html#usereducer&quot;&gt;useReducer section of the Hooks Reference API&lt;/a&gt;
writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;useReducer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;const [state, dispatch] = useReducer(reducer, initialArg, init);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;An alternative to useState.
Accepts a reducer of type (state, action) =&amp;gt; newState, and returns the current state paired with a dispatch method.
(If you’re familiar with Redux, you already know how this works.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;m not familiar with Redux, and I don&#39;t know how this works.
The reducer function is simple enough:
it&#39;s a function that takes in a &lt;code&gt;state&lt;/code&gt; and an &lt;code&gt;action&lt;/code&gt; object
and returns a new state object.
But what exactly is the function signature of &lt;code&gt;dispatch&lt;/code&gt;?
Well, it turns out that another section of the React docs
&lt;a href=&quot;https://reactjs.org/docs/hooks-custom.html&quot;&gt;Building Your Own Hooks&lt;/a&gt;
has it.
The &lt;code&gt;dispatch&lt;/code&gt; function simply calls the provided &lt;code&gt;reducer&lt;/code&gt; function on the state
to get the new state object, &lt;code&gt;nextState&lt;/code&gt;.
It then mutates the state using &lt;code&gt;setState(nextState)&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useReducer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;reducer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; initialState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; setState&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nextState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reducer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; action&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
              
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dispatch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here&#39;s how we would use this &lt;code&gt;dispatch&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Todos&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;todos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dispatch&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;useReducer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;todosReducer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handleAddClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;add&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; text  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can think of &lt;code&gt;dispatch&lt;/code&gt; as a &amp;quot;higher-level &lt;code&gt;setState&lt;/code&gt;&amp;quot;:
while &lt;code&gt;setState&lt;/code&gt; merely replaces one state with another,
&lt;code&gt;dispatch&lt;/code&gt; allows us to specify exactly &lt;em&gt;how&lt;/em&gt; we want to
&lt;code&gt;setState&lt;/code&gt; according to the &lt;code&gt;reducer&lt;/code&gt; function.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-usereducer-for%3F-why-use-it-over-usestate&quot; tabindex=&quot;-1&quot;&gt;What&#39;s &lt;code&gt;useReducer&lt;/code&gt; for? Why use it over &lt;code&gt;useState&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The difference between &lt;code&gt;useReducer&lt;/code&gt; and &lt;code&gt;useState&lt;/code&gt;
is that &lt;code&gt;useReducer&lt;/code&gt; allows you to pass it a &lt;code&gt;reducer&lt;/code&gt; function.
&lt;code&gt;useReducer&lt;/code&gt; also returns a &lt;code&gt;dispatch&lt;/code&gt; function that is the equivalent
of &lt;code&gt;setState&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Why would you use dispatch? Why not just pass the &lt;code&gt;setState&lt;/code&gt; function
down as props directly? You can certainly do that, but there are two advantages
to using dispatch.&lt;/p&gt;
&lt;p&gt;Firstly, using &lt;code&gt;dispatch&lt;/code&gt; allows us to simplify complex updating functions,
as well as encapsulate all of the logic in one single &lt;code&gt;reducer&lt;/code&gt; function.
If you didn&#39;t have that function each child component would have to implement
their own function to create a new state before setting it.
With the dispatch pattern you can simply
pass it some parameters and the &lt;code&gt;reducer&lt;/code&gt; function will handle it.
[TODO] (... i&#39;m not entirely convinced. come up with an example where it&#39;s obvious
that the dispatch method is significantly better than just passing setState down)&lt;/p&gt;
&lt;p&gt;Speaking of passing props:
You can use dispatch with &lt;code&gt;useContext&lt;/code&gt; to avoid passing props many levels down.
It&#39;s a way for deeply nested components
to mutate the state of the parent which might be many levels up.
I remember first writing React in 2015 and thinking that it was very
very &lt;em&gt;leceh&lt;/em&gt; to have to pass props down.
[TODO] (but again it&#39;s unclear why I can&#39;t pass the setState function down with context)
But what is &lt;code&gt;useContext&lt;/code&gt;?&lt;/p&gt;
&lt;h3 id=&quot;what-is-context%3F&quot; tabindex=&quot;-1&quot;&gt;What is context?&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;React&#39;s Context API is a mechanism for making a single user-provided value
available to a subtree of components. Any component inside of a given
&lt;code&gt;&amp;lt;MyContext.Provider&amp;gt;&lt;/code&gt; can read the value from that context instance,
without having to explicitly pass that value as a prop through every
intervening component.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;bibliography&quot; tabindex=&quot;-1&quot;&gt;Bibliography&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e&quot;&gt;React Hooks: Not Magic, Just Arrays&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down&quot;&gt;How to avoid passing callbacks down&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Splitting a string into the fewest number of palindromes</title>
    <link href="https://lieuzhenghong.com/splitting_a_string_into_the_fewest_number_of_palindromes/"/>
    <updated>2021-02-18T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/splitting_a_string_into_the_fewest_number_of_palindromes/</id>
    <content type="html">&lt;p&gt;Started 645pm&lt;/p&gt;
&lt;p&gt;Question Number 181&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good morning! Here&#39;s your coding interview problem for today.&lt;/p&gt;
&lt;p&gt;This problem was asked by Google.&lt;/p&gt;
&lt;p&gt;Given a string, split it into as few strings as possible such that each string
is a palindrome.&lt;/p&gt;
&lt;p&gt;For example, given the input string &lt;code&gt;racecarannakayak&lt;/code&gt;,
return &lt;code&gt;[&amp;quot;racecar&amp;quot;, &amp;quot;anna&amp;quot;, &amp;quot;kayak&amp;quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Given the input string &lt;code&gt;abc&lt;/code&gt;, return &lt;code&gt;[&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;, &amp;quot;c&amp;quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;problem-analysis&quot; tabindex=&quot;-1&quot;&gt;Problem analysis&lt;/h3&gt;
&lt;p&gt;Call a &lt;code&gt;partition&lt;/code&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; a list of indices &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;[i_1, i_2, ... i_K]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
where each index &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;i_k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8095em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; denotes where to split the string.
A partition is &lt;em&gt;valid&lt;/em&gt; if each substring&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[0:i_1], S[i_1:i_2], ... ,S[i_{K}:]
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;is a palindrome.&lt;/p&gt;
&lt;p&gt;A partition &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;P&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is &lt;em&gt;minimal&lt;/em&gt; if &lt;code&gt;len(indices)&lt;/code&gt; is
the smallest for all possible valid partitions.&lt;/p&gt;
&lt;p&gt;The recurrence relation is as follows:
The minimal partition of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[0:N]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is
the minimum of minimal partitions of all
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∀&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[k:N+1] \forall k &amp;lt;= N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∀&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[0:k]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a palindrome.&lt;/p&gt;
&lt;p&gt;That is to say, for each k where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[0:k]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a palindrome,
recurse into the subproblem of finding a minimal
partition for &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[k:N+1]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I believe the time complexity is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(N^2)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.
In the worst case each substring is a palindrome,
so you have to check all the substrings.
With memoisation each lookup of a substring is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
and checking whether a substring is a palindrome should
also take constant time if a subsubstring already exists
(checking if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[a:b]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is a palindrome is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; if you have memoised &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;S[a+1, b-1]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;).
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;O(N^2)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; memory complexity.&lt;/p&gt;
&lt;p&gt;Pseudocode:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# TODO
&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Saltzer and Kaashoek (2009). Principles of Computer System Design: An Introduction</title>
    <link href="https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/"/>
    <updated>2021-02-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.1.5-before-or-after-atomicity&quot;&gt;9.1.5 Before-or-After Atomicity&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-sequence-coordination%3F&quot;&gt;What is sequence coordination?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-before-or-after-atomicity%3F&quot;&gt;What is before-or-after atomicity?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what&#39;s-the-difference-between-sequence-coordination-and-before-or-after-atomicity%3F&quot;&gt;What&amp;#39;s the difference between sequence coordination and before-or-after atomicity?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what&#39;s-the-relationship-between-before-or-after-atomicity-and-serialisability%3F-what&#39;s-the-difference%3F&quot;&gt;What&amp;#39;s the relationship between before-or-after atomicity and serialisability? What&amp;#39;s the difference?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what&#39;s-the-difference-between-consistency-models-and-these-atomicity-guarantees%3F&quot;&gt;What&amp;#39;s the difference between consistency models and these atomicity guarantees?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-the-fundamental-definition-of-atomicity%3F&quot;&gt;What is the fundamental definition of atomicity?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.1.6-correctness-and-serialisation&quot;&gt;9.1.6 Correctness and serialisation&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#before-or-after-atomicity-leads-directly-to-this-concept-of-correctness&quot;&gt;Before-or-after atomicity leads directly to this concept of correctness&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#there-are-correctness-requirements-that-are-stronger-than-serialisability%3A-external-time-consistency%2C-or-sequential-consistency&quot;&gt;There are correctness requirements that are stronger than serialisability: external time consistency, or sequential consistency&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-sequential-consistency%3F&quot;&gt;What is sequential consistency?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what&#39;s-the-difference-between-external-time-consistency-and-sequential-consistency%3F&quot;&gt;What&amp;#39;s the difference between external time consistency and sequential consistency?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.5.2-simple-locking&quot;&gt;9.5.2 Simple locking&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#simple-locking-can-cause-deadlocks&quot;&gt;Simple locking can cause deadlocks&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#simple-locking-is-not-completely-efficient&quot;&gt;Simple locking is not completely efficient&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.5.3-two-phase-locking&quot;&gt;9.5.3 Two-phase locking&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#how-can-we-handle-system-recovery-with-locks%3F&quot;&gt;How can we handle system recovery with locks?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#are-volatile-locks-(locks-in-memory)-fault-tolerant%3F&quot;&gt;Are volatile locks (locks in memory) fault-tolerant?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#two-phase-locking-often-results-in-deadlocks&quot;&gt;Two-phase locking often results in deadlocks&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.6.2-two-phase-commit&quot;&gt;9.6.2 Two-phase commit&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#9.6.3-multiple-site-atomicity%3A-distributed-two-phase-commit&quot;&gt;9.6.3 Multiple-Site Atomicity: Distributed Two-Phase commit&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-the-procedure-for-2pc%3F&quot;&gt;What is the procedure for 2PC?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-happens-when-the-coordinator-crashes%3F&quot;&gt;What happens when the coordinator crashes?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-happens-when-a-worker-crashes%3F&quot;&gt;What happens when a worker crashes?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-are-the-tradeoffs-of-2pc%3F&quot;&gt;What are the tradeoffs of 2PC?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#why-must-the-coordinator-must-hold-completion-states-of-all-transactions-indefinitely%3F&quot;&gt;Why must the coordinator must hold completion states of all transactions indefinitely?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#the-two-generals-problem-and-impossibility-theorem&quot;&gt;The Two Generals problem and impossibility theorem&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#given-the-two-generals-impossibility-theorem%2C-how-does-2pc-work%3F&quot;&gt;Given the Two Generals impossibility theorem, how does 2PC work?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#when-would-you-want-to-use-2pc%3F&quot;&gt;When would you want to use 2PC?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#should-one-use-2pc-or-raft%3F&quot;&gt;Should one use 2PC or Raft?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#what-is-the-relationship-between-2pc%2C-3pc%2C-and-raft%3F&quot;&gt;What is the relationship between 2PC, 3PC, and Raft?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I read this paper as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This week we read the Saltzer and Kaashoek (2009)
textbook, which explained atomicity,
consistency, locking, two-phase commits,
and distributed two-phase commits.
&lt;a href=&quot;https://tsong.co/blog/6.824-distributed-transactions-notes/&quot;&gt;Song Tianyi&lt;/a&gt;
was in charge of explaining this week
(click the link for his notes).&lt;/p&gt;
&lt;p&gt;I&#39;ve marked things I don&#39;t know with &lt;code&gt;[?]&lt;/code&gt;
and bits that still need work with &lt;code&gt;[TODO]&lt;/code&gt;.
Please help me clarify or fill them in!&lt;/p&gt;
&lt;h2 id=&quot;9.1.5-before-or-after-atomicity&quot; tabindex=&quot;-1&quot;&gt;9.1.5 Before-or-After Atomicity&lt;/h2&gt;
&lt;h3 id=&quot;what-is-sequence-coordination%3F&quot; tabindex=&quot;-1&quot;&gt;What is sequence coordination?&lt;/h3&gt;
&lt;p&gt;[?]&lt;/p&gt;
&lt;p&gt;not sure about this&lt;/p&gt;
&lt;p&gt;Sequence coordination ensures some logical order/
semantics of the object,
e.g. you cannot dequeue before enqueuing.&lt;/p&gt;
&lt;h3 id=&quot;what-is-before-or-after-atomicity%3F&quot; tabindex=&quot;-1&quot;&gt;What is before-or-after atomicity?&lt;/h3&gt;
&lt;p&gt;Concurrent actions possess &lt;strong&gt;before-or-after atomicity&lt;/strong&gt;
if their effect from the point of view of the invokers
is the same as if the actions occurred
either &lt;em&gt;completely before&lt;/em&gt; or &lt;em&gt;completely after&lt;/em&gt;
one another.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-sequence-coordination-and-before-or-after-atomicity%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between sequence coordination and before-or-after atomicity?&lt;/h3&gt;
&lt;p&gt;[?]&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-relationship-between-before-or-after-atomicity-and-serialisability%3F-what&#39;s-the-difference%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the relationship between before-or-after atomicity and serialisability? What&#39;s the difference?&lt;/h3&gt;
&lt;p&gt;A history H is serialisable if and only if
a concurrent history can be rearranged
into some (any) serial ordering.
&lt;a href=&quot;https://jepsen.io/consistency/models/serializable&quot;&gt;&amp;quot;Informally, serializability means that transactions appear to have occurred in some total order.&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Before-or-after atomicity implies serialisability.
Consider any set of concurrent actions.
By before-or-after atomicity (BAA) they
must appear to have occurred either completely
before or completely after one another.
But that directly implies that there exists
some serial ordering of these concurrent transactions,
which is exactly what we need for serialisability.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-consistency-models-and-these-atomicity-guarantees%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between consistency models and these atomicity guarantees?&lt;/h3&gt;
&lt;p&gt;[?]&lt;/p&gt;
&lt;p&gt;There is another atomicity guarantee
called &lt;em&gt;all-or_nothing&lt;/em&gt; atomicity.
You need before-or-after and all-or-nothing atomicity
in order to get serialisability?&lt;/p&gt;
&lt;p&gt;I think before-or-after atomicity implies
all-or-nothing atomicity.
This is because if all-or-nothing atomicity
was violated, it would be possible for
half of a transaction to fail and
half of a transaction to succeed... so what?
is that OK as long as both halves lie before or
after other transactions?&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-fundamental-definition-of-atomicity%3F&quot; tabindex=&quot;-1&quot;&gt;What is the fundamental definition of atomicity?&lt;/h3&gt;
&lt;p&gt;Both atomicity guarantees can be thought of as
what we &lt;em&gt;really&lt;/em&gt; care about:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An action is atomic if there is no way for a higher layer to discover the internal structure of its implementation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;9.1.6-correctness-and-serialisation&quot; tabindex=&quot;-1&quot;&gt;9.1.6 Correctness and serialisation&lt;/h2&gt;
&lt;p&gt;The textbook gives this general concept of correctness:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;if any result is guaranteed to be one that
could have been obtained by some
&lt;em&gt;purely serial&lt;/em&gt; application of those same actions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is serialisability!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;before-or-after-atomicity-leads-directly-to-this-concept-of-correctness&quot; tabindex=&quot;-1&quot;&gt;Before-or-after atomicity leads directly to this concept of correctness&lt;/h3&gt;
&lt;p&gt;If all transactions are before-or-after atomic,
then they must form some purely serial ordering.
And if they form some purely serial ordering,
this is the definition of serialisability.&lt;/p&gt;
&lt;p&gt;Note that serialisabilty places no constraints on
the total order, so transactions may appear
to execute in any (serial) order.
There are correctness requirements stricter
than serialisability:
we walk through two here.&lt;/p&gt;
&lt;h3 id=&quot;there-are-correctness-requirements-that-are-stronger-than-serialisability%3A-external-time-consistency%2C-or-sequential-consistency&quot; tabindex=&quot;-1&quot;&gt;There are correctness requirements that are stronger than serialisability: external time consistency, or sequential consistency&lt;/h3&gt;
&lt;p&gt;External time consistency
(that transactions must appear to happen
in the order that they were called)
is equivalent to &lt;em&gt;strict serialisability&lt;/em&gt;.
Note that strict serialisability is not
quite the same (is stricter than)
linearisability:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We can view strict serializability as linearizability plus the multi-object
transactions of serializability. But in another sense, linearizability is
strict serializability with the constraint that transactions are constrained
to act on a single object
&lt;a href=&quot;https://aphyr.com/posts/333-serializability-linearizability-and-locality&quot;&gt;source&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;what-is-sequential-consistency%3F&quot; tabindex=&quot;-1&quot;&gt;What is sequential consistency?&lt;/h3&gt;
&lt;p&gt;Sequential consistency is stronger than serialisability.
It requires that transactions must appear
to have occurred in some order, &lt;em&gt;and&lt;/em&gt;
that
transactions must appear to have occurred
in order on a &lt;em&gt;per-process&lt;/em&gt; basis.&lt;/p&gt;
&lt;p&gt;For example, this concurrent history&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;B READ x 
A READ x
B WRITE x
A WRITE x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;would be serialisable
but not sequentially consistent
if the following execution order was permitted:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;A WRITE x
A READ x
B WRITE x
B READ x 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This respects a serial ordering,
but is not sequentially consistent because
process A needs to read before writing.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-difference-between-external-time-consistency-and-sequential-consistency%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the difference between external time consistency and sequential consistency?&lt;/h3&gt;
&lt;p&gt;External time consistency imposes a time order on all different processes.
In sequential consistency
all transactions &lt;em&gt;within a process&lt;/em&gt; must run sequentially.
But there&#39;s no requirement for real-time order
&lt;em&gt;between&lt;/em&gt; processes.&lt;/p&gt;
&lt;h2 id=&quot;9.5.2-simple-locking&quot; tabindex=&quot;-1&quot;&gt;9.5.2 Simple locking&lt;/h2&gt;
&lt;p&gt;We next consider how to maintain correctness.
One way is locking.
We first consider &lt;em&gt;simple locking.&lt;/em&gt;
There&#39;s a lock manager that manages the locks.
Each transaction has to acquire all the locks
that it will need before starting the transaction.
The transaction has what is called a &lt;em&gt;lock point&lt;/em&gt;:
the instant at which it has acquired all of its locks.
It may release its locks only after the transaction
installs its last update and commits or completely
restores its data (aborts).&lt;/p&gt;
&lt;p&gt;A lock manager can enforce simple locking by requiring
that each transaction supply its intended lock set
to the function call.&lt;/p&gt;
&lt;h3 id=&quot;simple-locking-can-cause-deadlocks&quot; tabindex=&quot;-1&quot;&gt;Simple locking can cause deadlocks&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;p&gt;Consider the following scenario:&lt;/p&gt;
&lt;p&gt;Mitigate this by assigning each lock a unique ID
and mandate that each process tries to acquire
each lock in order.&lt;/p&gt;
&lt;h3 id=&quot;simple-locking-is-not-completely-efficient&quot; tabindex=&quot;-1&quot;&gt;Simple locking is not completely efficient&lt;/h3&gt;
&lt;p&gt;However, simple locking might not be efficient
because it needs to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;acquire locks on
every shared object that it &lt;em&gt;might&lt;/em&gt; need
to read or write, even if it doesn&#39;t
need it in the end;&lt;/li&gt;
&lt;li&gt;acquire locks on &lt;em&gt;all objects&lt;/em&gt; at the start,
even if the transaction is long-running
and it may only need the lock towards the end.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So there are some more optimistic approaches.
One of them is &lt;em&gt;two-phase locking&lt;/em&gt;,
which we&#39;ll cover next.&lt;/p&gt;
&lt;h2 id=&quot;9.5.3-two-phase-locking&quot; tabindex=&quot;-1&quot;&gt;9.5.3 Two-phase locking&lt;/h2&gt;
&lt;p&gt;Two-phase locking improves upon simple locking
in two &lt;em&gt;key&lt;/em&gt; (ha ha) ways:
rather than forcing a transaction to acquire
all the locks before it begins,
it allows the transaction to acquire locks as it proceeds.
The transaction may read or write a data object
only after it acquires a lock on that object.&lt;/p&gt;
&lt;p&gt;Second, instead of forcing a transaction to
release all locks at the end,
the transaction may release a lock on an object
that it &lt;em&gt;only reads&lt;/em&gt; &lt;strong&gt;if&lt;/strong&gt; it will never need to read
that object again, even to abort.
(Note that it can&#39;t release a lock on an object
that it writes, because it would be impossible
to roll back!)&lt;/p&gt;
&lt;p&gt;This is called two-phase locking because the number of
locks requested by a transaction increases monotonically
at the start, then decreases monotonically.&lt;/p&gt;
&lt;p&gt;However, two-phase locking still has its inefficiencies...&lt;/p&gt;
&lt;p&gt;[todo]&lt;/p&gt;
&lt;h3 id=&quot;how-can-we-handle-system-recovery-with-locks%3F&quot; tabindex=&quot;-1&quot;&gt;How can we handle system recovery with locks?&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;p&gt;There are two interactions between locks and logs that
require thought: 1) individual transactions that abort,
and 2) system recovery.&lt;/p&gt;
&lt;p&gt;Aborts are easy, since all aborting transactions
must restore their changed data objects to
their original values before releasing any locks.&lt;/p&gt;
&lt;h3 id=&quot;are-volatile-locks-(locks-in-memory)-fault-tolerant%3F&quot; tabindex=&quot;-1&quot;&gt;Are volatile locks (locks in memory) fault-tolerant?&lt;/h3&gt;
&lt;p&gt;What happens if you have processes holding
different sets of locks and then they crash?
How do you make sure that reconstructing the
new state from the logs ensures the correct
(serialisable) outcome?&lt;/p&gt;
&lt;h3 id=&quot;two-phase-locking-often-results-in-deadlocks&quot; tabindex=&quot;-1&quot;&gt;Two-phase locking often results in deadlocks&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;p&gt;Two-phase locking results in deadlocks but
simple locking does not result in deadlocks
(why?) as long as you index locks in order.
(Prove this -- also mentioned in GFS)&lt;/p&gt;
&lt;h2 id=&quot;9.6.2-two-phase-commit&quot; tabindex=&quot;-1&quot;&gt;9.6.2 Two-phase commit&lt;/h2&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;p&gt;Go through this myself&lt;/p&gt;
&lt;h2 id=&quot;9.6.3-multiple-site-atomicity%3A-distributed-two-phase-commit&quot; tabindex=&quot;-1&quot;&gt;9.6.3 Multiple-Site Atomicity: Distributed Two-Phase commit&lt;/h2&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;p&gt;In Chapter 4 we learned of the Remote Procedure Call method
and in Chapter 7 we learned how to design an RPC
with a persistent sender.
Now we combine a two-phase commit protocol with
&lt;em&gt;persistent senders&lt;/em&gt;, &lt;em&gt;duplicate suppression&lt;/em&gt;,
and &lt;em&gt;single-site transactions&lt;/em&gt;
to build a distributed two-phase commit protocol.&lt;/p&gt;
&lt;p&gt;Correctness of multiple-site atomicity
is when all the sites commit OR
all the sites abort;
we will have failed if some sites commit their part
of a multiple-site transaction while others
abort their part of that same transaction.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-procedure-for-2pc%3F&quot; tabindex=&quot;-1&quot;&gt;What is the procedure for 2PC?&lt;/h3&gt;
&lt;p&gt;First phase: Alice the coordinator assigns
its child jobs to its slaves:
&lt;code&gt;PREPARE TO COMMIT X&lt;/code&gt;.
Bob, Charlie and Dawn &lt;strong&gt;PREPARE&lt;/strong&gt;
to commit X (commit tentatively).
They acquire and don&#39;t release the locks.
(or abort, if they can&#39;t):
&lt;code&gt;I HAVE PREPARED TO COMMIT X&lt;/code&gt; or
&lt;code&gt;I HAVE ABORTED X&lt;/code&gt;.
Second phase: Only after receiving
all tentative commits,
or any least one abort,
will Alice choose to abort the entire
transaction or tell a different worker site
to carry its component transaction.
Alice marks her own outcome record &lt;code&gt;COMMITTED&lt;/code&gt;
and sends
&lt;code&gt;COMMIT&lt;/code&gt; back to Bob, Charles and Dawn.
Each worker site, upon receiving such a message,
changes its state from &lt;code&gt;PREPARED&lt;/code&gt; to &lt;code&gt;COMMITTED&lt;/code&gt;
and exits.&lt;/p&gt;
&lt;p&gt;Only three messages are needed:
one message to tell the worker to prepare the commit,
one message to tell the master that it&#39;s prepared,
and one message to tell the worker to commit.&lt;/p&gt;
&lt;p&gt;Bob, Charlie and Dawn can lose messages arbitrarily,
so Alice will never know if they have received her message to commit.
However, since Bob, Charlie and Dawn are persistent senders
(they keep asking if they haven&#39;t received a commit
instruction),
Alice can be confident
that the workers will commit their transactions &lt;em&gt;eventually&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-happens-when-the-coordinator-crashes%3F&quot; tabindex=&quot;-1&quot;&gt;What happens when the coordinator crashes?&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;h3 id=&quot;what-happens-when-a-worker-crashes%3F&quot; tabindex=&quot;-1&quot;&gt;What happens when a worker crashes?&lt;/h3&gt;
&lt;p&gt;There are four places a worker can crash:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Before it receives the first phase message&lt;/li&gt;
&lt;li&gt;After it receives the first phase message,
but before it sends the prepared message&lt;/li&gt;
&lt;li&gt;After it sends the prepared message,
but before receiving a commit message&lt;/li&gt;
&lt;li&gt;After receiving a commit message&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only state 3 is nontrivial:
recovery procedure must reacquire all locks
the &lt;strong&gt;PREPARED&lt;/strong&gt; transaction was holding
at the time of the failure.
The recovery procedure must also restart
the persistent sender.&lt;/p&gt;
&lt;h3 id=&quot;what-are-the-tradeoffs-of-2pc%3F&quot; tabindex=&quot;-1&quot;&gt;What are the tradeoffs of 2PC?&lt;/h3&gt;
&lt;p&gt;2PC gives up availability:
nodes can block forever if the coordinator goes down.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/&quot;&gt;The Spinnaker paper&lt;/a&gt;
mentions a few other tradeoffs:
Firstly, the failure of a single node will lead to an abort.
Secondly, it suffers in performance:
a typical implementation of 2PC requires 2 disk forces
and 2 message delays.
Lastly, it also blocks when the coordinator fails.&lt;/p&gt;
&lt;h3 id=&quot;why-must-the-coordinator-must-hold-completion-states-of-all-transactions-indefinitely%3F&quot; tabindex=&quot;-1&quot;&gt;Why must the coordinator must hold completion states of all transactions indefinitely?&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;h3 id=&quot;the-two-generals-problem-and-impossibility-theorem&quot; tabindex=&quot;-1&quot;&gt;The Two Generals problem and impossibility theorem&lt;/h3&gt;
&lt;p&gt;The Two Generals problem is an impossibility theorem
that states that it is impossible for
two nodes to reach consensus over a lossy network.
There&#39;s a lovely formalisation of the problem
and the impossibility proof
&lt;a href=&quot;https://mwhittaker.github.io/blog/two_generals_and_time_machines/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;given-the-two-generals-impossibility-theorem%2C-how-does-2pc-work%3F&quot; tabindex=&quot;-1&quot;&gt;Given the Two Generals impossibility theorem, how does 2PC work?&lt;/h3&gt;
&lt;p&gt;[?]
[TODO]&lt;/p&gt;
&lt;p&gt;You&#39;d think the two generals problem is very
similar to the two-phase commit protocol,
so how come 2PC works despite the impossibility
result?&lt;/p&gt;
&lt;p&gt;Bernard thinks it has to do with the notion of
bounded vs unbounded time.
I think that&#39;s true, but it might be more useful
to think of it more as &lt;em&gt;blocking&lt;/em&gt; vs &lt;em&gt;non-blocking&lt;/em&gt;:
we can&#39;t decide&lt;/p&gt;
&lt;p&gt;There&#39;s a really nice blog post on 2PC
by Henry Robinson
&lt;a href=&quot;https://www.the-paper-trail.org/post/2008-11-27-consensus-protocols-two-phase-commit/&quot;&gt;here&lt;/a&gt;.
I&#39;ll have to read this post
(and the rest of his blog!)
much more closely,
but I think here it solves the consensus problem
but a node failure might block indefinitely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Follow-up:&lt;/strong&gt; what is the relationship
between the FLP and the Two Generals Problem?&lt;/p&gt;
&lt;h3 id=&quot;when-would-you-want-to-use-2pc%3F&quot; tabindex=&quot;-1&quot;&gt;When would you want to use 2PC?&lt;/h3&gt;
&lt;p&gt;If you had independent databases with very non-atomic
transactions e.g when you buy something,
you have child transactions
of contacting the credit card company,
decrementing the stock,
adding loyalty points, etc.
And you want to either commit or
roll all of this back atomically.&lt;/p&gt;
&lt;h3 id=&quot;should-one-use-2pc-or-raft%3F&quot; tabindex=&quot;-1&quot;&gt;Should one use 2PC or Raft?&lt;/h3&gt;
&lt;p&gt;They are solving different problems:
Raft solves the problem of &lt;em&gt;replication&lt;/em&gt;,
2PC solves the problem of &lt;em&gt;coordination&lt;/em&gt;.
We use 2PC when we want different computers
to do different things.
We use Raft when we want to replicate the same
state over different machines.&lt;/p&gt;
&lt;h3 id=&quot;what-is-the-relationship-between-2pc%2C-3pc%2C-and-raft%3F&quot; tabindex=&quot;-1&quot;&gt;What is the relationship between 2PC, 3PC, and Raft?&lt;/h3&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The major events in the development of consensus protocols can be summarised below, in hugely oversimplified form:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Jim Gray (amongst others) proposes 2PC in the 1970s. Problem: blocks on failure of single node even in synchronous networks.&lt;/li&gt;
&lt;li&gt;Dale Skeen (amongst others) shows the need for an extra, third phase to avoid blocking in the early 1980s. 3PC is an obvious corollary, but it is not provably correct, and in fact suffers from incorrectness under certain network conditions.&lt;/li&gt;
&lt;li&gt;Leslie Lamport proposes Paxos, which is provably correct in asynchronous networks that eventually become synchronous, does not block if a majority of participants are available (so withstands &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;n/2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; faults) and has provably minimal message delays in the best case.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.the-paper-trail.org/post/2009-02-03-consensus-protocols-paxos/&quot;&gt;(source: the excellent Henry Robinson again)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FOLLOW-UP:&lt;/strong&gt; be clear about the difference between
synchronous and asynchronous networks&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FOLLOW-UP:&lt;/strong&gt; add a point number 4. talking about Raft&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;[TODO]&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Notes on CRDTs</title>
    <link href="https://lieuzhenghong.com/crdt_notes/"/>
    <updated>2021-02-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/crdt_notes/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#overview&quot;&gt;Overview&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#the-big-picture&quot;&gt;The big picture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#faq&quot;&gt;FAQ&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-the-purpose-of-the-compare-function%3F&quot;&gt;What&amp;#39;s the purpose of the compare function?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-least-upper-bound%3F&quot;&gt;What&amp;#39;s least upper bound?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-a-monotonic-join-semilattice%3F&quot;&gt;What&amp;#39;s a monotonic join semilattice?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-a-source-pre-condition%3F&quot;&gt;What&amp;#39;s a source pre-condition?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-a-causal-history%3F&quot;&gt;What&amp;#39;s a causal history?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#causal-history-op-based%3A&quot;&gt;Causal history op-based:&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-an-%22abstract-state%22%3F-how-does-it-differ-from-regular-state%3F&quot;&gt;What&amp;#39;s an &amp;quot;abstract state&amp;quot;? How does it differ from regular state?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#why-is-it-not-possible-to-maintain-a-global-invariant%3F&quot;&gt;Why is it not possible to maintain a global invariant?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-the-importance-of-this-paper%3A&quot;&gt;What&amp;#39;s the importance of this paper:&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what-makes-something-a-crdt%3F&quot;&gt;What makes something a CRDT?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-a-pn-set%3F-do-you-need-add-and-remove-counter-for-each-replica%3F&quot;&gt;What&amp;#39;s a PN-Set? Do you need add and remove counter for each replica?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#removing-stuff-is-hard-without-synchronisation&quot;&gt;Removing stuff is hard without synchronisation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#when-would-you-use-crdts-versus-a-more-traditional-synchronisation-solution%3F&quot;&gt;When would you use CRDTs versus a more traditional synchronisation solution?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what&#39;s-the-process-of-designing-or-building-a-new-crdt%3F&quot;&gt;What&amp;#39;s the process of designing or building a new CRDT?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#is-it-true-that-any-crdt-can-be-represented-as-both-state-based-and-op-based%3F-proof%3F&quot;&gt;Is it true that any CRDT can be represented as both state-based and op-based? Proof?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what-are-operational-transforms%3F&quot;&gt;What are operational transforms?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#what-is-quiescent-consistency%3F&quot;&gt;What is quiescent consistency?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/#further-reading&quot;&gt;Further reading&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This week I read
&lt;a href=&quot;https://files.lieu.gg/docs/Shapiro%20et%20al.%20(2011).%20A%20comprehensive%20study%20of%20Convergent%20and%20Commutative%20Replicated%20Data%20Types.pdf&quot;&gt;Shapiro et al. (2011). A comprehensive study of Convergent and Conflict-Free Replicated Data Types&lt;/a&gt;
as part of
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;overview&quot; tabindex=&quot;-1&quot;&gt;Overview&lt;/h2&gt;
&lt;h2 id=&quot;the-big-picture&quot; tabindex=&quot;-1&quot;&gt;The big picture&lt;/h2&gt;
&lt;p&gt;A lot of the literature in distributed systems tries to solve the problem of consistency,
which (roughly speaking) demands that all nodes must have the same state at every point in time.&lt;/p&gt;
&lt;p&gt;Consensus algorithms like 2PC and Raft ensure consistency by
guaranteeing that every transaction is either executed on all nodes, or not at all.
This ensures that each node will have the same transactions in the same order.
The idea is if every node starts from the same initial state,
and each node runs the same set of (deterministic) transactions in the same order,
then each node will have the same subsequent states.
So this is the approach to solving consistency.&lt;/p&gt;
&lt;p&gt;Of course we know from the famous
&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/&quot;&gt;CAP theorem&lt;/a&gt;
that we give up availability as a result.
We can try and get back availability
by relaxing consistency into &lt;em&gt;eventual consistency&lt;/em&gt;:
mandating that all nodes must have the same state
at &lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/dynamo_notes.md#what&#39;s-%22eventual-consistency%22%2C-and-what-are-some-advantages-and-disadvantages%3F-what&#39;s-a-specific-example-of-behaviour-that-could-happen-under-this-consistency-model%3F&quot;&gt;&lt;em&gt;some&lt;/em&gt; point in time&lt;/a&gt;.
This is the approach favoured by Amazon&#39;s &lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/&quot;&gt;DynamoDB&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But even relaxing consistency to allow eventual consistency
doesn&#39;t necessarily give us full availability.
The biggest problem is that nodes could reach a &amp;quot;broken&amp;quot; or
otherwise unrecoverable state if operations come in out of order.
A simple example is a stack: obviously the state of the stack
depends on the order of operations, and if the &lt;code&gt;pop&lt;/code&gt; operations
come before the &lt;code&gt;push&lt;/code&gt; operations you&#39;re broken.&lt;/p&gt;
&lt;p&gt;And even if our nodes never &amp;quot;break&amp;quot;, their histories can diverge
irreconcilably in a way that kind of breaks eventual consistency ---
&lt;a href=&quot;http://localhost:8080/dynamo_notes/#why-is-dynamo-only-eventually-consistent%3F-how-can-divergent-histories-form-even-with-a-3-2-2-quorum-setup%3F&quot;&gt;DynamoDB&lt;/a&gt; may be always writable (and thus fully available)
with &lt;code&gt;W = 1&lt;/code&gt;,
but it has to return a set of possible states rather than a single canonical one.
This is technically not eventual consistency, because obviously no
single-threaded execution (non-concurrent history) would ever result in
a set of states.&lt;/p&gt;
&lt;p&gt;Wouldn&#39;t it be nice if we had full availability &lt;em&gt;and&lt;/em&gt; (eventual) consistency?
That&#39;s the promise of CRDTs:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;replicas of any CRDT [eventually] converge to a common state that is
equivalent to some correct sequential execution.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The key contract of CRDTs is: as long as you design your data structure
in a specific way, it doesn&#39;t matter what network partitions you have,
it doesn&#39;t matter in which order operations are applied,
all nodes will eventually converge to the same state.&lt;/p&gt;
&lt;p&gt;How does it do this?
The idea is simple and genius.
Recall that the various definitions of consistency
are all about rearranging operations in some &lt;em&gt;concurrent&lt;/em&gt; history
(where calls can interleave)
into a valid &lt;em&gt;sequential&lt;/em&gt; history
(where each call must immediately be followed by its response),
subject to some other rules (follow process order, real-time order, etc.)&lt;/p&gt;
&lt;p&gt;And the tricky bit is that in many data structures,
the order of operations is important.
The operations are &lt;em&gt;not commutative&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If we have noncommutativity
then getting a valid sequential history may be tough
because you might violate an invariant.&lt;/p&gt;
&lt;p&gt;This presents the two problems I mentioned earlier:
firstly you must rearrange carefully so as not to violate the invariants of the object,
and secondly every node must rearrange its operations in the exact same way&lt;/p&gt;
&lt;p&gt;But of course, if your operations are commutative,
then any arrangement of method calls is perfectly fine!
No matter in what order you&lt;/p&gt;
&lt;p&gt;&lt;code&gt;set(1)&lt;/code&gt;
&lt;code&gt;set(3)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You can think of these things as existing in a consistency--availability
Cartesian space, where the impossibility theorems constrain
the possible spots in that space.
Raft and 2PC are in one region: they guarantee strong consistency,
but they&#39;re not available in the presence of partitions.
Amazon&#39;s Dynamo with N=3 is in the middle;
it (almost always) guarantees eventual consistency,
and is (almost always) available.
Dynamo with N=1 is further to the left:
it&#39;s always writable, but forks more easily.
And finally CRDTs are better than Dynamo with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N=1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
fully available, _and _ always eventually consistent.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot; tabindex=&quot;-1&quot;&gt;FAQ&lt;/h2&gt;
&lt;h3 id=&quot;what&#39;s-the-purpose-of-the-compare-function%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the purpose of the &lt;code&gt;compare&lt;/code&gt; function?&lt;/h3&gt;
&lt;p&gt;To map it to a monotonic join semilattice.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-least-upper-bound%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s least upper bound?&lt;/h3&gt;
&lt;h3 id=&quot;what&#39;s-a-monotonic-join-semilattice%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a monotonic join semilattice?&lt;/h3&gt;
&lt;p&gt;Monotonic: you can only move &amp;quot;up&amp;quot; state, or don&#39;t move at all&lt;/p&gt;
&lt;p&gt;a Join Semilattice is some ordered set
where a LUB must exit.
This ordered set is the set of all possible payload sate&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-a-source-pre-condition%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a source pre-condition?&lt;/h3&gt;
&lt;p&gt;It&#39;s a &amp;quot;guard statement&amp;quot; that causes the query or update function to fail
if a particular condition is not met.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-a-causal-history%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a causal history?&lt;/h3&gt;
&lt;p&gt;The causal history of an &lt;em&gt;object&lt;/em&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_i&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3117em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; a set of all &lt;em&gt;update&lt;/em&gt; operations applied to the object.&lt;/p&gt;
&lt;p&gt;The operation can contain the snapshot or&lt;/p&gt;
&lt;h3 id=&quot;causal-history-op-based%3A&quot; tabindex=&quot;-1&quot;&gt;Causal history op-based:&lt;/h3&gt;
&lt;p&gt;Downstream:
executes after the source-local phase immediately at the source and asynchronously at all other replicas &lt;em&gt;only if the downstream precondition is true&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-an-%22abstract-state%22%3F-how-does-it-differ-from-regular-state%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s an &amp;quot;abstract state&amp;quot;? How does it differ from regular state?&lt;/h3&gt;
&lt;p&gt;Merge is idempotent and commutative by the properties of... messages may be lost, received out of order, or multiple times.&lt;/p&gt;
&lt;h3 id=&quot;why-is-it-not-possible-to-maintain-a-global-invariant%3F&quot; tabindex=&quot;-1&quot;&gt;Why is it not possible to maintain a global invariant?&lt;/h3&gt;
&lt;p&gt;There is actually no non-negative counter.
You can only enforce local invariants by definition&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-the-importance-of-this-paper%3A&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the importance of this paper:&lt;/h3&gt;
&lt;p&gt;The importance is that &lt;em&gt;any&lt;/em&gt; data type that&lt;/p&gt;
&lt;h3 id=&quot;what-makes-something-a-crdt%3F&quot; tabindex=&quot;-1&quot;&gt;What makes something a CRDT?&lt;/h3&gt;
&lt;p&gt;Query and add&lt;/p&gt;
&lt;p&gt;&amp;quot;Only merge and compare must follow CRDT&amp;quot;&lt;/p&gt;
&lt;p&gt;All merges must be idempotent , commutative, and associative to be a state-based CRDT.&lt;/p&gt;
&lt;h3 id=&quot;what&#39;s-a-pn-set%3F-do-you-need-add-and-remove-counter-for-each-replica%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s a PN-Set? Do you need add and remove counter for each replica?&lt;/h3&gt;
&lt;p&gt;I think so.&lt;/p&gt;
&lt;h3 id=&quot;removing-stuff-is-hard-without-synchronisation&quot; tabindex=&quot;-1&quot;&gt;Removing stuff is hard without synchronisation&lt;/h3&gt;
&lt;h3 id=&quot;when-would-you-use-crdts-versus-a-more-traditional-synchronisation-solution%3F&quot; tabindex=&quot;-1&quot;&gt;When would you use CRDTs versus a more traditional synchronisation solution?&lt;/h3&gt;
&lt;h3 id=&quot;what&#39;s-the-process-of-designing-or-building-a-new-crdt%3F&quot; tabindex=&quot;-1&quot;&gt;What&#39;s the process of designing or building a new CRDT?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I&#39;ll start with some primitives, LWW sets&lt;/li&gt;
&lt;li&gt;Then compose higher level CRDTs on the primitives. E.g. 2P sets can be composed with grow-only sets.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;is-it-true-that-any-crdt-can-be-represented-as-both-state-based-and-op-based%3F-proof%3F&quot; tabindex=&quot;-1&quot;&gt;Is it true that any CRDT can be represented as both state-based and op-based? Proof?&lt;/h3&gt;
&lt;h3 id=&quot;what-are-operational-transforms%3F&quot; tabindex=&quot;-1&quot;&gt;What are operational transforms?&lt;/h3&gt;
&lt;h3 id=&quot;what-is-quiescent-consistency%3F&quot; tabindex=&quot;-1&quot;&gt;What is quiescent consistency?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Quiescent consistency requires non-overlapping operations to appear to take effect in their real-time order, but overlapping operations might be reordered.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;http://coldattic.info/post/88/&quot;&gt;Pavel Shved&#39;s 2012 post on &amp;quot;Consistency Models Explained Briefly&lt;/a&gt;
and &lt;a href=&quot;https://stackoverflow.com/questions/26089729/what-are-the-differences-between-sequential-consistency-and-quiescent-consistenc&quot;&gt;this SO post&lt;/a&gt;
are both very useful.
Pavel&#39;s post needs a bit of background, but if you have it, it is a great post.&lt;/p&gt;
&lt;h2 id=&quot;further-reading&quot; tabindex=&quot;-1&quot;&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Delta CRDTs: Almeida, Shoker, and Baquero&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.figma.com/blog/realtime-editing-of-ordered-sequences/&quot;&gt;Realtime Editing of Ordered Sequences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Stern-Brocot trees&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.kevinjahns.de/are-crdts-suitable-for-shared-editing/&quot;&gt;Jahns. Are CRDTs Suitable for Shared Editing?&lt;/a&gt;: CRDTs are complex, too much overhead&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/2006.10494.pdf&quot;&gt;Dolan, 2006. The Only Undoable CRDTs are Counters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;In comparing well-known CRDTs representing sets that can growand shrink, we find caveats. In one, the removal of an element can-not be reliably undone. In another, undesirable states are attainable,such as when an element is present -1 times (and so must be addedfor the set to become empty). The first lacks a general-purposeundo, while the second acts less like a set and more like a tuple ofcounters, one per possible element.Using some group theory, we show that this trade-off is unavoid-able:every undoable CRDT is a tuple of counters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://arxiv.org/pdf/1805.06358.pdf&quot;&gt;Preguica et al. (2018). Conflict-free Replicated Data Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://files.lieu.gg/docs/Shapiro%20et%20al.%20(2011).%20A%20comprehensive%20study%20of%20Convergent%20and%20Commutative%20Replicated%20Data%20Types.pdf&quot;&gt;Shapiro et al. (2011). A comprehensive study of Convergent and Conflict-Free Replicated Data Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/liaujianjie/crdt&quot;&gt;Jian Jie&#39;s CRDT repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/&quot;&gt;y.js library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/&quot;&gt;IPFS notes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>System design (and business case) for a EV charging station backend</title>
    <link href="https://lieuzhenghong.com/ev_charger_systems_design/"/>
    <updated>2021-02-13T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ev_charger_systems_design/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;h2 id=&quot;business-case&quot; tabindex=&quot;-1&quot;&gt;Business case&lt;/h2&gt;
&lt;p&gt;There are 600,000 private cars in Singapore.
Right now, 600 of them are (fully) electric.&lt;/p&gt;
&lt;p&gt;By 2030, the SG government wants to have 60,000 chargers installed island-wide.
Suppose there are 60,000 electric cars.
These electric cars need to be charged at chargers.
An average driver drives about 50km in a day.
That means 10kWh.
The business model has us charge 45c per kWh.
So that means that each charger makes about &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0.45&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;4.5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0.45 * 10 = \$4.5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.45&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$4.5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; of revenue.
Power from the grid costs &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;15&lt;/mn&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;15c&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; per kWh,
so that&#39;s &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; in profit per day.&lt;/p&gt;
&lt;p&gt;A Toyota Corolla Altis gets an average of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;15.4&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;15.4&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;15.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; kms per liter
&lt;a href=&quot;https://www.budgetdirect.com.sg/car-insurance/research/car-running-costs-singapore&quot;&gt;source&lt;/a&gt;.
At 50km, this is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3.25&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3.25&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3.25&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; liters of fuel per day,
which at a fuel cost of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;2.25&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$2.25/liter&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$2.25/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
equals &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3.25&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;2.25&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;7.30&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3.25 * \$2.25 = \$7.30/day&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3.25&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$2.25&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$7.30/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.
So the electric car driver saves almost 40% on fuel costs.&lt;/p&gt;
&lt;p&gt;Suppose there are 60,000 electric cars (10% market penetration)
and each of them gives us &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;4.50&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$4.50&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$4.50&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; of daily revenue,
then the total addressable market is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;000&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;4.50&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;365&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;98&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;550&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;000.00&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;60,000 * \$4.50 * 365 = \$98,550,000.00&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8389em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;000&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$4.50&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;365&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9444em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$98&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;000.00&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
or almost 100 million dollars in revenue per annum.&lt;/p&gt;
&lt;h2 id=&quot;meta-question%3A-when-is-it-better-to-build-your-own-v.-outsource-the-software-development%3F&quot; tabindex=&quot;-1&quot;&gt;Meta-question: when is it better to build your own v. outsource the software development?&lt;/h2&gt;
&lt;p&gt;Should ask Ben about this.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://plugit.fi/ratkaisu/&quot;&gt;PlugIT&lt;/a&gt;
(website in Finnish)
offers a SaaS that makes the backend easy.
It charges $21/month per charging station
with an additional fee per charging transaction.&lt;/p&gt;
&lt;p&gt;On the one hand, since PlugIT has already gone through all the hard work
to develop this software, we would certainly incur a very high fixed cost
to do the R&amp;amp;D in-house (especially if we&#39;re hiring top engineers,
which we will want to).&lt;/p&gt;
&lt;p&gt;On the other hand, in the long run building your own software would
make financial sense.
Suppose the company manages to install 4,000 chargers.
Then at 21 dollars per charging station per month that&#39;s
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;82&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;000&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$82,000&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9444em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$82&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; per month: enough to hire 5 or 6 full-time
excellent SWEs to develop the front- and back- end
and maintain it full-time.
At the time of its acquisition,
Instagram had 6 engineers supporting 30 million users,
Even with a 50% volume discount this would be &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;40&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;000&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$40,000&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9444em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$40&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; per month,
enough to support three full-time engineers.
I hear that PlugIT also takes a 1% extra transaction fee per transaction.
Assuming just one transaction per day per charging station,
that&#39;s &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;4.5&lt;/mn&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;4.5c&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;4.5&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; per transaction, which is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;0.045&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;4000&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;30&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;$&lt;/mi&gt;&lt;mn&gt;5400&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\$0.045 * 4000 * 30 = \$5400&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$0.045&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;4000&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;$5400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; per month.&lt;/p&gt;
&lt;p&gt;Also, an argument could be made that this is
critical software infrastructure that should not be outsourced.
Without the backend your company literally cannot make money
(cannot take payment). It might not be a good idea to be reliant
on a single company for all of your infra.&lt;/p&gt;
&lt;p&gt;There are also more nebulous advantages wrt owning your own data,
adding new features etc.
For instance, you might be able to use the charging data
to optimise charging patterns&lt;/p&gt;
&lt;p&gt;I think it all depends on how much scale the company has.
With only a few chargers it doesn&#39;t make financial sense to build
your own software, but it does when you do have 4,000 chargers.&lt;/p&gt;
&lt;h2 id=&quot;user-story&quot; tabindex=&quot;-1&quot;&gt;User story&lt;/h2&gt;
&lt;p&gt;The user first registers himself with the app and saves his credit card data.
Subsequently he can drive up to any of the charging stations,
press a button on the app to start charging, and plug the charger into the car.&lt;/p&gt;
&lt;p&gt;On the backend once we receive a charge request this backend
should send a &amp;quot;start charging&amp;quot; request to the charger
via the OCPP 2.0 protocol.
On the frontend the app will tell him how much energy he&#39;s used so far
(ideally also battery percentage) and the cost incurred.&lt;/p&gt;
&lt;p&gt;When the user finishes charging he again presses a button on the app
which sends a &amp;quot;stop charging&amp;quot; request to the charger,
which releases the safety lock and allows the user to unplug the charger
from the car. A payment transaction is created on the backend and the user
is charged appropriately.&lt;/p&gt;
&lt;h2 id=&quot;technical-detail&quot; tabindex=&quot;-1&quot;&gt;Technical detail&lt;/h2&gt;
&lt;p&gt;OCPP 2.0 protocol&lt;/p&gt;
&lt;h2 id=&quot;questions-to-ask&quot; tabindex=&quot;-1&quot;&gt;Questions to ask&lt;/h2&gt;
&lt;p&gt;Storing sensitive credit card data?&lt;/p&gt;
&lt;p&gt;Server can never go down otherwise you literally cannot take payments
and your business is dead in the water&lt;/p&gt;
&lt;p&gt;WHat happens if the server stops responding?
you must not have mechanical locks be software controlled&lt;/p&gt;
&lt;h2 id=&quot;what-comes-next&quot; tabindex=&quot;-1&quot;&gt;What comes next&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>What is a Golang interface?</title>
    <link href="https://lieuzhenghong.com/golang_interfaces/"/>
    <updated>2021-02-11T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/golang_interfaces/</id>
    <content type="html">&lt;p&gt;Thanks to Liang Jun for this.&lt;/p&gt;
&lt;h2 id=&quot;question&quot; tabindex=&quot;-1&quot;&gt;Question&lt;/h2&gt;
&lt;p&gt;What does the line&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; Something &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    a &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;actually mean? What is this &lt;code&gt;interface&lt;/code&gt; thingy, anyway?&lt;/p&gt;
&lt;h2 id=&quot;explanation&quot; tabindex=&quot;-1&quot;&gt;Explanation&lt;/h2&gt;
&lt;p&gt;Say you have a program that reads and writes to a database. Your program is passed a InMemoryStore object that contains the functions read() and write(). The database object now could be an in-memory store, but maybe in future you want to make it a persistent store? It would be troublesome if we had to edit the way our program calls the database&lt;/p&gt;
&lt;p&gt;This is where interfaces come in - we define Database as an interface that contains read() and write():&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; Database&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token function&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of having our program directly operate on the InMemoryStore object, we make InMemoryStore implement the interface Database:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; InMemoryStore &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// implements Database &lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And have our program operate on the Database interface.&lt;/p&gt;
&lt;p&gt;This means that in the future, if we want to swap the in-memory store to a persistent database, we just need to implement the persistent database to conform to the Database interface:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; PersistentDB &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// implements Database &lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the beauty of this is that our program doesn&#39;t need to be changed, we just need to pass a PersistentDB instead of an InMemoryStore to it.&lt;/p&gt;
&lt;h3 id=&quot;interfaces-as-multiple-inheritance&quot; tabindex=&quot;-1&quot;&gt;Interfaces as multiple inheritance&lt;/h3&gt;
&lt;p&gt;Interfaces can also be used to implement something like multiple inheritance:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; WithdrawalMachine&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; DepositMachine &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;deposit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; ATM &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// implements WithdrawalMachine, DepositMachine &lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;withdraw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;deposit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;so-what&#39;s-%5B%5Dinterface%7B%7D-then%3F%3F&quot; tabindex=&quot;-1&quot;&gt;So what&#39;s []interface{} then??&lt;/h3&gt;
&lt;p&gt;In Golang, an object is considered to implicitly implement an interface
if it implements all the methods of that interface.
So let&#39;s say I have an interface and a struct:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; MyInterface &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; MyStruct &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;Z&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because MyStruct implements all functions in MyInterface, Golang sees MyStruct as implementing MyInterface despite it never being explicitly declared anywhere.&lt;/p&gt;
&lt;p&gt;Now consider the empty interface:&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All structs in Golang implement it by default, since all structs implement &amp;quot;all&amp;quot; of its (zero) functions.&lt;/p&gt;
&lt;p&gt;And therefore, a list of empty interfaces []interface{} basically means a list of &lt;code&gt;Any&lt;/code&gt; objects.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>What is the CAP theorem really about?</title>
    <link href="https://lieuzhenghong.com/cap_theorem/"/>
    <updated>2021-02-11T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/cap_theorem/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#the-cap-theorem-is-not-%22pick-two-out-of-three%22!&quot;&gt;The CAP theorem is NOT &amp;quot;pick two out of three&amp;quot;!&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#consistency%3A-what-%22consistency%22-is-is-actually-super-nontrivial&quot;&gt;Consistency: What &amp;quot;consistency&amp;quot; is is actually super nontrivial&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#availability%3A-thankfully-easier-to-define&quot;&gt;Availability: thankfully easier to define&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#partition-tolerance%3A-you-need-to-define-partition-tolerance-with-respect-to-something&quot;&gt;Partition-tolerance: You need to define partition-tolerance with respect to something&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#putting-it-all-together%3A-stating-the-cap-theorem-properly&quot;&gt;Putting it all together: stating the CAP theorem properly&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#partition-tolerance-is-not-fault-tolerance!&quot;&gt;Partition-tolerance is NOT fault-tolerance!&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#references&quot;&gt;References&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#appendix-a%3A-linearisability&quot;&gt;Appendix A: linearisability&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The NUS folks and I were discussing
&lt;a href=&quot;https://lieuzhenghong.com/spinnaker_notes/&quot;&gt;the Spinnaker paper&lt;/a&gt;
while doing
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;MIT&#39;s distributed systems course&lt;/a&gt;.
We realised that we kept going around in circles
talking about Spinnaker&#39;s guarantees:
apparently DynamoDB is an &amp;quot;AP&amp;quot; system,
but Spinnaker is a &amp;quot;CA&amp;quot; system?
Is that right?
What is a &amp;quot;CA&amp;quot; system? Can such a system exist?
What does &amp;quot;partition tolerance&amp;quot; even mean?&lt;/p&gt;
&lt;p&gt;The discussion got hopelessly muddled because
we didn&#39;t really understand what the CAP theorem
was really about. After very helpful discussions
with Liang Jun, Julius and Wei Neng,
I&#39;m writing this post to (try to)
shed some light on the topic,
and dispel some common misconceptions I heard
(and previously held!) during the discussion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT 2021-02-16:&lt;/strong&gt;
I just came across
&lt;a href=&quot;https://www.the-paper-trail.org/page/cap-faq/&quot;&gt;this wonderful CAP FAQ on the-paper-trial.org&lt;/a&gt;
which has basically written everything I have here,
but better! &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;
I wish I had stumbled across this earlier.
But I&#39;m happy that what I have written here is
correct and vindicated by this FAQ.&lt;/p&gt;
&lt;h2 id=&quot;the-cap-theorem-is-not-%22pick-two-out-of-three%22!&quot; tabindex=&quot;-1&quot;&gt;The CAP theorem is NOT &amp;quot;pick two out of three&amp;quot;!&lt;/h2&gt;
&lt;p&gt;One common mis-definition of CAP is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can only pick two out of consistency, availability,
and partition tolerance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This implies that there are &amp;quot;CA&amp;quot; systems, &amp;quot;CP&amp;quot; systems,
and &amp;quot;AP systems&amp;quot;.
In fact, this couldn&#39;t be further from the truth.
As a system designer you can&#39;t choose not to be partition-tolerant.
Rather, almost all systems are (or can easily be) CA
in the &lt;em&gt;absence&lt;/em&gt; of partitions,
and systems &lt;em&gt;must&lt;/em&gt; choose to give up either C (Dynamo, Cassandra)
&lt;em&gt;or&lt;/em&gt; A (Spinnaker) in the presence of P.
More on this later, but first, some definitions:&lt;/p&gt;
&lt;h3 id=&quot;consistency%3A-what-%22consistency%22-is-is-actually-super-nontrivial&quot; tabindex=&quot;-1&quot;&gt;Consistency: What &amp;quot;consistency&amp;quot; is is actually super nontrivial&lt;/h3&gt;
&lt;p&gt;I often hear consistency defined as &amp;quot;a system is consistent if
any request received by the system returns either the correct result
or an error.&amp;quot; But what is the &amp;quot;correct&amp;quot; result?
It&#39;s too handwavy for my taste.
Upon reading up more, I learned that there&#39;s
&lt;em&gt;strong consistency&lt;/em&gt;, &lt;em&gt;linearisable consistency&lt;/em&gt;,
&lt;em&gt;timeline consistency&lt;/em&gt;, &lt;em&gt;eventual consistency&lt;/em&gt;,
and who knows what else.&lt;/p&gt;
&lt;p&gt;I like the following two more formal treatments of consistency
that show that there&#39;s actually a &lt;em&gt;universe&lt;/em&gt; of consistencies.
&lt;a href=&quot;https://jepsen.io/consistency&quot;&gt;Jepsen&lt;/a&gt;
has a clickable map and excellent definitions and
&lt;a href=&quot;https://aphyr.com/posts/313-strong-consistency-models&quot;&gt;Aphyr&lt;/a&gt;
has a very readable treatment of the matter.&lt;/p&gt;
&lt;p&gt;So which version of consistency do we want?
The CAP theorem actually means &lt;em&gt;linearisable consistency&lt;/em&gt;,
or &lt;em&gt;linearisability&lt;/em&gt;.
This is quite a strong definition of consistency
(and in fact it&#39;s often called &amp;quot;strong consistency&amp;quot;).
The usual definition of linearisability is stated as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Linearisable Consistency&lt;/em&gt;:
A system is linearisable if all operations appear to take place
atomically in an order consistent with the real-time ordering of
those operations:
e.g., if operation A completes before operation B begins,
then B should logically take effect after A.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The real definition given by
&lt;a href=&quot;http://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf&quot;&gt;Herlihy and Wing (1990)&lt;/a&gt;
is a tad more complicated. I&#39;ll go through it in the appendix.&lt;/p&gt;
&lt;h3 id=&quot;availability%3A-thankfully-easier-to-define&quot; tabindex=&quot;-1&quot;&gt;Availability: thankfully easier to define&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Availability&lt;/em&gt;: A system is available if
every request received by a &lt;em&gt;non-failing node&lt;/em&gt; in the system
results in a response.&lt;/p&gt;
&lt;p&gt;Note here &amp;quot;&lt;em&gt;non-failing&lt;/em&gt; node!&amp;quot; This is key.
We&#39;ll use this later.&lt;/p&gt;
&lt;h3 id=&quot;partition-tolerance%3A-you-need-to-define-partition-tolerance-with-respect-to-something&quot; tabindex=&quot;-1&quot;&gt;Partition-tolerance: You need to define partition-tolerance with respect to something&lt;/h3&gt;
&lt;p&gt;A system must be partition-tolerant with respect to consistency
or availability---it can&#39;t be just &amp;quot;partition-tolerant&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Partition Tolerance&lt;/em&gt;:
A system is part
ition-tolerant with respect to X
if {condition for X} still holds
when the set of nodes are
split into any number of disjoint subsets
that cannot communicate with any elements
outside that subset.&lt;/p&gt;
&lt;p&gt;Closely related, but not identical, is the notion of &lt;em&gt;fault-tolerance&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Fault Tolerance&lt;/em&gt;: A system is fault-tolerant
with respect to X up to F failures
if {condition for X} still holds
when any of F nodes fail.&lt;/p&gt;
&lt;h3 id=&quot;putting-it-all-together%3A-stating-the-cap-theorem-properly&quot; tabindex=&quot;-1&quot;&gt;Putting it all together: stating the CAP theorem properly&lt;/h3&gt;
&lt;p&gt;Almost all systems are CA in the absence of partitions or failures.
We should therefore only talk about the CAP theorem
&lt;em&gt;in the presence of faults or network partitions&lt;/em&gt;.
More precisely, when you have a network partition,
you can only have one of linearisability (consistency)
or availability.&lt;/p&gt;
&lt;p&gt;Here&#39;s aphyr again:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Providing consistency and availability when the network is reliable is easy.
Providing both when the network is not reliable is provably impossible. If
your network is not perfectly reliable–and it isn’t–you cannot choose CA. This
means that all practical distributed systems on commodity hardware can
guarantee, at maximum, either AP or CP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Paxos/Spinnaker/Raft are C in the presence of partitions,
CA when the number of failing servers is less than half,
and C when the number of failing servers is more than half.&lt;/p&gt;
&lt;p&gt;More interestingly, because consistency is a spectrum (ish),
as you start weakening the definition of consistency,
you will eventually get availability AND &amp;quot;consistency&amp;quot;
for some sufficiently weak definition of consistency.&lt;/p&gt;
&lt;p&gt;Here&#39;s a nice map of the CAP theorem for different definitions of C.
The ones shaded in red cannot be fully available:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://aphyr.com/data/posts/313/family-tree.jpg&quot; alt=&quot;family tree of consistency models&quot;&gt;&lt;/p&gt;
&lt;p&gt;The nicer version is available at
&lt;a href=&quot;https://jepsen.io/consistency&quot;&gt;the Jepsen website.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;partition-tolerance-is-not-fault-tolerance!&quot; tabindex=&quot;-1&quot;&gt;Partition-tolerance is NOT fault-tolerance!&lt;/h2&gt;
&lt;p&gt;Something I kept hearing during the discussions
is that &amp;quot;network partitions are basically like node failures&amp;quot;.
That&#39;s not quite true!
It is kind of true in a practical sense that
if a node stops receiving and sending messages
to the rest of the cluster
because it&#39;s behind a network partition,
that node might as well be failing.&lt;/p&gt;
&lt;p&gt;But it does matter for the finicky definition
of the CAP theorem, because availability
is about queries on &lt;em&gt;non-failing&lt;/em&gt; nodes.
A node can be behind a network partition
but not be failing, in which case that
node has to return a value to be available
(provided it can be reached by the client).
Coda Hale made this mistake
in his post
&lt;a href=&quot;https://codahale.com/you-cant-sacrifice-partition-tolerance/&quot;&gt;&lt;em&gt;You Can&#39;t Sacrifice Partition Tolerance.&lt;/em&gt;&lt;/a&gt;,
and made a correction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;... Therefore, considering a node
failure as a partition results in an &lt;strong&gt;obviously inappropriate CAP theorem
conclusion&lt;/strong&gt; [emphasis mine].&lt;/p&gt;
&lt;p&gt;He is correct: a dead (or wholly partitioned) node can receive no requests,
and so the other nodes can easily compensate without compromising consistency
or availability here. My error lies in forgetting that Gilbert and Lynch’s
formulation of availability requires only non-failing nodes to respond, and
that without ≥1 live nodes in a partition there isn’t the option for
split-brain syndrome. I regret the error and thank both him and Dr. Brewer for
pointing this out&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Furthermore, there&#39;s a sense in which partition-tolerance
is a stronger condition than fault-tolerance.
If a system is partition-tolerant with respect to availability
it is also fault-tolerant with respect to availability,
but the reverse is not true.
Systems like Raft or Paxos are fault-tolerant
(with respect to availability),
but not partition-tolerant, because that&#39;s literally impossible.
Here&#39;s a rough sketch of a proof:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claim&lt;/em&gt;: if a system is partition-tolerant
with respect to availability,
it is also fault-tolerant
with respect to availability,&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Proof&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;Consider a partition where
any F nodes are in individual disjoint subsets of size 1
and all other nodes are in another subset:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\{\{x_1\}, \{x_2\}, ... \{x_f\}, \{x_{f+1}, ... x_N\}\}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0361em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Since the system is partition-tolerant
with respect to availability,
every request received by any node
in any subset results in a response.
&lt;em&gt;A fortiori&lt;/em&gt;, every request received by
any node in the subset &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\{x_{f+1} ... x_N\}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0361em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
results in a response.&lt;/p&gt;
&lt;p&gt;Now consider if nodes &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; through &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_f&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7167em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; fail.
The system is available if
every request received by any &lt;em&gt;non-failing&lt;/em&gt; node
results in a response.
Therefore, the system is available if
every request received by any
node &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_{f+1}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7167em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; through &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_{N}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; results in a response.
But we know that every request received by
any node in the subset &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msub&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\{x_{f+1} ... x_N\}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0361em;vertical-align:-0.2861em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2861em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
results in a response.
Therefore, the system is still available
despite the failure of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;F&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;F&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;F&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; nodes. &lt;em&gt;QED&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Note that the converse is not true!
Counterexample: Paxos/Raft are fault-tolerant
with respect to availability up to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N/2 - 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/2&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; node failures.
But if one node is in its own partition with the client
and you query that node,
it will never be able to get quorum and will
not return you a result--hence, it&#39;s not partition-tolerant.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;TBD&lt;/p&gt;
&lt;h2 id=&quot;references&quot; tabindex=&quot;-1&quot;&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Coda Hale (2010).
&lt;a href=&quot;https://codahale.com/you-cant-sacrifice-partition-tolerance/&quot;&gt;&lt;em&gt;You Can&#39;t Sacrifice Partition Tolerance.&lt;/em&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf&quot;&gt;Herlihy and Wing (1990). Linearizability: A Correctness Condition for Concurrent Objects&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Jepsen (2018)
&lt;a href=&quot;https://jepsen.io/consistency&quot;&gt;Consistency Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Kyle Kingsbury, a.k.a Aphyr (2014).
&lt;a href=&quot;https://aphyr.com/posts/313-strong-consistency-models&quot;&gt;Strong consistency models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Robinson (2013), on The Paper Trail. &lt;a href=&quot;https://www.the-paper-trail.org/page/cap-faq/&quot;&gt;&lt;em&gt;The CAP FAQ&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;appendix-a%3A-linearisability&quot; tabindex=&quot;-1&quot;&gt;Appendix A: linearisability&lt;/h2&gt;
&lt;p&gt;Linearisability comes from the
&lt;a href=&quot;http://cs.brown.edu/~mph/HerlihyW90/p463-herlihy.pdf&quot;&gt;Herlihy and Wing (1990)&lt;/a&gt; paper.
This is my attempt at explaining it simply because there&#39;s lots of notation,
and my God do they do a bad job of explaining simply.&lt;/p&gt;
&lt;p&gt;Linearisability is fundamentally about a history.
We&#39;ll see how we will be able to expand this to objects and systems later.
But what is a history? Let&#39;s use an example to demonstrate.&lt;/p&gt;
&lt;p&gt;Suppose we have a queue object called &lt;code&gt;r&lt;/code&gt;
(why not call it &lt;code&gt;q&lt;/code&gt;? Cause I&#39;m gangsta that way).
The queue object supports the operation
&lt;code&gt;enqueue x&lt;/code&gt;, which enqueues some value &lt;code&gt;x&lt;/code&gt;, and
&lt;code&gt;dequeue&lt;/code&gt;, which returns the first object in the queue.&lt;/p&gt;
&lt;p&gt;Most importantly, because we&#39;re talking about concurrency,
there can be different processes calling functions
on the same object.
We use the notation &lt;code&gt;r (Enq(x), B)&lt;/code&gt; to denote
process &lt;code&gt;B&lt;/code&gt; calling &lt;code&gt;enqueue&lt;/code&gt; with the argument &lt;code&gt;x&lt;/code&gt;
on the object &lt;code&gt;r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now these operations take time.
We can split it up into two parts:
the time when you &lt;code&gt;call&lt;/code&gt; the function
(enqueue or dequeue), and the time when you receive a response.
Let&#39;s use the notation &lt;code&gt;r (OK(x), A)&lt;/code&gt; to denote
process &lt;code&gt;A&lt;/code&gt; receiving a response to its latest
function call with the result &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, a history is basically a log of all these operations,
in time-ascending order (earliest first).
Let&#39;s use an example to illustrate.
Suppose processes A and B concurrently enqueue two values.
While process A started first,
process B&#39;s call ran quicker and returned earlier.
Then the history would look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(x), A)   // process A starts calling first...
r (Enq(x), B)
r (OK, B)       // but process B gets a response first!
r (OK, A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So that&#39;s a history.
In particular, this is a &lt;em&gt;concurrent&lt;/em&gt; history,
because we can have function calls returning out-of-order:
an earlier call might get a response after a later call.
This is in contrast with a &lt;em&gt;sequential&lt;/em&gt; history,
where every call must immediately be followed by its matching response.&lt;/p&gt;
&lt;p&gt;With those definitions down,
we can then define linearisability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linearisability&lt;/strong&gt;:
An concurrent history is &lt;em&gt;linearisable&lt;/em&gt;
if you can rearrange it into a &lt;em&gt;sequential&lt;/em&gt; history
while following the following rules:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You must not violate the invariants of the object
(e.g. a queue is FIFO, a stack is LIFO, etc.)&lt;/li&gt;
&lt;li&gt;You must respect &lt;em&gt;real-time ordering&lt;/em&gt;:
If in the concurrent history you have &lt;code&gt;Response_1&lt;/code&gt; return
before &lt;code&gt;Call_2&lt;/code&gt;, you may never move &lt;code&gt;Call_2-Response_2&lt;/code&gt;
before &lt;code&gt;Call_1-Response_1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s an example. The following history is linearisable,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(x), B)
r (Enq(y), A)
r (OK, A)
r (OK, B)
r (Deq(), A)
r (Deq(), B)
r (OK(y), B)
r (OK(x), A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;because it can be rearranged into the following sequential ordering:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(x), A)
r (OK, A)
r (Enq(y), B)
r (OK, B)
r (Deq(), A)
r (OK(x), A)
r (Deq(), B)
r (OK(y), B)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, the following history is &lt;strong&gt;not&lt;/strong&gt; linearisable,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(x), A)
r (OK, A)
r (Enq(y), B)
r (Deq(), A)
r (OK, B)
r (OK(y), A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;because the only sequential reordering breaks one of the rules.
If you moved forward &lt;code&gt;r (OK, B)&lt;/code&gt;
(the only possible rearrangement)
you&#39;d get the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(x), A)
r (OK, A)
r (Enq(y), B)
r (OK, B)
r (Deq(), A)
r (OK(y), A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But here &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is enqueued first, but &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;y&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is dequeued first,
which violates the FIFO principle.&lt;/p&gt;
&lt;p&gt;Note that if you didn&#39;t have rule number 2
(that rearrangements must follow the time ordering)
you &lt;em&gt;could&lt;/em&gt; get a valid history:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;r (Enq(y), B)
r (OK, B)
r (Enq(x), A)
r (OK, A)
r (Deq(), A)
r (OK(y), A)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;s&gt;And in fact this is Lamport&#39;s &lt;em&gt;sequential consistency&lt;/em&gt;:
a concurrent history is sequentially consistent
if you can rearrange it any-which-way to get a consistent
sequential history.&lt;/s&gt;
(&lt;strong&gt;EDIT:&lt;/strong&gt; this is actually &lt;em&gt;serialisability&lt;/em&gt;, not sequential
consistency. Serialisability allows you to arrange it any-which-way:
sequential consistency allows you to rearrange it provided you follow
a time order within a process.
Linearisability needs you to follow a time order &lt;em&gt;between&lt;/em&gt; all processes.
Thanks to Julius and Zongran for pointing this out!)
But this rearrangement is not allowed under linearisability
because in the concurrent history
&lt;code&gt;r (OK, A)&lt;/code&gt; happened before &lt;code&gt;r (Enq(y), B)&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;So what does this have to do with distributed systems
and consistency?&lt;/p&gt;
&lt;p&gt;The idea here is that a distributed system is made up of objects.
Herlihy and Wing show that a system is linearisable
(ergo &amp;quot;strongly consistent&amp;quot;)
if all its objects are linearisable.&lt;/p&gt;
&lt;p&gt;But we&#39;ve been talking about histories. how can objects be linearisable?
Herlihy and Wing just whack definitions:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A set S of histories is prefix-closed if whenever H is in S,
every prefix of H is also in S.
A single-object history is one in which all events are associated
with the same object.
A sequential specification for an object is a prefix-closed set
of single-object sequential histories for that object.
...
A linearisable object is one whose concurrent histories are linearisable
with respect to some sequential specification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Eureka! Or maybe not, if you&#39;re not mega big brain.
Let me try to unpack this in normal-people-speak without all the definitions.&lt;/p&gt;
&lt;p&gt;Consider all the possible &amp;quot;valid&amp;quot; sequential histories of an object
(that is, histories that don&#39;t break the invariants of the object, like
popping a value before it&#39;s pushed, or dequeuing a value that wasn&#39;t first in).
This set is technically finite since histories must be of bounded length,
and you can&#39;t push unbounded values (maybe the max value is uint256 or whatever).&lt;/p&gt;
&lt;p&gt;Basically, an object is linearisable if
any valid concurrent history (a concurrent history that could actually happen)
can be rearranged (following the rules) into a valid sequential history.
So a queue is not linearisable,
because we&#39;ve just constructed examples
of valid concurrent histories that are not linearisable.
But a mutex would be linearisable, for instance.&lt;/p&gt;
&lt;p&gt;So there we have it: the formal definition of linearisability.
The worst thing is that it&#39;s not really helpful,
because it&#39;s much easier to reason with the entirely equivalent
&amp;quot;atomic&amp;quot; definition.
But I hope it was interesting all the same.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I believe I explain linearisability better: I don&#39;t really get his explanation about &amp;quot;external communication being respected&amp;quot;. &lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Rao, Shekita and Tata (2011). Using Paxos to Build a Scalable, Consistent, and Highly Available Datastore [Spinnaker]</title>
    <link href="https://lieuzhenghong.com/spinnaker_notes/"/>
    <updated>2021-02-08T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/spinnaker_notes/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;h2 id=&quot;overview-of-the-paper&quot; tabindex=&quot;-1&quot;&gt;Overview of the paper&lt;/h2&gt;
&lt;p&gt;Partitioning and load balancing&lt;/p&gt;
&lt;p&gt;Two-way replication doesn&#39;t work.
Three-way replication works, but more complicated failures become possible.
The Paxos familiy of protocols is widely considered to be the only proven solution
when there are 3 or more replicas.
Paxos solves the general problem of reaching consensus on the state of 2F+1
replicas while tolerating up to F failures.&lt;/p&gt;
&lt;p&gt;Idea: three nodes replicate keys of a particular&lt;/p&gt;
&lt;p&gt;A cohort of a key range &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;j&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;[i, j]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0572em;&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the set of nodes that contains its key range.
So the cohort of the key range &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;199&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;[0,199]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;199&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the set &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;{A, B, C}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Each node in Spinnaker contains several components.
All components are thread safe.&lt;/p&gt;
&lt;p&gt;There&#39;s a shared write-ahead log (shared amongst),
each log record is uniquely identified with an LSN.
Each cohort on a node uses its own &lt;em&gt;logical LSNs&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;commit queue&lt;/em&gt; is a main-memory data structure that is used to track
pending writes. Writes are committed only after receiving a sufficient
number of acks from a cohort.&lt;/p&gt;
&lt;p&gt;Committed writes are placed in a &lt;em&gt;memtable&lt;/em&gt;, which is sorted and flushed
to an immutable disk structure called an &lt;em&gt;SSTable&lt;/em&gt;. (Sorted String table)&lt;/p&gt;
&lt;h3 id=&quot;what-is-a-write-ahead-log%3F&quot; tabindex=&quot;-1&quot;&gt;What is a write-ahead log?&lt;/h3&gt;
&lt;p&gt;Write-ahead log: before you perform an action,
you save it to disk first&lt;/p&gt;
&lt;p&gt;MemTable has the most recent state,
we want to restore the state inside the memtable.&lt;/p&gt;
&lt;h3 id=&quot;how-does-sstable-work%3F&quot; tabindex=&quot;-1&quot;&gt;How does SSTable work?&lt;/h3&gt;
&lt;p&gt;If it&#39;s immutable, how is there a&lt;/p&gt;
&lt;h3 id=&quot;what-is-zookeeper%3F&quot; tabindex=&quot;-1&quot;&gt;What is Zookeeper?&lt;/h3&gt;
&lt;p&gt;Zookeeper is a &amp;quot;fault toleratnt, distributed coordination service&amp;quot;.&lt;/p&gt;
&lt;p&gt;The only messages exchanged between Zookeeper and a Spinnaker node are heartbeats.&lt;/p&gt;
&lt;h3 id=&quot;why-don&#39;t-we-use-zookeeper-for-the-entirety-of-spinnaker%3F&quot; tabindex=&quot;-1&quot;&gt;Why don&#39;t we use Zookeeper for the entirety of Spinnaker?&lt;/h3&gt;
&lt;h2 id=&quot;what-is-the-difference-between-strong-consistency%2C-eventual-consistency%2C-and-timeline-consistency%3F&quot; tabindex=&quot;-1&quot;&gt;What is the difference between strong consistency, eventual consistency, and timeline consistency?&lt;/h2&gt;
&lt;h2 id=&quot;strong-consistency-vs-eventual-consistency&quot; tabindex=&quot;-1&quot;&gt;Strong consistency vs eventual consistency&lt;/h2&gt;
&lt;p&gt;Strong consistency guarantees that all replicas available identical to applications.&lt;/p&gt;
&lt;p&gt;Partition-tolerance:&lt;/p&gt;
&lt;p&gt;Dynamo uses &lt;em&gt;eventual consistency&lt;/em&gt; to provide high availability and partition tolerance.
Dynamo is AP, so applications may see multiple versions of the same data.&lt;/p&gt;
&lt;p&gt;Spinnaker is CA.&lt;/p&gt;
&lt;p&gt;Spinnaker uses the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;key based range partitioning,&lt;/li&gt;
&lt;li&gt;3 way replication,&lt;/li&gt;
&lt;li&gt;transactional get-put API with the option to choose either
strong or time-line consistency on reads.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not robust to network partition.
It assumes that you will run it on a single datacenter
where network partitions are rare.&lt;/p&gt;
&lt;p&gt;&amp;quot;A data partition will be available for reads and writes
as long as a majority of the nodes containing its replicas
are alive.&amp;quot;&lt;/p&gt;
&lt;p&gt;Bigtable is CP apparently.&lt;/p&gt;
&lt;h3 id=&quot;optimistic-concurrency-control&quot; tabindex=&quot;-1&quot;&gt;Optimistic concurrency control&lt;/h3&gt;
&lt;p&gt;OCC: the idea that data races are unlikely.
You allow
Assumption: low data contention.&lt;/p&gt;
&lt;p&gt;To increment a counter &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;c&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;c = get(key, &amp;quot;c&amp;quot;, consistent = true)
ret = conditionalPut(key, &amp;quot;c&amp;quot;, c.value+1, c.version)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and this would fail if the &lt;code&gt;c.version&lt;/code&gt; is not equal the later version.&lt;/p&gt;
&lt;h3 id=&quot;two-phase-commit&quot; tabindex=&quot;-1&quot;&gt;Two-phase commit&lt;/h3&gt;
&lt;p&gt;A type of atomic protocol:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Commit-request phase (or voting phaes)&lt;/li&gt;
&lt;li&gt;If all vote yes, then commit.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Two phase commit is overkill because if one node fails, we get an abort:
not fault-tolerant.&lt;/p&gt;
&lt;p&gt;2PC blocks when the coordinator fails.&lt;/p&gt;
&lt;h2 id=&quot;replication-protocol&quot; tabindex=&quot;-1&quot;&gt;Replication protocol&lt;/h2&gt;
&lt;p&gt;Two phases (in Paxos): leader election, then quorum.&lt;/p&gt;
&lt;p&gt;When a client submits a write W.&lt;/p&gt;
&lt;p&gt;when a leader gets an act from at least one follower,
(so it has a majority 2/3),
it &lt;em&gt;commits&lt;/em&gt; W and writes to MemTable.&lt;/p&gt;
&lt;p&gt;Periodically the leader sends an async commit meesage
asking them to apply all pending writes up to a certain LSN
to their memtable, effectively committing those writes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key guarantee:&lt;/strong&gt; Anything written to the MemTable is guaranteed not to be lost.&lt;/p&gt;
&lt;h3 id=&quot;strong-consistency-vs-timeline-consistency&quot; tabindex=&quot;-1&quot;&gt;Strong consistency vs timeline consistency&lt;/h3&gt;
&lt;p&gt;Strongly consistent reads are always routed to the cohort&#39;s leader,
so they are guaranteed to see the latest value for W.
However, timeline consistent reads are routed to any node in the cohort,
so they may see a stale value for W.&lt;/p&gt;
&lt;h2 id=&quot;why-is-spinnaker-not-partition-tolerant%3F&quot; tabindex=&quot;-1&quot;&gt;Why is Spinnaker not partition-tolerant?&lt;/h2&gt;
&lt;h2 id=&quot;where-is-the-leader-info-stored%3F&quot; tabindex=&quot;-1&quot;&gt;Where is the leader info stored?&lt;/h2&gt;
&lt;h2 id=&quot;how-do-we-ensure-that-all-committed-writes-are-saved%3F&quot; tabindex=&quot;-1&quot;&gt;How do we ensure that all committed writes are saved?&lt;/h2&gt;
&lt;h2 id=&quot;leader-election&quot; tabindex=&quot;-1&quot;&gt;Leader election&lt;/h2&gt;
&lt;p&gt;Done on per-cohort basis, shared data in Zookeeper client&lt;/p&gt;
&lt;p&gt;Two guarantees:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Will give a result&lt;/li&gt;
&lt;li&gt;No committed writes are lost&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;how-do-we-know-when-the-leader-is-down%3F&quot; tabindex=&quot;-1&quot;&gt;How do we know when the leader is down?&lt;/h3&gt;
&lt;p&gt;Zookeeper keep-alive by heartbeat.
&amp;quot;Ephemeral znode&amp;quot; of /r/leader will be deleted&lt;/p&gt;
&lt;h3 id=&quot;how-does-the-leader-election-in-zookeeper-differ-from-the-leader-election-in-raft%3F&quot; tabindex=&quot;-1&quot;&gt;How does the leader election in Zookeeper differ from the leader election in Raft?&lt;/h3&gt;
&lt;p&gt;A cohort will not lose committed data even if 2 out of its 3 nodes permanently fail.&lt;/p&gt;
&lt;h3 id=&quot;what-is-partition-tolerance-really-about%3F&quot; tabindex=&quot;-1&quot;&gt;What is partition tolerance really about?&lt;/h3&gt;
&lt;p&gt;Is a majority of nodes failing an availability thing or a network partition thing?&lt;/p&gt;
&lt;h3 id=&quot;what-is-availability%3F&quot; tabindex=&quot;-1&quot;&gt;What is availability?&lt;/h3&gt;
&lt;p&gt;Every request received by a non-failing node in the system
must result in a response.&lt;/p&gt;
&lt;h3 id=&quot;which-part-of&quot; tabindex=&quot;-1&quot;&gt;Which part of&lt;/h3&gt;
&lt;h3 id=&quot;is-zookeeper-a-ca-system%3F-why-don&#39;t-you-use-zookeeper-as-the-data-store%3F&quot; tabindex=&quot;-1&quot;&gt;Is Zookeeper a CA system? Why don&#39;t you use Zookeeper as the data store?&lt;/h3&gt;
&lt;p&gt;What are the guarantees of Zookeeper?&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Ongaro and Ousterhout (2014). In Search of an Understandable Consensus Algorithm [Raft]</title>
    <link href="https://lieuzhenghong.com/raft_notes/"/>
    <updated>2021-02-05T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/raft_notes/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This is the famous Raft (extended) paper,
and here are my notes on it.&lt;/p&gt;
&lt;p&gt;I read this paper as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;overview-of-the-paper&quot; tabindex=&quot;-1&quot;&gt;Overview of the paper&lt;/h2&gt;
&lt;p&gt;Raft is an algorithm for managing a replicated log.
In the context of Raft a replicated log is a list
of proposed changes to a state machine.
Raft guarantees consistency (it&#39;s CP)
and is &lt;em&gt;fault-tolerant&lt;/em&gt;: the system remains available
and consistent (linearisable?) &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/raft_notes/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; as long as a
majority of nodes stay up.&lt;/p&gt;
&lt;p&gt;It was designed with ease of understanding in mind:
the authors claim that Paxos is difficult to
understand and propose Raft as a more understandable
alternative.&lt;/p&gt;
&lt;h3 id=&quot;safety-properties-of-raft%3A&quot; tabindex=&quot;-1&quot;&gt;Safety properties of Raft:&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Election safety&lt;/strong&gt;: at most one leader can be elected
in a given term.
&lt;strong&gt;Leader append-only&lt;/strong&gt;: a leader never overwrites
or deletes entries in its log; it only appends new entries.
&lt;strong&gt;Log matching&lt;/strong&gt;: if two logs contain an entry with
the same index and term, then the logs are identical
in all entries up through the given index.
(That is, if two logs agree on an entry in position i,
they will also agree on all entries from 1 through i-1).
&lt;strong&gt;Leader completeness:&lt;/strong&gt; if a log entry is committed
in a given term, that entry will be present
in the logs of the leaders for all higher-numbered terms.
&lt;strong&gt;State machine safety&lt;/strong&gt;:if a server has applied
a log entry at a given index to its state machine,
no other server will ever apply a different log entry
for the same index.&lt;/p&gt;
&lt;h2 id=&quot;interesting-things-about-the-paper&quot; tabindex=&quot;-1&quot;&gt;Interesting things about the paper&lt;/h2&gt;
&lt;h2 id=&quot;questions-i-had-about-the-paper&quot; tabindex=&quot;-1&quot;&gt;Questions I had about the paper&lt;/h2&gt;
&lt;h3 id=&quot;leader-election-and-the-election-timeout&quot; tabindex=&quot;-1&quot;&gt;Leader election and the election timeout&lt;/h3&gt;
&lt;p&gt;A server remains in follower state as long as it receives
valid RPCs from a leader or candidate. Leaders send
periodic heartbeats (AppendixEntries RPCs with no log entries)
to all followers in order to maintain their authority.
If a follower receives no communication over a period
of time called the &lt;em&gt;election timeout&lt;/em&gt;, then it assumes
there is no viable leader and begins an election to choose
a new leader.&lt;/p&gt;
&lt;h3 id=&quot;why-is-it-important-that-nodes-disregard-requestvote-rpcs-before-the-minimum-election-timeout%3F-what-would-happen-if-they-didn&#39;t%3F&quot; tabindex=&quot;-1&quot;&gt;Why is it important that nodes disregard RequestVote RPCs before the minimum election timeout? What would happen if they didn&#39;t?&lt;/h3&gt;
&lt;p&gt;Find an example whereby nodes didn&#39;t disregard
RequestVote RPCs before the minimum election timeout,
and show that it is bad.&lt;/p&gt;
&lt;h3 id=&quot;what-is-%22copy-on-write%22%3F-why-is-it-important%3F&quot; tabindex=&quot;-1&quot;&gt;What is &amp;quot;copy-on-write&amp;quot;? Why is it important?&lt;/h3&gt;
&lt;h3 id=&quot;what-is-%22linearisable-semantics%22%3F-why-is-it-important%3F&quot; tabindex=&quot;-1&quot;&gt;What is &amp;quot;linearisable semantics&amp;quot;? Why is it important?&lt;/h3&gt;
&lt;h3 id=&quot;why-does-linearisable-semantics-imply-no-stale-reads%3F&quot; tabindex=&quot;-1&quot;&gt;Why does linearisable semantics imply no stale reads?&lt;/h3&gt;
&lt;h3 id=&quot;how-do-we-prevent-leaders-from-returning-stale-reads%3F&quot; tabindex=&quot;-1&quot;&gt;How do we prevent leaders from returning stale reads?&lt;/h3&gt;
&lt;p&gt;Leaders need to receive a heartbeat from a majority
to make sure it&#39;s still the leader before returning
any read data to the client.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I should think more about how to map these consistency guarantees to the actual safety properties of Raft. &lt;a href=&quot;https://lieuzhenghong.com/raft_notes/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>MIT&#39;s 6.824 Distributed Systems, Lab 1: MapReduce</title>
    <link href="https://lieuzhenghong.com/mit_6.824_lab_1_mapreduce/"/>
    <updated>2021-02-05T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/mit_6.824_lab_1_mapreduce/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Here I talk about what Lab 1 was about,
what problems I faced when implementing it,
and what I learned doing the lab.&lt;/p&gt;
&lt;p&gt;This is part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-task&quot; tabindex=&quot;-1&quot;&gt;The task&lt;/h2&gt;
&lt;p&gt;The task in Lab 1 was to implement MapReduce
more-or-less faithfully as it was described
in the original paper in Golang.
The key difference is that all workers run
on the same computer and all files are on
the same local disk.
One other difference is that
while the original MapReduce paper
describes the master pushing tasks to workers,
we were told to have workers call the master
using remote procedure calls (RPCs)
to ask for tasks instead.&lt;/p&gt;
&lt;p&gt;We were given scaffolding code and testing code
which helped a great deal.
All we had to do was write the master
and worker code.&lt;/p&gt;
&lt;p&gt;Reading the paper and grokking it took me
around two hours,
and implementing it took me about 6 hours.
Overall, it wasn&#39;t too hard.&lt;/p&gt;
&lt;h2 id=&quot;my-implementation&quot; tabindex=&quot;-1&quot;&gt;My implementation&lt;/h2&gt;
&lt;p&gt;Here&#39;s an overview of the process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Periodically, workers call the Master
with a RequestJob RPC.&lt;/li&gt;
&lt;li&gt;Master checks current job status:
&lt;ul&gt;
&lt;li&gt;if all jobs done: assign &amp;quot;exit&amp;quot; job&lt;/li&gt;
&lt;li&gt;elif there are idle Map jobs: assign Map job&lt;/li&gt;
&lt;li&gt;elif all Map jobs completed and
there are idle Reduce jobs: assign Reduce job&lt;/li&gt;
&lt;li&gt;else: assign &amp;quot;null&amp;quot; job&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When a worker receives a reply from RequestJob:
&lt;ul&gt;
&lt;li&gt;if &amp;quot;exit&amp;quot;: exit&lt;/li&gt;
&lt;li&gt;if &amp;quot;map&amp;quot;: perform Map job on
file at fileLocation.
Save intermediate files as &amp;quot;mr-X-Y&amp;quot;
where &lt;code&gt;X&lt;/code&gt; is the index of the map job
and &lt;code&gt;Y&lt;/code&gt; is the (modded) hash of the key.
When this job is done,
call Master with ReceiveFileLocation RPC,
giving the location of the intermediate files.&lt;/li&gt;
&lt;li&gt;if &amp;quot;reduce&amp;quot;: perform Reduce job on
all files at fileLocations,
then save file as &amp;quot;mr-0-Y&amp;quot;
where &lt;code&gt;Y&lt;/code&gt; is the index of the reduce job.&lt;/li&gt;
&lt;li&gt;if &amp;quot;null&amp;quot;: sleep(1), then RequestJob again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the master receives a ReceiveFileLocation RPC,
it takes the file locations contained therein
and saves them so that it can then pass them
to the reduce workers.&lt;/p&gt;
&lt;p&gt;The master does some bookkeeping to
check when tasks are complete/have stalled,
save file locations returned by ReceiveFileLocation,
and so on.&lt;/p&gt;
&lt;h2 id=&quot;problems-i-faced%2C-and-how-i-solved-them&quot; tabindex=&quot;-1&quot;&gt;Problems I faced, and how I solved them&lt;/h2&gt;
&lt;p&gt;Concurrency is the biggest challenge.
The master is constantly receiving lots of
different RPCs, each in a different thread.
You can very easily have a race condition.
For instance, the ReceiveFileLocation RPC
causes the master to update its list of
intermediate files.
But these intermediate files might be read
when responding to a RequestJob RPC.
Since each RPC runs on a different thread,
it&#39;s possible that the RequestJob RPC
might read while the ReceiveFileLocation RPC
is writing, which would result in inconsistent
state.&lt;/p&gt;
&lt;h3 id=&quot;segfault-because-i-didn&#39;t-initialise-arrays-of-objects&quot; tabindex=&quot;-1&quot;&gt;Segfault because I didn&#39;t initialise arrays of objects&lt;/h3&gt;
&lt;p&gt;This was due to my lack of knowledge with Go.
So I was declaring &lt;code&gt;a := [][]string&lt;/code&gt;
and then doing &lt;code&gt;a[i]&lt;/code&gt; which throws a segfault,
because the slice hasn&#39;t yet been initialised.
Instead one should do &lt;code&gt;a := make([][]string, N)&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;deadlocks&quot; tabindex=&quot;-1&quot;&gt;Deadlocks&lt;/h3&gt;
&lt;p&gt;When Liang Jun explained deadlocks to me I thought
only an idiot would get into deadlocks.
I guess that makes me an idiot 🙃.&lt;/p&gt;
&lt;p&gt;The way he explained it is that deadlock happens
when there&#39;s a function A holding the lock
and is waiting for B to finish in order to unlock,
while B is waiting for A to unlock so that it
can start running.
I thought &amp;quot;I&#39;ll never write code where this happens&amp;quot;.
Well--it turns out that you can easily do that with nested calls.&lt;/p&gt;
&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token function&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// do something ...&lt;/span&gt;
    m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here &lt;code&gt;f&lt;/code&gt; will acquire a lock, call &lt;code&gt;g&lt;/code&gt;,
then &lt;code&gt;g&lt;/code&gt; will try to acquire the same lock.
But it can&#39;t because &lt;code&gt;f&lt;/code&gt; is still holding on to it.
But &lt;code&gt;f&lt;/code&gt; will never release the lock because it&#39;s
waiting for &lt;code&gt;g&lt;/code&gt; to complete! So we have a deadlock.&lt;/p&gt;
&lt;p&gt;In this lab, &lt;code&gt;g&lt;/code&gt; was &lt;code&gt;GrabAllFileNamesForReduceJob&lt;/code&gt;
and &lt;code&gt;f&lt;/code&gt; was &lt;code&gt;AssignReduceJobToWorker&lt;/code&gt;.
Inside &lt;code&gt;f&lt;/code&gt; there was a call
&lt;code&gt;reply.MapFileLocations = GrabAllFileNamesForReduceJob(..)&lt;/code&gt;.
It was very easy to make this mistake,
because I thought &amp;quot;OK, so g() is reading state, we need to lock it&amp;quot;.
And if you do call it from a function that doesn&#39;t lock then you
would indeed have to have a lock in &lt;code&gt;g&lt;/code&gt;.
But in this case since &lt;code&gt;f&lt;/code&gt; locks, you cannot lock in &lt;code&gt;g&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot; tabindex=&quot;-1&quot;&gt;What I learned&lt;/h2&gt;
&lt;p&gt;This was a good warm-up exercise just to get to know Go better.
Lab 2 is going to be very hard,
so this practice is definitely welcome.&lt;/p&gt;
&lt;p&gt;I didn&#39;t know what an RPC was until I took this course.
I wish someone had told me this earlier, because
&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/&quot;&gt;my Python library I wrote for work&lt;/a&gt;
is basically just reinventing an RPC library.
I suppose this means that I can now write
&amp;quot;designed and implemented custom RPC library with TCP sockets&amp;quot;
in my resume...&lt;/p&gt;
&lt;p&gt;I also went down the rabbit hole a little bit.
In order to do this lab
I had to learn about concurrency and mutexes.
But in order to learn that I had to learn what
the difference is between a thread and a process.
And in order to learn &lt;em&gt;that&lt;/em&gt; I had to know what
a process even was -- which brought me back to
operating systems and &lt;code&gt;fork()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And, of course, I learned about MapReduce at a level
that you just don&#39;t get from passively listening
or reading alone. There&#39;s no substitute for implementation.&lt;/p&gt;
&lt;h2 id=&quot;what-i-should-have-done-better&quot; tabindex=&quot;-1&quot;&gt;What I should have done better&lt;/h2&gt;
&lt;p&gt;Not a mistake &lt;em&gt;per se&lt;/em&gt;, but
I tried to stick very closely to the spec
given in the actual MapReduce paper,
but after doing a code review of Liang Jun&#39;s code
I realised the code can be much cleaner
if you don&#39;t follow it strictly.
For instance, one thing Liang Jun did that I didn&#39;t
was to make workers send an acknowledgement
after a successful reduce task.
I deliberately didn&#39;t do this because the paper says&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;When a map task completes, the worker &lt;strong&gt;sends a message to the master&lt;/strong&gt;... When a reduce task completes, the reduce worker &lt;strong&gt;atomically renames its temporary output file&lt;/strong&gt; to the final output file&amp;quot;,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;implying that the reduce worker should not
send a message back to the master.
This entails extra complexity on the master
because it has to have response handling code
for the map workers, and file-checking code
for the reduce workers.
But as far as I can tell there&#39;s no good reason
for reduce workers not to send back a completion too:
having all workers send back a completion
makes the implementation much cleaner.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, I learned a lot from this lab.
It wasn&#39;t too hard and I quite enjoyed writing in Go.
I do kind of miss list comprehensions from Python,
but I do like the simplicity of Golang.
(There&#39;s a lot more to learn, of course!)&lt;/p&gt;
&lt;p&gt;What I want to learn more about:
Golang, Go&#39;s channels, interfaces,
concurrent programming.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dean and Ghemawat (2004). MapReduce: Simplified Data Processing on Large Clusters</title>
    <link href="https://lieuzhenghong.com/mapreduce_notes/"/>
    <updated>2021-02-05T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/mapreduce_notes/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This paper introduces MapReduce.&lt;/p&gt;
&lt;p&gt;I read this paper as part of my
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;self-study of 6.824 with NUS SoC folks&lt;/a&gt;.
It may or may not be part of my goal to
&lt;a href=&quot;https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/&quot;&gt;finish a Stanford CS degree in a year&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;overview-of-the-paper&quot; tabindex=&quot;-1&quot;&gt;Overview of the paper&lt;/h2&gt;
&lt;h2 id=&quot;interesting-things-about-the-paper&quot; tabindex=&quot;-1&quot;&gt;Interesting things about the paper&lt;/h2&gt;
&lt;h3 id=&quot;mapreduce-gets-map-jobs&quot; tabindex=&quot;-1&quot;&gt;MapReduce gets map jobs&lt;/h3&gt;
&lt;p&gt;For some reason, the paper gets Map workers
to send the list of the generated intermediate file locations
back to the server,
but doesn&#39;t do it for Reduce workers.
I get it--there&#39;s not really a need
for Reduce workers to send back
since Reduce output files are saved
on a shared file system while Map intermediate files
are saved on the individual workers&#39; storage.
The drawback is that it results in
additional work for the server
to have to constantly check for the presence
of output files.
I compared my implementation to&lt;/p&gt;
&lt;p&gt;I think this could be trying to save
unnecessary network I/O.&lt;/p&gt;
&lt;h3 id=&quot;how-mapreduce-avoids-inconsistency&quot; tabindex=&quot;-1&quot;&gt;How MapReduce avoids inconsistency&lt;/h3&gt;
&lt;p&gt;The problem is&lt;/p&gt;
&lt;p&gt;With&lt;/p&gt;
&lt;p&gt;Suppose you have a m&lt;/p&gt;
&lt;p&gt;The paper prevents master from observing
files that have been partially written
by using temporary output files
plus a atomic rename operation.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Self-studying MIT&#39;s 6.824 Distributed Systems</title>
    <link href="https://lieuzhenghong.com/mit_6.824_self_study/"/>
    <updated>2021-02-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/mit_6.824_self_study/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&#39;m auditing the NUS DYOM Distributed Systems course.
Thanks to Wei Neng for introducing me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I would do 6.284 if I were you&lt;/p&gt;
&lt;p&gt;There&#39;s a class in NUS running now&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Wei Neng told me to ask Joel,
who then told me to consult Bernard,
who managed to get me on board! Very pleased.&lt;/p&gt;
&lt;p&gt;I was surprised at how progressive NUS was:
they allow students to make their own module
(they call it DYOM) and do it for credits.
So this module is based on the MIT course
&lt;a href=&quot;https://pdos.csail.mit.edu/6.824/&quot;&gt;6.824: Distributed Systems&lt;/a&gt;.
The difference between the NUS DYOM course
and the MIT course is primarily that of scope.
The original 6.824 is a graduate-level course,
this is for undergraduates;
the original course is taught by a professor,
this is student-run;
finally, MIT students usually do two modules a semester,
while NUS students do five.
So I think the plan is to do fewer labs (they will stop at lab 2C)
read fewer papers, and have fewer lectures.
However, I plan to finish all of the labs
(up to Lab 3B and do the &lt;a href=&quot;https://pdos.csail.mit.edu/6.824/project.html&quot;&gt;final project&lt;/a&gt;)&lt;br&gt;
and read some additional papers on the side.&lt;/p&gt;
&lt;h2 id=&quot;structure-of-the-course&quot; tabindex=&quot;-1&quot;&gt;Structure of the course&lt;/h2&gt;
&lt;p&gt;From the MIT 6.824 course page:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.824 is a core 12-unit graduate subject with lectures, readings,
programming labs, an optional project, a mid-term exam, and a final exam. It
will present abstractions and implementation techniques for engineering
distributed systems. Major topics include fault tolerance, replication, and
consistency. Much of the class consists of studying and discussing case
studies of distributed systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We meet every Monday in person at SoC to go through a paper or proof.
Each week a different person leads the discussion.
We do the labs (1, 2A--2D, 3A, 3B) on our own time.&lt;/p&gt;
&lt;h3 id=&quot;papers-covered-in-the-course&quot; tabindex=&quot;-1&quot;&gt;Papers covered in the course&lt;/h3&gt;
&lt;p&gt;The NUS students voted to cover a subset of the papers
covered in the 2018 offering.
Some of these papers are no longer being covered
in the latest (2021) offering.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/mapreduce_notes/&quot;&gt;MapReduce (2004)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;GFS (2003)&lt;/li&gt;
&lt;li&gt;Fault-Tolerant Virtual Machines (2010)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/raft_notes/&quot;&gt;Extended Raft paper (2014)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Zookeeper (2010)&lt;/li&gt;
&lt;li&gt;CRAQ (2009)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/aurora_notes/&quot;&gt;Amazon Aurora (2017)&lt;/a&gt; (replaced with Pacifica (2008) in the 2021 offering)&lt;/li&gt;
&lt;li&gt;Frangipani (1997)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/principles_of_computer_systems_design_ch_9_notes/&quot;&gt;Saltzer and Kaashoek (2009).
&lt;em&gt;Principles of Computer System Design: An Introduction&lt;/em&gt;
(used in MIT&#39;s 6.033 course).
Chapter 9, sections 9.1.5, 9.1.6, 9.5.2, 9.5.3, 9.6.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spanner (2012)&lt;/li&gt;
&lt;li&gt;FARM (2015)&lt;/li&gt;
&lt;li&gt;Spark (2012)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/memcached_at_facebook/&quot;&gt;Memcached at Facebook (2013)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;COPS (2011)&lt;/li&gt;
&lt;li&gt;Bitcoin (2008)&lt;/li&gt;
&lt;li&gt;Blockstack (2017)&lt;/li&gt;
&lt;li&gt;Analogic FS experience paper&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/spinnaker_notes/&quot;&gt;Spinnaker (2011)&lt;/a&gt; (this was taken out in the 2021 offering, but we&#39;re reading it regardless)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/dynamo_notes/&quot;&gt;Amazon DynamoDB (2007)&lt;/a&gt; (ditto)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/crdt_notes/&quot;&gt;Shapiro et al. (2011). CRDTs&lt;/a&gt; (not covered in the MIT course, but interesting and relevant)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will be writing notes on each paper I read
to serve as a reference for my future self,
to keep me accountable,
and to serve as a proof-of-work.&lt;/p&gt;
&lt;p&gt;I also write notes in key distributed systems concepts:
&lt;a href=&quot;https://lieuzhenghong.com/cap_theorem/&quot;&gt;the CAP impossibility theorem&lt;/a&gt; and
&lt;a href=&quot;https://lieuzhenghong.com/flp_theorem/&quot;&gt;the FLP impossibility theorem&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lab-assignments-in-the-course&quot; tabindex=&quot;-1&quot;&gt;Lab assignments in the course&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Lab 1 implements MapReduce.
I&#39;ve successfully implemented it
(took me about a day and a half to read and implement:
7--8 hours total?)
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_lab_1_mapreduce/&quot;&gt;My notes on Lab 1&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lab 2 (A, B, C, D) implements the
&lt;a href=&quot;https://files.lieu.gg/docs/Ongaro%20and%20Ousterhout%20(2014).%20In%20Search%20of%20an%20Understandable%20Consensus%20Algorithm%20(Extended%20Version).pdf&quot;&gt;Raft consensus algorithm&lt;/a&gt;
with log compaction.
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_lab_2_raft/&quot;&gt;My notes on Lab 2&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Lab 3 (A, B) builds a fault-tolerant key-value store
using the Raft consensus mechanism.&lt;/li&gt;
&lt;li&gt;Lab 4 is either building a sharded key-value service,
or creating a final project of your own.
I think this is super cool, and I hope that someone in the class will be
keen to do a final project with me.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;other-things-i-expect-to-learn-in-the-course&quot; tabindex=&quot;-1&quot;&gt;Other things I expect to learn in the course&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Programming in Go&lt;/li&gt;
&lt;li&gt;The Go memory model&lt;/li&gt;
&lt;li&gt;Concurrency, threads, locking, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;other-things-i-want-to-read&quot; tabindex=&quot;-1&quot;&gt;Other things I want to read&lt;/h3&gt;
&lt;p&gt;I&#39;m pasting here to read in the future.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Zanzibar (2019). Link &lt;a href=&quot;https://research.google/pubs/pub48190/&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Google&#39;s Hybrid Approach to Research (2012). Link &lt;a href=&quot;https://cacm.acm.org/magazines/2012/7/151226-googles-hybrid-approach-to-research/fulltext&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Christopher Meiklejohn&#39;s &amp;quot;Readings in distributed systems&amp;quot;. Link
&lt;a href=&quot;http://christophermeiklejohn.com/distributed/systems/2013/07/12/readings-in-distributed-systems.html&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Dan Cres&#39;s &amp;quot;A Distributed Systems Reading List&amp;quot;. Link
&lt;a href=&quot;https://dancres.github.io/Pages/&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Spanner (2012).
Link &lt;a href=&quot;https://research.google/pubs/pub39966/&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Distributed systems for fun and profit
Link &lt;a href=&quot;http://book.mixu.net/distsys/single-page.html&quot;&gt;here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.cs.princeton.edu/~wlloyd/papers/existential-sosp15.pdf&quot;&gt;Existential Consistency: Measuring and Understanding Consistency at Facebook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>DIY-ing a Stanford CS degree in one year</title>
    <link href="https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/"/>
    <updated>2021-01-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/diying_a_stanford_CS_degree_in_a_year/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Can we, through self-study,
learn as much CS as a Stanford CS graduate would learn?
And (stretch goal) can we do it in a year?&lt;/p&gt;
&lt;p&gt;Spreadsheet tracking my progress
&lt;a href=&quot;https://docs.google.com/spreadsheets/d/1rhbUxoDY7Yi0z9bg8RRS1DxQCjC9HszYU5UoQ8n0vHQ/edit?usp=sharing&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-would-be-the-point%3F&quot; tabindex=&quot;-1&quot;&gt;What would be the point?&lt;/h2&gt;
&lt;p&gt;If you wanted to optimise
for getting a big job offer your time would
probably be better spent grinding LC (for regular SWE jobs)
or learning the ins and outs of C++ (for quant trading).&lt;/p&gt;
&lt;p&gt;There is obviously no credential from doing this.
That&#39;s not really important to me
since I already have a degree from Oxford,
so there would be very little (if any) marginal signaling value.&lt;/p&gt;
&lt;p&gt;So what&#39;s the point?
The main purpose for me is to fill up all the gaps
in my knowledge. Having rubbed shoulders with folks
like Bernard/Mark/WH/Julius/WN/Vig,
I know there&#39;s still a lot I don&#39;t know,
and I know there&#39;s a long way to go before I can match them.
I want to fix this.&lt;/p&gt;
&lt;p&gt;I also hope that some of these more &amp;quot;fundamental&amp;quot;
concepts will be useful in my future work.
In particular, I expect OS, networking, and databases
to be particularly useful.&lt;/p&gt;
&lt;p&gt;And of course, there&#39;s the joy of learning new things
as well.&lt;/p&gt;
&lt;h2 id=&quot;why-this%3F-why-now%3F&quot; tabindex=&quot;-1&quot;&gt;Why this? Why now?&lt;/h2&gt;
&lt;p&gt;Motivation is manyfold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;IMDA has asked me to come up with a personal development plan,
and Eric recommended several courses&lt;/li&gt;
&lt;li&gt;I want to fill in the gaps in my knowledge to become the best SWE I can be&lt;/li&gt;
&lt;li&gt;The pandemic has forced many lecturers to upload their (very high quality) resources online
and think about how to teach in a non-lecture style&lt;/li&gt;
&lt;li&gt;CS is very easy to study online (many projects/lab-based with no final exams)&lt;/li&gt;
&lt;li&gt;As a corollary to 4: If I self-study CS that frees me up to study maths/stats/ML for Master&#39;s&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;%22rules-of-the-game%22&quot; tabindex=&quot;-1&quot;&gt;&amp;quot;Rules of the game&amp;quot;&lt;/h2&gt;
&lt;p&gt;The (very much self-imposed) rules for each module are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Don&#39;t skip any of the lessons/work unless strictly necessary&lt;/li&gt;
&lt;li&gt;Have a final project, paper, or something &amp;quot;real&amp;quot; to show for every course taken&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A corollary to point 2 is that
I should look for courses that are lab-based/project based.
It&#39;s fortunate that I enjoy those courses better anyway.&lt;/p&gt;
&lt;p&gt;There&#39;s no real need to do all Stanford courses:
I&#39;m happy to mix-and-match with MIT/other
similarly (or more) rigorous offerings.
For instance, instead of doing Stanford&#39;s
CS 244B Distributed Systems offering,
I am currently working through
&lt;a href=&quot;https://lieuzhenghong.com/mit_6.824_self_study/&quot;&gt;MIT&#39;s 6.824 Distributed Systems course&lt;/a&gt;
with the NUS SoC folks.&lt;/p&gt;
&lt;p&gt;Also, there&#39;s no need to strictly follow any &amp;quot;honour code&amp;quot;
to do all the work myself.
This is for three reasons.
Firstly, since this is a self-directed project with no signaling value,
the only person I would be cheating is myself.
Secondly, doing work with someone else
may give me the motivation to push through
periods of low motivation/a part that I am blocked on.
Finally, technical issues might stygmie my going it alone:
most recently for CS140E/CS107E WSL2 didn&#39;t support UART
so Wei Neng and I had to pair program.&lt;/p&gt;
&lt;h2 id=&quot;can-you-really-do-it-in-a-year%3F&quot; tabindex=&quot;-1&quot;&gt;Can you really do it in a year?&lt;/h2&gt;
&lt;p&gt;To graduate, a Stanford CS student must finish
courses in all of these topic areas
&lt;a href=&quot;https://exploredegrees.stanford.edu/schoolofengineering/computerscience/&quot;&gt;source: Stanford website&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mathematics&lt;/li&gt;
&lt;li&gt;Science&lt;/li&gt;
&lt;li&gt;Technology in Society&lt;/li&gt;
&lt;li&gt;Engineering Fundamentals&lt;/li&gt;
&lt;li&gt;Writing in the Major&lt;/li&gt;
&lt;li&gt;CS Core&lt;/li&gt;
&lt;li&gt;Senior Project (Software Project)&lt;/li&gt;
&lt;li&gt;Electives&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This takes four years for a regular Stanford undergrad,
but there are several reasons why I can do it quicker:&lt;/p&gt;
&lt;h3 id=&quot;i&#39;ve-already-done-equivalents-of-several-courses&quot; tabindex=&quot;-1&quot;&gt;I&#39;ve already done equivalents of several courses&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CS109 Introduction to Probability for Computer Scientists: I&#39;ve done a lot of this in my own probability course in uni.&lt;/li&gt;
&lt;li&gt;CS106B Programming Abstractions: already know a lot of
what is covered.&lt;/li&gt;
&lt;li&gt;CS161 Design and Analysis of Algorithms:
did Tim Roughgarden&#39;s course on Coursera.&lt;/li&gt;
&lt;li&gt;CS229 Machine Learning: done Andrew Ng&#39;s course on
Coursera.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;we-are-at-liberty-to-skip-many-of-the-non-cs-courses&quot; tabindex=&quot;-1&quot;&gt;We are at liberty to skip many of the non-CS courses&lt;/h3&gt;
&lt;p&gt;A regular Stanford undergrad needs to do
compulsory Science modules,
but I will skip them.
I will also skip &amp;quot;Technology in Society&amp;quot;,
&amp;quot;Engineering Fundamentals&amp;quot;,
&amp;quot;Writing in the Major&amp;quot;, because they are fluffy,
and God knows I got enough writing in &lt;em&gt;my&lt;/em&gt; major...&lt;/p&gt;
&lt;p&gt;After skipping the science courses and fluffy modules,
what&#39;s left for me to do is the following
(strikethroughs denote courses I either already did,
or already know from my own self-assessment):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CS 103 Mathematical Foundations of Computing&lt;/li&gt;
&lt;li&gt;&lt;s&gt;CS 109 Introduction to Probability for Computer Scientists&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;MATH 19 (Calculus I)&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;MATH 20 (Calculus II)&lt;/li&gt;
&lt;li&gt;MATH 21 (Calculus III)&lt;/li&gt;
&lt;li&gt;MATH Elective 1 (PHIL 151/CS 157 Computational Logic?)&lt;/li&gt;
&lt;li&gt;MATH Elective 2 (linear algebra? real analysis)&lt;/li&gt;
&lt;li&gt;&lt;s&gt;CS 106B Programming Abstractions&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;CS 107E Computer Systems from the Ground Up&lt;/li&gt;
&lt;li&gt;CS 111 Operating Systems Principles&lt;/li&gt;
&lt;li&gt;&lt;s&gt;CS 161 Design and Analysis of Algorithms&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;CS 194W Software Project&lt;/s&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I also need to do seven electives.
Some electives that particularly interest me are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CS 140e Operating Systems&lt;/li&gt;
&lt;li&gt;CS 144 Introduction to Computer Networking&lt;/li&gt;
&lt;li&gt;CS 190 Software Design&lt;/li&gt;
&lt;li&gt;CS 228 Probabilistic Graphical Models&lt;/li&gt;
&lt;li&gt;&lt;s&gt;CS 229 Machine Learning&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;CS 230 Deep Learning&lt;/li&gt;
&lt;li&gt;CS 231n Convolutional Neural Networks&lt;/li&gt;
&lt;li&gt;CS 244B Distributed Systems&lt;/li&gt;
&lt;li&gt;CS 245 Principles of Data-Intensive Systems&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;the-normal-pace-is-for-chumps&quot; tabindex=&quot;-1&quot;&gt;The normal pace is for chumps&lt;/h3&gt;
&lt;p&gt;I took three years to do my degree,
and by all metrics did it very well.
That&#39;s &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;52&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;156&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;52 * 3 = 156&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;156&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; weeks.
But---thinking back---since the terms were only
eight weeks long, and Trinity Term of final year
doesn&#39;t really count, that&#39;s a total of
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;8&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;8&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;64&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;8 * 8 = 64&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;64&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; study weeks.
Of course some of the holidays were spent revising,
but on the flip side there were also many days
during term where I didn&#39;t work much if at all.&lt;/p&gt;
&lt;p&gt;If one devoted yourself full-time to the pursuit
I am confident that one could do the PPE degree
in a year. At the very least one could give it
a damn good shake.&lt;/p&gt;
&lt;h2 id=&quot;i-can-do-it%3A-should-i-do-it%3F&quot; tabindex=&quot;-1&quot;&gt;I can do it: &lt;em&gt;should&lt;/em&gt; I do it?&lt;/h2&gt;
&lt;p&gt;Similarly, if I devoted myself to this
I&#39;m pretty sure I could do it in a year.
The question as always is whether I could do it
but whether I &lt;em&gt;should&lt;/em&gt; do it.
Is it better to spend my time doing
&lt;a href=&quot;https://www.benkuhn.net/blub/&quot;&gt;blub studies&lt;/a&gt;
instead? Or more Leetcode? Or more side projects?
Or write more essays that nobody reads?
I&#39;m not sure.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Making your habits zero-friction is a massive productivity hack</title>
    <link href="https://lieuzhenghong.com/zero_friction_habits/"/>
    <updated>2021-01-28T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/zero_friction_habits/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;TL;DR;&lt;/strong&gt;
I have found that &lt;strong&gt;aggressively minimising&lt;/strong&gt; the friction of my tasks
has allowed me to easily build and maintain desirable habits.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;We want to build and maintain habits because they allow us to convert our
motivation (a finite and transient resource) into a more permanent routine.
But I often find myself not sticking to the habits I&#39;ve tried to build.&lt;/p&gt;
&lt;p&gt;How can you stick to your habits?
I have found that &lt;strong&gt;aggressively minimising&lt;/strong&gt; task friction has been the
most effective,
and that even tiny decreases in friction (from almost-zero to zero)
can make a huge difference in adherence.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;ll explain why habits are useful, define what it means to
&amp;quot;aggressively minimise&amp;quot; the friction of a task,
and give several examples of how aggressive minimisation helped me.&lt;/p&gt;
&lt;h2 id=&quot;aggressively-minimising-friction-is-a-highly-effective-way-to-maintain-one&#39;s-habits&quot; tabindex=&quot;-1&quot;&gt;Aggressively minimising friction is a highly effective way to maintain one&#39;s habits&lt;/h2&gt;
&lt;p&gt;Define the &lt;em&gt;static friction&lt;/em&gt; of a task as
the time/effort/displeasure incurred to &lt;em&gt;start doing&lt;/em&gt; the task,
and the &lt;em&gt;dynamic friction&lt;/em&gt; of a task as
the effort required to actually perform it.&lt;/p&gt;
&lt;p&gt;Scott Young writes that
&lt;a href=&quot;https://www.scotthyoung.com/blog/2015/03/25/permanent-habits/&quot;&gt;reducing static friction is by far more significant&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For a lot of tasks, the second cost reduction is far greater than the first.
Flossing, for instance, hasn’t gotten any easier the hundredth time I’ve done
it, but I have stopped thinking about whether I should do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He suggests starting a habit as a way to reduce the static friction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you read your fifty pages at lunch, every day, for three months, the next
lunch break you’ll automatically start reading without having to decide
whether to do it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The idea is that if you succesfully maintain a habit
you will decrease the task&#39;s static friction because that action will become habitual.
This begs the question, however:
&lt;em&gt;how&lt;/em&gt; do I maintain the habits that I&#39;ve started?
I&#39;ve found that &lt;strong&gt;aggressively minimising&lt;/strong&gt; friction is by far the most
effective method to do so.&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I started working out much more often
once I switched to a bodyweight fitness routine that didn&#39;t require me to travel
to the gym,
allowing me to maintain my daily workout habit.&lt;/li&gt;
&lt;li&gt;I started vacuuming the floor of my room daily once we bought a cordless
vacuum cleaner,
because I no longer had to lug the heavy thing around and plug it into an
outlet.&lt;/li&gt;
&lt;li&gt;Simply leaving the guitar out of its case makes me practice 10x more often,
because I could just pick it up whenever I got bored.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How do we aggressively minimise friction? I think there&#39;s not that much to it:
Think about a habit that you&#39;re trying (and failing) to adhere to.
Next, think about what you dread about/ what&#39;s difficult about starting the task.
See if you can reduce or eliminate whatever that is.&lt;/p&gt;
&lt;h2 id=&quot;there-are-no-diminishing-returns-to-decreasing-friction&quot; tabindex=&quot;-1&quot;&gt;There are no diminishing returns to decreasing friction&lt;/h2&gt;
&lt;p&gt;I have observed no diminishing returns to decreasing friction.
Even a tiny bit of friction can spell the difference between a successful habit
and an abandoned one.&lt;/p&gt;
&lt;p&gt;Here are some examples of how small frictions make a difference:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Even on the very low-friction bodyweight routine,
I am much more consistent in doing my &amp;quot;push&amp;quot; workout compared to my
&amp;quot;pull&amp;quot; workout because the &amp;quot;pull&amp;quot; workout requires me to make the 2-minute walk
to the fitness corner outside.
I therefore bought gym equipment and put it in my room.&lt;/li&gt;
&lt;li&gt;Putting Pleco (a dictionary app) on the first page of my home screen
made me much more likely
to look words up. The same was true for Anki, even though it literally takes
one swipe to go from the first screen to the second.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;corollary%3A-to-break-a-bad-habit%2C-deliberately-try-to-increase-friction&quot; tabindex=&quot;-1&quot;&gt;Corollary: to break a bad habit, deliberately try to &lt;em&gt;increase&lt;/em&gt; friction&lt;/h2&gt;
&lt;p&gt;Again, even a tiny bit of added friction can make a big difference!&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I stopped playing as much computer games once I switched from Windows to Linux dual boot
because it was a hassle to reboot the computer.&lt;/li&gt;
&lt;li&gt;I wasted much less time on Facebook/LinkedIn/YouTube
once I added a LeechBlock delay of just a few seconds to every link.
The delay is only a few seconds long,
but this is enough for me to close the tab immediately most of the time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Reducing friction aggressively has outsized effects on habit adherence with
little to no diminishing returns.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Group testing to save the world</title>
    <link href="https://lieuzhenghong.com/group_testing/"/>
    <updated>2021-01-24T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/group_testing/</id>
    <content type="html">&lt;p&gt;The year is 2021.
The world has been transformed into a post-apocalyptic wasteland.
COVID-19 has been cured,
but one of the vaccines went horribly awry:
some of the people who got the Oxford-Zeneca vaccine started
frothing at the mouth,
indiscriminately biting people,
and chanting &lt;em&gt;&amp;quot;Volker Halbach, Volker Halbach&amp;quot;&lt;/em&gt;
before succumbing to their lack of qualia.&lt;/p&gt;
&lt;p&gt;Two back-to-back pandemics were too much for the world to handle,
and the remnants of humanity have been reduced to
scavenging for GrabFood discounts.&lt;/p&gt;
&lt;p&gt;But there is hope. A new screening test has been devised:
a perfect test that can detect for sure
whether someone has the virus in a matter of seconds...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You are an overworked civil servant at the Ministry of Health.
Your boss comes in one day
brandishing a couple of important-looking documents.&lt;/p&gt;
&lt;p&gt;&amp;quot;New directive from the Minister---we need
to test every traveler that comes in to the country.
Can you write me a proposal by today?&amp;quot;&lt;/p&gt;
&lt;p&gt;What choice do you have? You get to work.&lt;/p&gt;
&lt;h2 id=&quot;0.-the-basic-one&quot; tabindex=&quot;-1&quot;&gt;0. The basic one&lt;/h2&gt;
&lt;p&gt;The proposal goes something like this:
All visitors to the country will line up at a testing booth.
When it&#39;s their turn they&#39;ll spit in a cup
and then their secretion will be tested for the virus.
If they test negative, they&#39;re free to go;
if they test positive, they&#39;re whisked away
to a quarantine facility &lt;s&gt;never to be seen again&lt;/s&gt;.
You bang it all out and send it to your boss.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/group_testing/queue.png&quot; alt=&quot;How to test travelers&quot;&gt;&lt;/p&gt;
&lt;p&gt;You get a call the next day.
Your boss is aghast.&lt;/p&gt;
&lt;p&gt;&amp;quot;We haven&#39;t got nearly enough tests
to test everyone who comes!&amp;quot; he shouts.&lt;/p&gt;
&lt;p&gt;&amp;quot;Can we order more tests?&amp;quot; you ask.&lt;/p&gt;
&lt;p&gt;&amp;quot;No, the whole world is out of tests.&amp;quot;&lt;/p&gt;
&lt;p&gt;You take a deep breath to calm yourself.&lt;/p&gt;
&lt;p&gt;&amp;quot;The Minister wants us to test everybody that comes in, right?&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;Yes.&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;But we don&#39;t have enough tests to test everybody?&amp;quot;&lt;/p&gt;
&lt;p&gt;&amp;quot;Yes.&amp;quot;&lt;/p&gt;
&lt;p&gt;A few choice words come to mind, but you (wisely) stay silent.&lt;/p&gt;
&lt;p&gt;If your boss had any shame he&#39;d have the courtesy
to at least &lt;em&gt;look&lt;/em&gt; sheepish,
but unfortunately all senior civil servants have had that
part of the brain surgically excised.
In any case, he wants you to come up with a new proposal.
&amp;quot;Can you find some way to test everyone, but with fewer tests?
As few as possible?&amp;quot;
You try to say something noncommittal but he&#39;s already hung up.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Clumps of your hair lie morosely on the table.&lt;/p&gt;
&lt;p&gt;Testing everyone without enough tests for everyone?
How is that possible?&lt;/p&gt;
&lt;p&gt;You review the evidence.
Preliminary findings suggest that
out of every 1000 people,
roughly 3 people will have the virus.
Also, the test is perfectly accurate and infinitely-sensitive,
which means that it always gives the right answer,
and we can test as many people as we want with one test.
(Since the test is infinitely-sensitive, you can test the tiniest
drop of a person&#39;s spit, and it will give you the right answer).&lt;/p&gt;
&lt;p&gt;Then you have a flash of insight:&lt;/p&gt;
&lt;h2 id=&quot;1.-can-we-share-tests-between-two-people%3F&quot; tabindex=&quot;-1&quot;&gt;1. Can we share tests between two people?&lt;/h2&gt;
&lt;p&gt;Let&#39;s make one small change to the protocol.
Visitors will have to queue-up-and-spit---just as before---but
now TWO visitors will spit in one cup.
This combined cup will then be sent for testing.
Because the test is infinitely sensitive, it will test
positive if either (or both) of the visitors have the virus.
If the combined test comes back negative, then neither visitor
has the virus, and they are free to go.
If it comes back positive, then at least one of the pair has the virus.
We then test each of them individually.&lt;/p&gt;
&lt;p&gt;This two-visitors-one-cup protocol will save almost half
of the tests because most of the tests will come out negative.
Why is this so?
The key here is that &lt;strong&gt;most travelers don&#39;t have the virus.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s use an example to illustrate.&lt;/p&gt;
&lt;p&gt;Suppose we have 1,000 travelers and 3 of them have the virus. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/group_testing/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;
If you test them individually then you will use up 1,000 tests.
If you pair them up at random, however, one of the following
must be the case:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;There are three pairs with one positive person,
and 497 all-negative pairs.&lt;/li&gt;
&lt;li&gt;There is one pair with two positive people,
one pair of one pair with one positive person,
and 498 all-negative pairs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the first case,
we will use 500 tests for each of the pairs.
Three of those tests will come out positive and we will use
an additional two tests for each of them.
The total number of tests is
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;500&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;506&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;500 + 3*2 = 506&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;506&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;In the second,
we will again use 500 tests for each of the pairs,
and use two additional tests for each of the two positive pairs,
for a total of
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;500&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;504&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;500 + 2*2 = 504&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;504&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;In either case, we&#39;ve cut the number of tests needed by almost half!
This method only works because most travelers are negative,
and so most pairs will test negative.
By contrast, if the infection rate was much higher
and 800 out of every 1000 people had the virus then
almost all of the pairs would test positive
and you would do better just testing everyone individually.&lt;/p&gt;
&lt;h2 id=&quot;2.-can-we-share-tests-between-even-more-people%3F&quot; tabindex=&quot;-1&quot;&gt;2. Can we share tests between even more people?&lt;/h2&gt;
&lt;p&gt;If two is good, surely three is better, four even better,
and ten double-plus-good better?
We&#39;ll divide travelers into groups---of, say, ten---
and get them all to spit into the cup.
Doing so could save us even more
tests if most visitors don&#39;t have the virus.
Assuming we only have three visitors with the virus
out of our 1000 visitors,
there can be at most three positive groups &lt;em&gt;no matter the group size.&lt;/em&gt;
Doing groups of 10 would mean at most thirty individual tests,
for an upper bound of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;100&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;130&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;100 + (3*10) = 130&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;130&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests.&lt;/p&gt;
&lt;p&gt;But of course, there&#39;s an upper bound to how many people you can
put in a group.
If you get all 1,000 people to spit into the same bucket (yucks) and test &lt;em&gt;that&lt;/em&gt;
you&#39;ll only have to do one combined test,
but that test is definitely going to come out positive
and you&#39;re going to have to test all 1,000 people individually.
Then you haven&#39;t saved any tests at all.&lt;/p&gt;
&lt;p&gt;We can calculate the optimal size for each group.
The trade-off of having bigger groups
is that you do fewer group tests that combine multiple people,
but have to do more individual tests when a combined test comes back positive.
Let&#39;s introduce some notation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Number of total people = &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Number of infected = &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Number of groups = &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Number of people in each partition = &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N/G = p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the worst case you have to do &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;min&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G + (p * \min(K, G))&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests.&lt;/p&gt;
&lt;p&gt;Why is this so?
In the first step you need to test the &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; groups.
And in the worst case, all &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; of the groups will come out positive
(ergo each positive group has exactly one positive person),
and you&#39;ll have to test each of those &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; groups individually
which takes &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests each.&lt;/p&gt;
&lt;p&gt;We can prove by differentiation
that the optimal number of people in each partition,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, is given by &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msqrt&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msqrt&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*} = \sqrt{\frac{N}{k}}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.84em;vertical-align:-0.5913em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord sqrt&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.2487em;&quot;&gt;&lt;span class=&quot;svg-align&quot; style=&quot;top:-3.8em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.8em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;padding-left:1em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.345em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2087em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.8em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;hide-tail&quot; style=&quot;min-width:1.02em;height:1.88em;&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;400em&quot; height=&quot;1.88em&quot; viewBox=&quot;0 0 400000 1944&quot; preserveAspectRatio=&quot;xMinYMin slice&quot;&gt;&lt;path d=&quot;M983 90
l0 -0
c4,-6.7,10,-10,18,-10 H400000v40
H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7
s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744
c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30
c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722
c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5
c53.7,-170.3,84.5,-266.8,92.5,-289.5z
M1001 80h400000v40h-400000z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.5913em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Using our example of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1000&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N=1000&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K=3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
this would mean that the optimal group size is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msqrt&gt;&lt;mn&gt;333&lt;/mn&gt;&lt;/msqrt&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sqrt{333}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.04em;vertical-align:-0.1328em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord sqrt&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9072em;&quot;&gt;&lt;span class=&quot;svg-align&quot; style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;padding-left:0.833em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;333&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-2.8672em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;hide-tail&quot; style=&quot;min-width:0.853em;height:1.08em;&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;400em&quot; height=&quot;1.08em&quot; viewBox=&quot;0 0 400000 1080&quot; preserveAspectRatio=&quot;xMinYMin slice&quot;&gt;&lt;path d=&quot;M95,702
c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
c69,-144,104.5,-217.7,106.5,-221
l0 -0
c5.3,-9.3,12,-14,20,-14
H400000v40H845.2724
s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
M834 80h400000v40h-400000z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1328em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
which is something like 18.5. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/group_testing/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; If we use &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;20&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p = 20&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; instead
(just so the numbers are easier to work with)
you would need &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;50&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;20&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;110&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;50 + (3*20) = 110&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;110&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests at most
in the worst case, where you do 50 combined tests,
then test the 3 positive groups of 20 individually.&lt;/p&gt;
&lt;p&gt;That&#39;s quite a big reduction.
By grouping people together into larger groups and testing those groups
we can decrease the number of tests needed by almost 90%,
from 1,000 to around 100.&lt;/p&gt;
&lt;p&gt;You sketch out a diagram of how this larger group test approach works
and email it to your boss.
He makes a couple of quick scribbles on it
and it&#39;s quickly distributed to Border Control:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/group_testing/group_test_base_2.png&quot; alt=&quot;Handout to ministry workers&quot;&gt;&lt;/p&gt;
&lt;p&gt;For a while, all is well.
You&#39;ve done the impossible with your great leap of insight
and your boss gives you an A in your performance appraisal.
Your meteoric rise through the ranks of the Civil Service
is all but assured, you think to yourself -- but alas,
Fate is never so kind...&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A few months later, you enter the office and find it in a
state of upheaval.&lt;/p&gt;
&lt;p&gt;It is pandemonium.
Your colleagues are screaming, jumping on desks,
and smashing file cabinets:
files and papers litter the floor,
and your Director is bawling his eyes out.&lt;/p&gt;
&lt;p&gt;&amp;quot;What happened here?&amp;quot; you ask,
and in between racking sobs he points to a
stack of papers on his desk:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As part of the Digital Government Blueprint
and the continuing economic difficulties
caused by the post-pandemic pandemic,
we call upon the Whole-of-Government
to embark upon a Productivity Improvement and Digitisation Journey
to increase WoG efficiency and reduce government expenditure...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lesser men would have gotten hopelessly lost
in the thick thicket of Bureaucrat-ease,
but you realise the subtext immediately.
In order for your boss to keep his year-end bonus
all his charges must demonstrate a 25% efficiency increase
---which means &lt;em&gt;you&lt;/em&gt; have to reduce the number of tests by 25%.&lt;/p&gt;
&lt;p&gt;(At this point the reader might wonder if a fairly mundane requirement
of a efficiency increase could lead to such an exaggerated scene.
I congratulate such a reader for his good fortune not to have worked
in the Civil Service).&lt;/p&gt;
&lt;p&gt;You steal a furtive glance at your boss.
He seems to have recovered very quickly
and is now eyeing you expectantly.
You try to tell him that you&#39;ve &lt;em&gt;already&lt;/em&gt; saved him 90% of tests
but he&#39;s having none of it.
He quickly shoos you out of his office,
leaving you once again to do the seemingly impossible...&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;3.-can-we-share-tests-after-the-combined-test-comes-back-positive%3F&quot; tabindex=&quot;-1&quot;&gt;3. Can we share tests after the combined test comes back positive?&lt;/h2&gt;
&lt;p&gt;Your most recent proposal is to test groups of 20.
If any group&#39;s test comes back positive,
test every single person in that group.
But must we test everyone individually once a group tests positive?
Can&#39;t we group people together again into subgroups of, say, 5?
And if that subgroup tests positive, can&#39;t we group people together &lt;em&gt;again&lt;/em&gt;?
And so on.
After all, if we were able to save tests by
splitting our original group of 1000 into sub-groups,
maybe we can save even more tests by
splitting our sub-groups into sub-subgroups etc.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example. We have a group of 20 that tested positive.
We might then choose subgroups of 5 from that 20,
and start testing the first subgroup of 5.
If &lt;em&gt;that&lt;/em&gt; subgroup tests positive we then split them
&lt;em&gt;again&lt;/em&gt; into sub-subgroups of 2 and 3, and if those sub-subgroups
test positive we test them individually.
As before, if any group/subgroup/subsubgroup... tests negative
then we simply move on to the next one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/group_testing/breadth_first_search_2.png&quot; alt=&quot;Breadth-first search&quot;&gt;&lt;/p&gt;
&lt;p&gt;Does this actually save us tests?
Let&#39;s think about how many tests we would use in the worst case.
The worst case is when the positive tests are as
&amp;quot;spread out&amp;quot; as possible: that is, in different
groups/subgroups/sub-subgroups.&lt;/p&gt;
&lt;p&gt;So we test 50 groups of 20, using 50 tests.
In the worst case, three of the groups test positive.&lt;/p&gt;
&lt;p&gt;When we get a positive group of 20 we
split it up into subgroups of 5.
There will be 12 such subgroups in total (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;20&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;12&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(20 * 3)/ 5 = 12&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;12&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;).
We test all 12, using 12 tests.
In the worst case, three of those subgroups test positive.&lt;/p&gt;
&lt;p&gt;Again, when we get a positive subgroup of 5
we split them up into sub-subgroups of 2 and 3.
There will be three subgroups of 2 and three subgroups of 3.&lt;/p&gt;
&lt;p&gt;Again we test all six, using 6 tests.
Three of &lt;em&gt;those&lt;/em&gt; sub-subgroups test positive,
and because this is the worst case, all the positive sub-subgroups
are of size 3.&lt;/p&gt;
&lt;p&gt;Finally, we test each of those sub-subgroups individually,
using &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;9&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3*3 = 9&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests, for a total of
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;50&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;12&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;6&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;9&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;77&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;50 + 12 + 6 + 9 = 77&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;77&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;You&#39;ve saved the day again!
You send the improved proposal to your boss and
pat yourself on the back for a job well done.
You quickly update your Tinder profile:
after all, nothing gets women more excited than
&amp;quot;Achieved process improvements of more than 90%
for the Ministry of Health&amp;quot;.&lt;/p&gt;
&lt;p&gt;But while things are still fresh in your head
---and knowing that your boss will
probably try to squeeze more out of you---
you reckon that you should keep thinking
of more improvements to continually dole out.
You wouldn&#39;t want work to get in the way
of your schmoozing, after all.
So you keep cracking...&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;4.-can-we-do-better-by-picking-the-right-sub%2Fsubsubgroup-size%3F&quot; tabindex=&quot;-1&quot;&gt;4. Can we do better by picking the right sub/subsubgroup size?&lt;/h2&gt;
&lt;p&gt;You know from part 2 that choosing the right group size
makes a pretty big difference in the number of tests we need.
It stands to reason that the subgroup and subsubgroup sizes
also matter. But how should we pick these sizes?
In part 2 we calculated the optimal group size (20)
but in part 3 we picked the subgroup sizes
arbitrarily (sizes 5 and 2).
Can we do better?&lt;/p&gt;
&lt;p&gt;It turns out that we should halve the size of the (sub)group each time.&lt;/p&gt;
&lt;p&gt;Concretely, we start with a group size of 20
and first conduct a test on the first 10 of the 20 people
(i.e. the subgroup size is 10),
allowing us to eliminate either these 10 people
(if the test came back negative)
or the other 10 people
(if the test came back positive).
&lt;em&gt;But what if both subgroups of 10 test positive?&lt;/em&gt;
Given the small number of positive cases,
the odds of getting two or more positive elements
in a group of 20 are very low,
so in the vast majority of cases we will eliminate half of the people.
(But see a more rigorous treatment in the Appendix!)&lt;/p&gt;
&lt;p&gt;After the first test 10 people remain.
We conduct a test on the first 5 of the 10 people
(subgroup size 5),
allowing us to eliminate 5 people.
We continue doing so until we are left with a single person ---
this person must be infected.
This is an idea very similar to &lt;em&gt;binary search&lt;/em&gt;.
(The proof of why binary search is optimal can be found in the Appendix).&lt;/p&gt;
&lt;h2 id=&quot;5.-can-we-do-better-by-picking-the-right-group-size-(again)%3F&quot; tabindex=&quot;-1&quot;&gt;5. Can we do better by picking the right group size (again)?&lt;/h2&gt;
&lt;p&gt;We previously showed in part 2 that the
ideal number of people in each group is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msqrt&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msqrt&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p = \sqrt{\frac{N}{k}}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.84em;vertical-align:-0.5913em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord sqrt&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.2487em;&quot;&gt;&lt;span class=&quot;svg-align&quot; style=&quot;top:-3.8em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.8em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;padding-left:1em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.345em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2087em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.8em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;hide-tail&quot; style=&quot;min-width:1.02em;height:1.88em;&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;400em&quot; height=&quot;1.88em&quot; viewBox=&quot;0 0 400000 1944&quot; preserveAspectRatio=&quot;xMinYMin slice&quot;&gt;&lt;path d=&quot;M983 90
l0 -0
c4,-6.7,10,-10,18,-10 H400000v40
H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7
s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744
c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30
c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722
c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5
c53.7,-170.3,84.5,-266.8,92.5,-289.5z
M1001 80h400000v40h-400000z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.5913em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.
However, that calculation hinges on the assumption
that there is only one level of grouping before we test each person individually.
This isn&#39;t the case now, since we have many levels
(specifically it&#39;s &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi&gt;log&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\log_2 \frac{N}{p}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3534em;vertical-align:-0.4811em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop&quot;&gt;lo&lt;span style=&quot;margin-right:0.0139em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.207em;&quot;&gt;&lt;span style=&quot;top:-2.4559em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2441em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4811em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; levels,
since we halve the number of people in a (sub)group after each test).&lt;/p&gt;
&lt;p&gt;What is the new ideal group size &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;?
Because we halve the size of the group each time,
we need (at most) &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi&gt;log&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\log_2 \frac{N}{p} + 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3534em;vertical-align:-0.4811em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop&quot;&gt;lo&lt;span style=&quot;margin-right:0.0139em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.207em;&quot;&gt;&lt;span style=&quot;top:-2.4559em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2441em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4811em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests per infected individual.
And since there are &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; infected individuals,
we need a total of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi&gt;log&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G + k (\log_2 \frac{N}{p} + 1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3534em;vertical-align:-0.4811em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop&quot;&gt;lo&lt;span style=&quot;margin-right:0.0139em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.207em;&quot;&gt;&lt;span style=&quot;top:-2.4559em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2441em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4811em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; tests:
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; initial tests, then
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mrow&gt;&lt;mi&gt;log&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;/mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\log_2 \frac{N}{p} + 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3534em;vertical-align:-0.4811em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop&quot;&gt;lo&lt;span style=&quot;margin-right:0.0139em;&quot;&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.207em;&quot;&gt;&lt;span style=&quot;top:-2.4559em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2441em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4811em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
individual tests.
Using differentiation
we find that the optimal number of people in each partition,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, is given by&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mfrac&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*} = \frac{N}{k}.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9331em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7387em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.0463em;vertical-align:-0.686em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Note how it is the &lt;em&gt;square&lt;/em&gt; of the previous value&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msubsup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mrow&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;/mrow&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msubsup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msqrt&gt;&lt;mfrac&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msqrt&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*}_{old} = \sqrt{\frac{N}{k}}.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9857em;vertical-align:-0.247em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7387em;&quot;&gt;&lt;span style=&quot;top:-2.453em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.247em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.44em;vertical-align:-0.769em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord sqrt&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.671em;&quot;&gt;&lt;span class=&quot;svg-align&quot; style=&quot;top:-4.4em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:4.4em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot; style=&quot;padding-left:1em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.631em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:4.4em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;hide-tail&quot; style=&quot;min-width:1.02em;height:2.48em;&quot;&gt;&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;400em&quot; height=&quot;2.48em&quot; viewBox=&quot;0 0 400000 2592&quot; preserveAspectRatio=&quot;xMinYMin slice&quot;&gt;&lt;path d=&quot;M424,2478
c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514
c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20
s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121
s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081
l0 -0c4,-6.7,10,-10,18,-10 H400000
v40H1014.6
s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185
c-2,6,-10,9,-24,9
c-8,0,-12,-0.7,-12,-2z M1001 80
h400000v40h-400000z&quot;/&gt;&lt;/svg&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.769em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Importantly, this new group size is larger than the previous group size,
which makes a lot of intuitive sense.
Remember that the fundamental group size trade-off is that if you
make your group size too large, you will expend a lot of tests
testing every one individually (subgroups of 1).
But in our refinements of the method we have managed to use fewer tests
by choosing the right subgroup size.
The optimal group size therefore increases.
(And for our case of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1000&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N = 1000&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k = 3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
the optimal group size is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;333&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*}=333&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;333&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;h2 id=&quot;6.-depth-first-search%3A-should-we-%22reset%22-the-search-after-we&#39;ve-found-an-infected-person%3F&quot; tabindex=&quot;-1&quot;&gt;6. Depth-first search: should we &amp;quot;reset&amp;quot; the search after we&#39;ve found an infected person?&lt;/h2&gt;
&lt;p&gt;Previously, we were testing all 50 groups of 20 before testing the 12 groups of 5,
and testing all the 12 groups of 5 before testing the 6 groups of 2 or 3.&lt;/p&gt;
&lt;p&gt;There is another way to do it, though.
We could test groups of 20 until we find a group of 20 that tests positive.
Once we find a positive group of 20 we test groups of 5 from that 20
until we find a group of 5 that tests positive,
and from that group test the groups of 2 and 3, and so on.
Only when we find an infected individual do we go back up a level.&lt;/p&gt;
&lt;p&gt;Here&#39;s an illustration of what that looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/group_testing/depth_first_search.png&quot; alt=&quot;Depth-first search&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is called &lt;em&gt;breadth-&lt;/em&gt; vs &lt;em&gt;depth-&lt;/em&gt; first search.
In breadth-first search, we explore all groups of the same size before exploring
groups of smaller sizes (i.e. deeper levels). But in depth-first search, we
make our way to the first infected person as quickly as possible, before
backtracking to find the next infected person, and so on.&lt;/p&gt;
&lt;p&gt;Does it matter whether we use depth- or breadth-first search?
It turns out that depth-first search opens up some further
optimisations.
The idea is that once we find the first infected individual
we can stop and &amp;quot;reset&amp;quot; the search, using fewer tests overall.&lt;/p&gt;
&lt;p&gt;Suppose we conduct our tests, using the depth-first search procedure,
pausing just after we have identified the first infected individual
(in our example, it is the 13th person).
But note here that we have no information whatsoever
about the people behind the 13th person.
More specifically, we know that persons 1 to 12 are not infected,
and (of course) that person 13 is infected,
but we don&#39;t know anything about whether any of the subsequent people are infected.
This is because subsequent infected people don&#39;t
affect any of the test results obtained so far by the procedure.
This means that persons 14 to N are
&lt;em&gt;as likely to be infected as any other person we haven&#39;t tested&lt;/em&gt;:
it is as if we never did any tests on them at all.&lt;/p&gt;
&lt;p&gt;In our current procedure, after finding that the 13th person is infected,
we backtrack and test the 14th and 15th persons together (size 2)
then back out further and test the 16th to 20th person (size 5).
But if you think about it,
since persons 14 to 20 are as likely to be infected as
any other person we haven&#39;t tested,
we have no information about the 14th to 20th people,
and as such have no reason to test them in small groups.
You can think of it like the 13th person being positive
&amp;quot;polluted&amp;quot; the group test of 20 people.&lt;/p&gt;
&lt;p&gt;For this reason, if you did actually test the groups [14, 15] and [16, 20],
both two tests will very likely be negative!
And this is inefficient: it&#39;s similar to doing individual testing
when we know that most people will test negative.&lt;/p&gt;
&lt;p&gt;What should we do, then?
The key insight here is to &amp;quot;reset&amp;quot; the search.
Since persons 14 to N are equally likely to be infected,
we arrive at a smaller instance of the same original problem ---
there are &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1000&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;13&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;987&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1000-13=987&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;987&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; people that we want to test,
of which &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3-1 = 2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; of them are infected!
It then follows that we should perform an identical procedure
on these remaining people ---
we recalculate the new value of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;G&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (and hence &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;),
and proceed with the procedure with those new values.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;All the optimisations lead you to the final, optimal algorithm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Set the optimal group size as &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p = N/k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.
Pick the first &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; people, group them together and test them.&lt;/li&gt;
&lt;li&gt;If that group tests negative, remove all of these people, and repeat the
algorithm with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; now set to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N-p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;If that group tests positive, take a subgroup of the first half of those people and
test them:
&lt;ul&gt;
&lt;li&gt;If that subgroup tests negative, clear them and test the first half of the other subgroup.&lt;/li&gt;
&lt;li&gt;If that subgroup tests positive, test the first half of the subgroup.&lt;/li&gt;
&lt;li&gt;In either case, repeat this process until we get to a single person.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Remove all the people before and including the first positive person,
repeating the algorithm and setting &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; appropriately. Repeat this
process until everyone has been cleared or quarantined.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;You smugly file the optimal algorithm away,
content in the knowledge that you&#39;ll be able
to appease your boss and exceed your KPIs
for many months to come. You&#39;re feeling very clever with yourself,
but unbeknownst to you
Hwang (1972) beat you to it almost fifty years ago with his paper
&lt;em&gt;A Method for Detecting All Defective Members in a Population by Group Testing&lt;/em&gt;
(maybe you should have studied something useful instead of PPE).
Over the next few months you spend your working hours
writing florid poetry on the human condition,
slowly moulding yourself into the Tang dynasty bureaucrat-poet
all AOs surely aspire toward becoming.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;THE END&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post we went through Hwang&#39;s 1972 algorithm,
which allows us to find
all the people who test positive for a disease
using only a small number of tests.&lt;/p&gt;
&lt;p&gt;We kickstarted our intuition by realising that
we can group people and test them together.
If the number of positive people is small
most of these groups will come back negative
(and thus no further testing is necessary).
This gave us a large decrease in the number of tests needed.&lt;/p&gt;
&lt;p&gt;We further improved the method by noting that
i) we can split groups into subgroups, sub-subgroups etc.
when a group tests positive, and
ii) the best way to split a group that tests positive
is into two groups of half the size.&lt;/p&gt;
&lt;p&gt;Finally, we showed that we simply arrive at a smaller instance
of the same original problem once we find a positive person,
and it is optimal to simply &amp;quot;reset&amp;quot; the search with
smaller values of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
rather than continue to split the groups/subgroups in the original search.&lt;/p&gt;
&lt;p&gt;There are a few possible extensions to this piece.
For instance, what if tests are noisy
(they sometimes give false positives/negatives)?
Then you can never have certainty, only a certain
posterior probability.
Also, this algorithm runs serially, not in parallel.
You have to wait for the results of the group tests
before testing the subgroups.
What if (due to time constraints)
you&#39;re not allowed to do that?
Is there a better algorithm?
What if you&#39;re allowed to do at most e.g. 3 rounds of tests?
Can we find an algorithm that allows us
to specify a tradeoff between the number
of test kits needed verus the number of &amp;quot;rounds&amp;quot; of tests?
Please let me know if you are interested in reading posts
on these extensions,
or have any suggestions for improvement.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;I worked on this piece together with
&lt;a href=&quot;https://bernardteo.me/&quot;&gt;Bernard Teo Zhi Yi&lt;/a&gt;.
The idea for this post came from Bernard,
who is currently writing his thesis on group testing.
He is very much the brains behind this piece.&lt;/p&gt;
&lt;p&gt;A big thanks to &lt;a href=&quot;https://www.robertheaton.com/&quot;&gt;Robert Heaton&lt;/a&gt;
for reading a draft of this work and providing
very valuable comments.
Thanks also to CKY, Ed, Nick, Celine, Wilfred,
and Joy for reading early drafts of this piece and
giving me helpful comments.&lt;/p&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;h3 id=&quot;why-halving-the-group-size-each-time-is-optimal&quot; tabindex=&quot;-1&quot;&gt;Why halving the group size each time is optimal&lt;/h3&gt;
&lt;p&gt;Each group that tests positive is quite likely to have only one infected individual,
because there are more groups than infected individuals.
Suppose you rolled twenty 100-sided dice (d100):
the odds of getting one
100 is quite rate, but the odds of getting two or more 100s
is vanishingly unlikely.
In the same way,
since an individual is very unlikely to have the virus,
it is quite rare for a group to have an infected person,
and extremely rare for a group to have two (or more) infected people.&lt;/p&gt;
&lt;p&gt;Let&#39;s assume for now that each group that tests positive
has exactly one infected individual.
Our objective, then, is to determine which one of the 20 people
in this group is infected with the minimum number of tests,
and this is optimally done by halving the group size each time.&lt;/p&gt;
&lt;p&gt;To see why halving the group size each time
consider what would happen if we first
conducted a test on 5 (instead of 10) of the 20 people in the group.
If the test comes back positive, then we get to eliminate a whopping 15 people!
But if the test comes back negative, then we can only eliminate 5 people.
On average, then, what is the number of people that we will get to eliminate?&lt;/p&gt;
&lt;p&gt;If you&#39;ve answered &amp;quot;10 people&amp;quot;, that&#39;s unfortunately wrong.
Since the infected individual has an equal chance
of being each of the 20 people in the group,
it is more likely that the the infected individual
is in the untested 15 remaining people
rather than the 5 people we conducted a test on.
This means that it&#39;s more likely that
we will only get to eliminate 5 people, rather than 15.
As such, the average number of people
that we get to eliminate is less than 10.&lt;/p&gt;
&lt;p&gt;We may make a similar argument if
15 people are chosen for the first test, instead of 5 or 10.
The average number of people that we get to eliminate
will also be less than 10.&lt;/p&gt;
&lt;p&gt;Hence, testing exactly half of the group
is the most efficient way to narrow down the group size.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Note that this method doesn&#39;t rely on knowing exactly how many people have the virus, only the expected value. If you knew that there were EXACTLY three people you could stop once you found three positives. For ease of exposition we illustrate an example where there are exactly 1,000 travelers and exactly 3 positive cases, but the method and the probabilities are very similar even if we work with expected values instead. &lt;a href=&quot;https://lieuzhenghong.com/group_testing/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You can achieve an effective group size of 18.5 by having groups of 18 and 19. &lt;a href=&quot;https://lieuzhenghong.com/group_testing/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>From Third World to Utopia: Singapore could end poverty for our children forever, today</title>
    <link href="https://lieuzhenghong.com/a_ubi_for_singapore/"/>
    <updated>2021-01-18T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/a_ubi_for_singapore/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;If the Singapore government earmarked $200,000 for each child
at birth and let it grow until the child turned 18
before dispensing it, we could guarantee a basic income of
~$800 (inflation-adjusted!) every month in perpetuity
without ever depleting the capital.&lt;/p&gt;
&lt;p&gt;As the birth rate is 40,000 a year,
guaranteeing such a basic income to all future children
would cost the government 8 billion a year.
Better yet, since the capital is never depleted,
the capital from the first cohorts can be &amp;quot;recycled&amp;quot;
for future cohorts once the first cohorts die out.
The total cost is therefore bounded at $800 billion dollars
(8 billion * 100 years lifespan).&lt;/p&gt;
&lt;p&gt;I won&#39;t devote too much space here to defending a UBI;
these arguments have been covered elsewhere.
This essay aims to show that a UBI is actually well within our reach;
I&#39;ll punt on the question on whether we&#39;d want it to others.
But if UBI really is as wonderful as its proponents say,
and it &lt;em&gt;is&lt;/em&gt; within our reach,
we might just be one step from Eden.&lt;/p&gt;
&lt;h2 id=&quot;the-theory&quot; tabindex=&quot;-1&quot;&gt;The theory&lt;/h2&gt;
&lt;p&gt;Money makes money.
If you put your money in the stock market or in bonds
your money will always grow &lt;em&gt;in the long run&lt;/em&gt;.
So if you have a large enough sum of money
you can withdraw a small enough sum of money
such that the growth rate of your money exactly equals
your withdrawal rate plus inflation.
This means that that initial sum of money could theoretically
last forever--ergo, a BI.&lt;/p&gt;
&lt;p&gt;One glaring problem with this strategy is volatility:
unfortunately, stonks don&#39;t always go up.
However, we know that if you wait long enough
stonks &lt;em&gt;do&lt;/em&gt; always go up (in recorded history).
And so the initial losses can be made back by future gains
as long as your withdrawal rate is low enough.
The good news is that pension funds and
people who aim to retire early run these calculations all the time.
&lt;a href=&quot;https://earlyretirementnow.com/2016/12/14/the-ultimate-guide-to-safe-withdrawal-rates-part-2-capital-preservation-vs-capital-depletion/&quot;&gt;Early Retirement Now&lt;/a&gt;
find that over all 60 year time horizons a portfolio with 75--100% equities
always manages capital preservation (if not growth).
And in fact our government has it easier than this because
sequence of returns risk is greatly reduced
since the government is always both withdrawing (for older cohorts)
and investing (for younger cohorts)
at the same time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/ubi_for_singapore/swr.png&quot; alt=&quot;A 3% safe withdrawal rate always preserves capital over a 60 year time horizon&quot;&gt;&lt;/p&gt;
&lt;p&gt;So, in detail: if the government constitutionally guaranteed a
3% real interest rate (similar to what it does for CPF)
for 18 years, $200,000 at year 0 would become $330,569
in year 18 (after adjusting for inflation).
This would allow a withdrawal of $9,917 a year, or $826 a month.
And this capital would never be touched.
On death, the capital would be clawed back by the government,
ready to be endowed to the next person.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/ubi_for_singapore/excel.png&quot; alt=&quot;Path of investment income&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;can-we-afford-it%3F&quot; tabindex=&quot;-1&quot;&gt;Can we afford it?&lt;/h2&gt;
&lt;p&gt;How much is 8 billion? It sounds like a lot,
but it&#39;s not that much, really.
Singapore collected 2.6 billion in betting taxes alone
(wild! I wonder how much comes from Singapore Pools and how much the casinos).
Singapore collected 11.2 billion in GST,
12.4 billion in income taxes,
and 16.7 billion in corporate taxes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/ubi_for_singapore/tax_revenue.jpg&quot; alt=&quot;Tax revenue in 2020&quot;&gt;&lt;/p&gt;
&lt;p&gt;And our net investment returns contribution (NIRC)
from our reserves last year was
&lt;a href=&quot;https://thekopi.co/2020/04/12/singapore-reserves-explained/&quot;&gt;18.63 billion&lt;/a&gt;.
This is half of our long-term expected real return.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Net Investment Returns Contribution (NIRC) to the government budget
consists of two parts: up to 50% of the Net Investment Returns (NIR) on the
net assets invested by GIC, MAS and Temasek Holdings, and up to 50% of the Net
Investment Income (NII) derived from Past Reserves from the remaining assets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The government put in 6 billion to the GST Voucher Fund last year.
As the GST Voucher Fund is a permanent one,
the government is likely to continue contributing that amount to the fund.&lt;/p&gt;
&lt;p&gt;I really like the idea of the GST Voucher Fund (it&#39;s kinda-sorta UBI-lite).
But if 6 billion for the GST Voucher Fund sounds good,
how does 8 billion for the
&lt;em&gt;Free Money For Life For Everyone Born After 2021 Forever Fund&lt;/em&gt;
sound?&lt;/p&gt;
&lt;h2 id=&quot;why-not-a-more-targeted-welfare-programme%3F&quot; tabindex=&quot;-1&quot;&gt;Why not a more targeted welfare programme?&lt;/h2&gt;
&lt;p&gt;We can and should certainly do more for the bottom 10-20% of Singaporeans.&lt;/p&gt;
&lt;p&gt;But I think there are political reasons why this might be more popular.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TODO: To flesh out here.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Something about universality being more popular
Give the example of the UK&#39;s NHS being popular with the rich
even though they are certainly paying more than they would
under a privatised healthcare system
Another point: we have to have a dream;
a dream that excites people and gets them on board.
Targeted welfare doesn&#39;t sound like a dream;
ending poverty for our children does.&lt;/p&gt;
&lt;h2 id=&quot;why-give-money-to-the-unborn-and-not-the-people-who-desperately-need-it-now%3F&quot; tabindex=&quot;-1&quot;&gt;Why give money to the unborn and not the people who desperately need it now?&lt;/h2&gt;
&lt;p&gt;Three reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The yet-unborn are going to have to bear a greater burden
because of our shrinking population;&lt;/li&gt;
&lt;li&gt;We can&#39;t quite afford to give UBI to everyone;&lt;/li&gt;
&lt;li&gt;Parents spend a lot of time thinking,
talking, and worrying about their children,
so helping the children will help the parents.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;TODO: To flesh out here.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;will-a-ubi-not-encourage-indolence%3F&quot; tabindex=&quot;-1&quot;&gt;Will a UBI not encourage indolence?&lt;/h2&gt;
&lt;p&gt;There&#39;s not enough research on UBI.
But as far as the research shows,
disincentives to work are minor.&lt;/p&gt;
&lt;p&gt;But even if it did: what&#39;s wrong with indolence?
Is our work-life balance today healthy?
Should we have to put up with working 60-hour weeks and weekends?
Don&#39;t we want our children be able to spend more time with &lt;em&gt;their&lt;/em&gt; children?
Isn&#39;t this something we should fight for?&lt;/p&gt;
&lt;h2 id=&quot;a-ubi-isn&#39;t-a-panacea&quot; tabindex=&quot;-1&quot;&gt;A UBI isn&#39;t a panacea&lt;/h2&gt;
&lt;p&gt;I might have overpromised: it&#39;s not going to solve poverty.
You&#39;d still want comprehensive medical coverage
(mandatory health insurance) for every citizen at the minimum.&lt;/p&gt;
&lt;p&gt;But it&#39;d go a long way:
be it not having to be in arrears
not worrying about not being able to make the rent of your rental flat,
being able to afford the $500 co-pay (after MediSave deduction)
of your cataract surgery...&lt;/p&gt;
&lt;h2 id=&quot;what-would-it-take-to-give-every-citizen-a-ubi%3F&quot; tabindex=&quot;-1&quot;&gt;What would it take to give every citizen a UBI?&lt;/h2&gt;
&lt;p&gt;35 billion annual payment forever, or 1.2 trillion set aside as a one-time payment.
Our annual government revenue is 50b (with 18b NIRC),
and we have maybe ~1 trillion as reserves,
so we&#39;d either need to double our reserves
or devote all our reserves to UBI,
which would not be financially or politically feasible.&lt;/p&gt;
&lt;p&gt;The nice thing about this plan is that it&#39;s a &amp;quot;ramp up plan&amp;quot;:
it basically gives a small percentage of the population
(those born in or after year X) a UBI every year.
Eventually all people will be born in or after year X,
and everyone will have a UBI.&lt;/p&gt;
&lt;h2 id=&quot;reference&quot; tabindex=&quot;-1&quot;&gt;Reference&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ssir.org/books/reviews/entry/income_for_all&quot;&gt;Income for All&lt;/a&gt;
&lt;a href=&quot;https://basicincome.stanford.edu/uploads/Umbrella%20Review%20BI_final.pdf&quot;&gt;Stanford BI Umbrella Review&lt;/a&gt;
&lt;a href=&quot;https://ink.library.smu.edu.sg/cgi/viewcontent.cgi?article=1115&amp;amp;context=lien_research&quot;&gt;Measuring Poverty in Singapore&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Radically new ways of living and working are for the first time available (again) to us</title>
    <link href="https://lieuzhenghong.com/new_ways_of_living_and_working/"/>
    <updated>2021-01-10T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/new_ways_of_living_and_working/</id>
    <content type="html">&lt;ul&gt;
&lt;li&gt;https://levels.io/coworking-space-economics/&lt;/li&gt;
&lt;li&gt;https://levels.io/the-greatest-migration/&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Joe Rogan moved from Los Angeles to Austin, Texas this year. And as an influential person in his community, he was able to bring a big share of his friends of comedians and other celebrities over to Austin too.&lt;/p&gt;
&lt;p&gt;Kanye West bought a $14 million dollar, 6,000-acre ranch in Wyoming and is building an eco-village with a farm, houses and schools where his kids will go. And there&#39;s more famous people who are planning the same.&lt;/p&gt;
&lt;p&gt;The founder of Bali&#39;s most popular coworking space Dojo bought land north from Canggu near the beach and is building his own village. It will focus on creative, entrepreneurial, maker-type people and will feature tens of bungalow-style apartments, coworking spaces, a maker space and since it&#39;s in Bali: probably lots of swimming pools.&lt;/p&gt;
&lt;p&gt;The idea with all of these is the same: get out of cities that feel isolating (think of Los Angeles&#39; giant sprawl) and move to a place where you can be physically closer to your community of people: being able to walk to each other, instead of an hour car ride away.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&#39;s decoupling, right? Key SWE principle. The best place to work is not always the best place to live (the tails come apart). And for the first time we can decouple these two things where previously you had to live where you worked.&lt;/p&gt;
&lt;p&gt;We probably shouldn&#39;t start a cult of our own:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;And if the communes of the 1960s taught us anything: it&#39;s that trying to re-invent society by building a new mini society in a village usually doesn&#39;t work out and sometimes even ends bad:&lt;/p&gt;
&lt;p&gt;The 1960s teaches us we maybe the point isn&#39;t to try build entirely new artificially designed communities from the ground up, but instead iterate on the places that organically rise up for remote workers, improve them and solve the problems remote workers there have.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;but I can see things like again trying to disconnect a little (but not completely!!) from the rest of society. There are two key takeaways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In some sense I think we lose a lot when we scale up —&amp;gt; food/agriculture, schooling, etc. I learned so much from my tutors in Oxford because I had concentrated 1 to 1 time with them: qualitatively different from what a lecture or tutorial can give. In that vein i believe it&#39;s better to teach our children ourselves (or in a small collaborative team) rather than ship them over to school with 25 other children. Ditto with food: Big Ag optimises for shelf stability, size, aesthetics, but not for nutrition, taste, or healthfulness. The trade-off here is time/efficiency, but since we as a society are wealthier than ever before, it might be a good idea to make this tradeoff.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I think it&#39;s important to live in a community where you live near (walking distance to) all your friends. I think that was why I was so happy in Oxford. As I&#39;ve mentioned before, I think the nuclear family + single-family home is a Bad Idea, not just because no man (or family) is an island, but also because it really prevents people from living walking distance from one another.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  <entry>
    <title>Planning to build a Discord spatial layer</title>
    <link href="https://lieuzhenghong.com/planning_to_build_discord_server_layer/"/>
    <updated>2021-01-06T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/planning_to_build_discord_server_layer/</id>
    <content type="html">&lt;h2 id=&quot;mvp&quot; tabindex=&quot;-1&quot;&gt;MVP&lt;/h2&gt;
&lt;p&gt;build a browser extension that edits the
discord web client UI to include a canvas element&lt;/p&gt;
&lt;p&gt;this canvas element should contain a multiplayer 2D environ&lt;/p&gt;
&lt;p&gt;minimally, players should be able to move around the space
with the arrow keys
and this should update in real time
(client-side prediction optional)&lt;/p&gt;
&lt;p&gt;we should include SOME minimal discord integration element
in the MVP to showcase its potential.
i&#39;m not sure what form this would take,
building a discord bot is probably too time-consuming&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-the-point%3F&quot; tabindex=&quot;-1&quot;&gt;what&#39;s the point?&lt;/h2&gt;
&lt;p&gt;how is it different from gathertown, second life, minecraft?&lt;/p&gt;
&lt;p&gt;my thought: discord servers are already
communities, with chill VC hangout rooms and the like
we want to piggyback on this community,
not try to supplant it.
the only way we can get adoption is
for people to use our software is to piggyback
on an existing platform that people already like using.
that&#39;s the main hurdle facing all the YC startups
like gathertown rn i believe&lt;/p&gt;
&lt;p&gt;also, discord allows us to write bots
and there is already lots of bot games on discord
that people enjoy playing:
adding a spatial layer might be compelling to the
demographic that likes playing botgames on discord.&lt;/p&gt;
&lt;h2 id=&quot;what-needs-to-be-done%3F&quot; tabindex=&quot;-1&quot;&gt;what needs to be done?&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;check discord API:
find a way for a our game to see which discord server its in
and get a list of all the people in the server
and a way to make sure that a user owns/controls
his character&lt;/li&gt;
&lt;li&gt;actual game state sync&lt;/li&gt;
&lt;li&gt;canvas rendering of gameworld and players&lt;/li&gt;
&lt;li&gt;handle player input (update state)&lt;/li&gt;
&lt;li&gt;modify discord web client to include our canvas&lt;/li&gt;
&lt;li&gt;package up as browser extension?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;these can be done in parallel
(figuring out how to share and update state,
figuring out how to render game state,
figuring out how to modify the web client)
which makes it ideal for hackathon&lt;/p&gt;
&lt;h2 id=&quot;technical-unknowns&quot; tabindex=&quot;-1&quot;&gt;Technical unknowns&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;How do we get a list of all the people in the server?
is there a Discord API?&lt;/li&gt;
&lt;li&gt;think about how a server admin would set up
and reset the game state&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;further-extensions&quot; tabindex=&quot;-1&quot;&gt;further extensions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;allow players to customise their avatar&lt;/li&gt;
&lt;li&gt;grab text messages and display inside client&lt;/li&gt;
&lt;li&gt;allow text commands to mutate gamestate&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Worlds for hyperlocal communities</title>
    <link href="https://lieuzhenghong.com/gameworlds_for_hyperlocal_communities/"/>
    <updated>2021-01-06T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/gameworlds_for_hyperlocal_communities/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Main idea: a game world that acts as a thin &amp;quot;spatial layer&amp;quot;
above any Discord server.&lt;/p&gt;
&lt;p&gt;Players can walk around the game world which is basically just a 2D grid.
It&#39;s a very &amp;quot;thin&amp;quot; extra layer over any Discord server:
we&#39;d hook into the Discord API to send and receive chat messages
so all messages would go through the Discord server.
Using this &amp;quot;spatial layer&amp;quot; would be completely optional:
a person using the &amp;quot;spatial layer&amp;quot; can talk with someone
who is just using the regular Discord client.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT:&lt;/strong&gt; we could do a browser extension piggybacking on the Discord
web client.
See screenshots:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/gameworlds_for_hyperlocal_communities/original.png&quot; alt=&quot;What the web client is like now&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/gameworlds_for_hyperlocal_communities/game_overlay.png&quot; alt=&quot;What the web client could be&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-point%3F&quot; tabindex=&quot;-1&quot;&gt;What is the point?&lt;/h2&gt;
&lt;p&gt;Humans are naturally spatial creatures.
There&#39;s something about having an avatar in a physical space
that cannot be replicated with just text.
WN and I were talking about why people
like hanging out in MapleStory and just chat?
I believe hanging out in Maple is compelling
because it has something more than just chat:
you can express yourself with your movement,
fashion choices, your skills, your facial emotions.
We want to bring this spatial richness to existing communities.&lt;/p&gt;
&lt;p&gt;It&#39;s not easy to make friends on Discord or in Hack N Roll
(you usually just stick to yourself or your hacker group)
and the spatial component of this &amp;quot;Hack N Roll Game World&amp;quot;
might make a world of difference:
it helps discovery/sociality when you can walk up to an avatar and
just chat with them in the public channel, or DM them.
I believe it would increase the sense of community and encourage making friends.
Not everyone will find this compelling, but I think I would.&lt;/p&gt;
&lt;h2 id=&quot;extensions&quot; tabindex=&quot;-1&quot;&gt;Extensions&lt;/h2&gt;
&lt;p&gt;We might want to give players of this gameworld something to do:
the equivalent of Maki Bot in Discord servers.&lt;/p&gt;
&lt;p&gt;Different servers would have different tilesets (like server-specific emoji)
and construct their gameworld differently.
One server might use a generic tileset to build a massive mediaeval castle
while another might use a cyberpunk-inspired tileset to build Night City.
This would allow for easy customisation of the space.&lt;/p&gt;
&lt;p&gt;It would be really cool if we could allow fellow HnR participants
to code their own equivalent of Bots:
maybe expose some API where we allow squares and players to have
arbitrary metadata associated with them,
and allow getters and setters on that arbitrary metadata.&lt;/p&gt;
&lt;p&gt;At the most basic and boring level, for instance,
a bot could be written to assign players a &amp;quot;Fame&amp;quot; score (just an integer).
And players could interact by faming or defaming other players.
But more complicated interactions could exist.
What if a bot assigned each square a &lt;code&gt;terrain&lt;/code&gt; metadata type
and you could fish on squares with &lt;code&gt;terrain:water&lt;/code&gt;?
This would be an API call to a Discord bot
which would then update your player&#39;s &lt;code&gt;inventory&lt;/code&gt; metadata field
to have a random fish?
What if you wrote a bot that could trade items between players?
There are tons of possibilities.&lt;/p&gt;
&lt;h2 id=&quot;why-not-just-play-an-mmo%3F-or-use-second-life%3F&quot; tabindex=&quot;-1&quot;&gt;Why not just play an MMO? Or use Second Life?&lt;/h2&gt;
&lt;p&gt;(WIP section)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A discord server is already a community and you want to
build something on top of it, not try to transplant/supplant
the existing community&lt;/li&gt;
&lt;li&gt;zero friction is important! how can you possibly convince
everyone in your server to move to a game&lt;/li&gt;
&lt;li&gt;very lightweight layer not a entire game is a feature&lt;/li&gt;
&lt;li&gt;the layer is completely optional so you can
still have the same community even when not in the game&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;issues&quot; tabindex=&quot;-1&quot;&gt;Issues&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Building a game world where people can move around in in real time
might be too difficult/technically challenging&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-stuff-we-could-do&quot; tabindex=&quot;-1&quot;&gt;Other stuff we could do&lt;/h2&gt;
&lt;p&gt;This is an instantiation of the following meta-level principle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meta-level: build X ( tinder, facebook, twitter, a game world, etc... ) for a hyperlocal community (the HnR discord server, Telegram group)&lt;/li&gt;
&lt;li&gt;meta-meta-level: build Y that allows us to build some X for any hyperlocal community&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I like the meta idea of building something over the hyperlocal community.
Weineng suggested something like Tinder or FB but only for HnR participants.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Teleoperation: enabling remote work for nonremote workers</title>
    <link href="https://lieuzhenghong.com/teleoperation_remote_work/"/>
    <updated>2021-01-04T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/teleoperation_remote_work/</id>
    <content type="html">&lt;p&gt;&lt;a href=&quot;https://medium.com/starsky-robotics-blog/the-poor-roi-of-autonomy-f5d6f4f2dd14&quot;&gt;The Poor ROI of Autonomy&lt;/a&gt;
TL;DR: you don&#39;t really need full autonomous driving,
even teleoperation
(let drivers drive the trucks remotely from home)
is a big win
because drivers no longer have to sit around while their trucks are being unloaded
and they can sleep at home instead of in their cabs.&lt;/p&gt;
&lt;p&gt;This got me thinking whether we can do teleoperation
with other stuff as well.
Obviously we have those system whereby a very expensive
surgeon teleoperates on a patient,
but can we scale down the market?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/qGE-deYfb8I&quot;&gt;YouTube video demonstrating teleoperation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Can we have a very cheap robotic arm system that can be
mounted on a desk or some sort of factory floor
and allow people to work at factories via remote control?&lt;/p&gt;
&lt;p&gt;Any sort of job where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you need something to be physically effected&lt;/li&gt;
&lt;li&gt;range of motion is confined to a table&lt;/li&gt;
&lt;li&gt;no human contact necessary&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;this would allow handicapped workers to contribute to
the economy
you could also employ NEETs and people from other countries&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The cheater&#39;s chessboard</title>
    <link href="https://lieuzhenghong.com/cheaters_chessboard/"/>
    <updated>2021-01-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/cheaters_chessboard/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The idea is to build a custom chessboard
that looks like a regular chessboard
(with maybe clock at the side for time games)
but can actually read the state of the board,
calculate the best move,
and secretly leak information about the best move
to a player in the know.&lt;/p&gt;
&lt;h2 id=&quot;how-we&#39;d-do-it&quot; tabindex=&quot;-1&quot;&gt;How we&#39;d do it&lt;/h2&gt;
&lt;p&gt;We&#39;d have to wire up a Hall effect sensor for each square.
A Hall effect sensor is like a reed switch
which can detect the presence of a magnetic field.&lt;/p&gt;
&lt;p&gt;The idea is that when the piece is lifted up,
the circuit will cut off (0)
amd when the piece is put down,
the circuit will close again (1).&lt;/p&gt;
&lt;p&gt;We won&#39;t be able to distinguish between pieces,
but we will be able to guess it by assuming that the board is set up
in the correct position at the start.&lt;/p&gt;
&lt;p&gt;So for example if we detect that e2 square cuts off, then shortly after
e4 square cuts on, it&#39;s most probably e2e4 move.
We will have to handle things like castling, en passant, promotion
(especially hard because a pawn can promote to any piece).&lt;/p&gt;
&lt;p&gt;We would then feed this board state to a Raspi mounted
within the chessboard, which would use a chess engine to calculate
the best move and leak information to the player
in a surreptitious way.&lt;/p&gt;
&lt;h2 id=&quot;how-do-we-leak-information%3F&quot; tabindex=&quot;-1&quot;&gt;How do we leak information?&lt;/h2&gt;
&lt;p&gt;We need to leak information in a sneaky way
Basically if you think about it we need to leak 12 bits:
6 bits starting square and 6 bits ending square uniquely determine
any move (except pawn promotion, but we can worry about that later).
For castling you can talk about the position of the King
(moving two or three squares).&lt;/p&gt;
&lt;p&gt;My idea is that we have clocks on either side of the board
which act as time controls,
but they will leak the information somehow,
either by a different border thickness/
brightness level/something else.&lt;/p&gt;
&lt;h2 id=&quot;links&quot; tabindex=&quot;-1&quot;&gt;Links&lt;/h2&gt;
&lt;p&gt;https://www.sparkfun.com/products/9312&lt;/p&gt;
&lt;p&gt;https://sites.google.com/site/bergersprojects/reedcb/programming&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Debugging my thesis</title>
    <link href="https://lieuzhenghong.com/debugging_my_thesis/"/>
    <updated>2020-12-25T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/debugging_my_thesis/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Since my undergraduate thesis was quite well-received,
I thought it would be a good idea to publish it.
To that end, Gabe and I have been working on my thesis.
As a replication check both of us ran the code on
our machines...
both of our laptops produced the same data but
they were different from the existing data
generated by my old laptop.&lt;/p&gt;
&lt;p&gt;In my thesis I generate 100,000 hypothetical districting plans,
calculate four different compactness metrics
(Polsby-Popper, Reock, Convex Hull, and my own Human Compactness)
and see how they correlate with a measure of district homogeneity
(Stephanopoulos&#39;s &amp;quot;spatial diversity&amp;quot; metric).
On our replication runs we observed the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spatial diversity metric unchanged&lt;/li&gt;
&lt;li&gt;Polsby-Popper, Reock, and Convex Hull very slightly changed
(around 1/10th of the values were different in the
11th or 12th decimal place)&lt;/li&gt;
&lt;li&gt;Big changes in human compactness metric
(from 0.7 to 0.9, that sort of thing)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This was pretty bad, and threatened to derail my research
completely&lt;/p&gt;
&lt;h2 id=&quot;what-wasn&#39;t-the-bug%3F&quot; tabindex=&quot;-1&quot;&gt;What wasn&#39;t the bug?&lt;/h2&gt;
&lt;h2 id=&quot;what-was-the-bug%3F&quot; tabindex=&quot;-1&quot;&gt;What was the bug?&lt;/h2&gt;
&lt;p&gt;Because I didn&#39;t freeze the environment,
we had to install the newest versions of the libraries.&lt;/p&gt;
&lt;p&gt;There is one line of code in &lt;code&gt;sample_rvps&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;all_rvps &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; all_rvps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_crs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;EPSG:4326&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which converts the initial shapefile to a new coordinate reference system (CRS).&lt;/p&gt;
&lt;p&gt;For some reason, the &lt;code&gt;to_crs&lt;/code&gt; function in the new setup
gives &lt;strong&gt;very&lt;/strong&gt; slightly different values, differing in the 11th or 12th decimal place.
You can see it in the snippet below:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;gdf &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gdf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_crs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;init&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;epsg:4326&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gdf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;geometry&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# on old machine: POINT (-73.59250979083568 41.01678126113871)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# This assert passes on my new machine but fails on my old one&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gdf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;geometry&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POINT (-73.59250974534255 41.01678109722333)&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;All asserts passed!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This alone wouldn&#39;t cause that much of a discrepancy,
but it just so happens that this tiny change causes
a point which was originally out of the state line
to be &lt;em&gt;in&lt;/em&gt; the state line.
This causes the points sampled by &lt;code&gt;sample_rvps&lt;/code&gt;
to change completely even with the same random seed,
because all the points have been shifted down 1.
Because the points have all changed,
all the precalculated point-kNN values are all incorrect
(because they were for different points).
And this leads to completely incorrect results.&lt;/p&gt;
&lt;p&gt;The other metrics all changed by a very very tiny amount.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;initial_partition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; GeographicPartition&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    graph&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    assignment&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;New_Seed&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    updaters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;cut_edges&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; cut_edges&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;population&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Tally&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;population&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; alias&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;population&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;spatial_diversity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; spatial_diversity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;calc_spatial_diversity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;human_compactness&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; partial&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            hc_utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;calculate_human_compactness&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            DURATION_DICT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            tract_dict&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            duration_matrix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;polsby_compactness&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; polsby_popper&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token string&quot;&gt;&quot;reock_compactness&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; partial&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state_shp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We know the EPSG conversion is very slightly different in the new state.
But there is no EPSG conversion in the Reock function!&lt;/p&gt;
&lt;p&gt;My best guess (but I haven&#39;t verified this)
is that there is an upstream change in how points are calculated.
The Reock function calls the &lt;code&gt;_generate_external_points&lt;/code&gt; subroutine
to find all external points of the Census tracts
so that it can draw the circumscribing circle of the district:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_generate_external_points&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; geoid_to_id_mapping&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&#39;&#39;&#39;
    For each Census Tract, generate the exterior points of that Tract
    &#39;&#39;&#39;&lt;/span&gt;
    exterior_points &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# print(row[&#39;geometry&#39;].geom_type)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;geometry&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;geom_type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;MultiPolygon&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; polygon &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;geometry&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            exterior_points &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;polygon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exterior&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coords&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;geometry&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;geom_type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Polygon&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        polygon &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;geometry&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        exterior_points &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;polygon&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exterior&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coords&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; exterior_points&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I believe there might be a difference with &lt;code&gt;polygon.exterior.coords&lt;/code&gt;.
Perhaps there&#39;s something in the getting points from a shapefile thing that has changed.
If the exterior points&#39; coordinates are very slightly different,
this will affect the Reock function.&lt;/p&gt;
&lt;h3 id=&quot;what-causes-polsby-popper-to-change%3F&quot; tabindex=&quot;-1&quot;&gt;What causes Polsby-Popper to change?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;TL;DR: I have no idea.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I dug into the
&lt;a href=&quot;https://gerrychain.readthedocs.io/en/latest/_modules/gerrychain/metrics/compactness.html#polsby_popper&quot;&gt;Gerrychain source code&lt;/a&gt;
to look at the Polsby-Popper function:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; math

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compute_polsby_popper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;area&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; perimeter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pi &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; area &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; perimeter &lt;span class=&quot;token operator&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; ZeroDivisionError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nan
                        
                        
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;polsby_popper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
    Computes Polsby-Popper compactness scores for each district in the partition.
        &quot;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        part&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; compute_polsby_popper&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            partition&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;area&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;part&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; partition&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;perimeter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;part&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; part &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; partition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parts
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It gets &lt;code&gt;area&lt;/code&gt; and &lt;code&gt;perimeter&lt;/code&gt; from the Partition object,
which takes in a graph, an assignment, and a list of updaters.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;10_Process_Tracts.py&lt;/code&gt; we have the following code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;state_graph &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Graph&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;from_geodataframe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state_tracts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ignore_errors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
state_graph&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add_data&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state_tracts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
state_tracts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_file&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;./Data/Shapefiles/Tract2000_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;fips&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.shp&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
state_graph&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;to_json&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;./Data/Dual_Graphs/Tract2000_&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;fips&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;.json&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the
&lt;a href=&quot;https://gerrychain.readthedocs.io/en/latest/api.html?highlight=GeographicPartition#gerrychain.Graph.from_geodataframe&quot;&gt;GerryChain docs for from_geodataframe&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creates the adjacency Graph of geometries described by dataframe. The areas of
the polygons are included as node attributes (with key area). The shared
perimeter of neighboring polygons are included as edge attributes (with key
shared_perim). Nodes corresponding to polygons on the boundary of the union of
all the geometries (e.g., the state, if your dataframe describes VTDs) have a
boundary_node attribute (set to True) and a boundary_perim attribute with the
length of this “exterior” boundary.
By default, areas and lengths are computed in a UTM projection suitable for
the geometries. This prevents the bizarro area and perimeter values that show
up when you accidentally do computations in Longitude-Latitude coordinates. If
the user specifies reproject=False, then the areas and lengths will be
computed in the GeoDataFrame’s current coordinate reference system. This
option is for users who have a preferred CRS they would like to use.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So the areas and perimeters of the polygons have already been pre-calculated
and saved.
As far as I can tell, the areas and perimeters of the polygons are not recalculated.
And there doesn&#39;t seem to be a reprojection either.
Why then can the Polsby-Popper metric still give a different result?&lt;/p&gt;
&lt;h2 id=&quot;questions-i-still-have&quot; tabindex=&quot;-1&quot;&gt;Questions I still have&lt;/h2&gt;
&lt;p&gt;Why does &lt;code&gt;to_crs&lt;/code&gt; give a very slightly different result?
I created an issue + minimum reproducible example and posted it on the
&lt;a href=&quot;https://github.com/geopandas/geopandas/issues/1748&quot;&gt;geopandas repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am almost certain it is not the fault of geopandas but rather some upstream
dependency. This is why &lt;code&gt;reock&lt;/code&gt; and &lt;code&gt;polsby-popper&lt;/code&gt; are affected as well.&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next&quot; tabindex=&quot;-1&quot;&gt;What&#39;s next&lt;/h2&gt;
&lt;h2 id=&quot;things-i-learned&quot; tabindex=&quot;-1&quot;&gt;Things I learned&lt;/h2&gt;
&lt;p&gt;Bit-by-bit replication should be done with &lt;code&gt;conda list -e &amp;gt; requirements.txt&lt;/code&gt;.
Not using &lt;code&gt;conda list -e&lt;/code&gt; or &lt;code&gt;pip freeze&lt;/code&gt; or the like
is a mistake that I won&#39;t make again.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
</content>
  </entry>
  <entry>
    <title>Report on CS107E Lab and Assignment 3</title>
    <link href="https://lieuzhenghong.com/stanford_cs107e_notes_lab_3_report/"/>
    <updated>2020-12-21T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/stanford_cs107e_notes_lab_3_report/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;h2 id=&quot;lab-3&quot; tabindex=&quot;-1&quot;&gt;Lab 3&lt;/h2&gt;
&lt;h2 id=&quot;writing-a-strcpy-function&quot; tabindex=&quot;-1&quot;&gt;Writing a &lt;code&gt;strcpy&lt;/code&gt; function&lt;/h2&gt;
&lt;p&gt;This was a pretty easy task&lt;/p&gt;
&lt;h3 id=&quot;debugging-with-gdb&quot; tabindex=&quot;-1&quot;&gt;Debugging with GDB&lt;/h3&gt;
&lt;p&gt;We did a bit more debugging with GDB just to understand how
the stack works.
What exactly happens when a function is called?
How does it allocate memory?
And how does it jump back to the parent function?&lt;/p&gt;
&lt;h3 id=&quot;more-assembly&quot; tabindex=&quot;-1&quot;&gt;More assembly&lt;/h3&gt;
&lt;p&gt;I put the following function into godbolt, an online C compiler.
This function is quite instructive so I found it quite enlightening
to understand it in detail.&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stack_array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;         &lt;span class=&quot;token comment&quot;&gt;// not initialized before read&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// printf(&quot;array[] = {&quot;);&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; 0x%x &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;// increment starting from garbage&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// printf(&quot;}\n&quot;);&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This compiles into the following assembly code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;stack_array:
    stmfd sp!, {r4, r5, r6, lr}
    sub sp, sp, #32
    mov r5, #0
    b .L2
.L3:
    add r3, sp, #32
    add r6, r3, r5
    ldrb r4, [r6, #-32] @ zero_extendqisi2
    mov r1, r4
    ldr r0, .L5
    bl printf
    add r4, r4, #1
    strb r4, [r6, #-32]
    add r5, r5, #1
.L2:
    cmp r5, #4
    ble .L3
    add sp, sp, #32
    ldmfd sp!, {r4, r5, r6, lr}
    bx lr
.L5:
    .word .LC0
.LC0:
    .ascii &amp;quot; 0x%x \000&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function starts at &lt;code&gt;stack_array&lt;/code&gt;.
After some preamble (more on this later)
and initialising r5 to #0,
it jumps to &lt;code&gt;.L2&lt;/code&gt;.
&lt;code&gt;.L2&lt;/code&gt; checks the value of r5.
If r5 is less than 5 it ends the function
and does some postamble
before jumping back into the parent function
using &lt;code&gt;bx lr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;L3 is the main loop. What is happening in &lt;code&gt;.L3:&lt;/code&gt;?
&lt;code&gt;r5&lt;/code&gt; is &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;r4&lt;/code&gt; is the current value of &lt;code&gt;array[i]&lt;/code&gt;.
So what we do is we load the value in the address pointed to at &lt;code&gt;r6&lt;/code&gt; minus 32
into &lt;code&gt;r4&lt;/code&gt;, we increment it, then we store it back into that address.
Note that at every loop &lt;code&gt;r6&lt;/code&gt; is being added to
Note also that the array is being added from the back.&lt;/p&gt;
&lt;h4 id=&quot;stmfd-and-ldmfd&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;stmfd&lt;/code&gt; and &lt;code&gt;ldmfd&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;What do these mean? &lt;code&gt;stm&lt;/code&gt; means store multiple
and &lt;code&gt;ldm&lt;/code&gt; means load multiple.
If the stack is descending
(ergo the stack starts from a large number and decreases)
you use &lt;code&gt;fd&lt;/code&gt; to do full descending,
otherwise you use &lt;code&gt;fa&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;stmfd sp!, {r4, r5, r6, lr}&lt;/code&gt;
stores the data inside those four registers
into the first four words of the stack pointer,
then decrements the stack pointer by 16 (4 * 4).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ldmfd sp!, {r4, r5, r6, lr}&lt;/code&gt;
loads the first four words of the stack pointer
back into those four registers.&lt;/p&gt;
&lt;p&gt;Why do we do this?
This basically saves the state of this register
before we jump into the new function
and restores the registers once the function
has finished running.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So, the instruction&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;ldm r4!, {r0, r1, r2, r3}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;can be represented by the following pseudocode:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;r0 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r4&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
r1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r4&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
r2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r4&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
r3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;r4&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
r4 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r4 &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// writeback (16 bytes transferred)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the variant without ! the writeback doesn&#39;t happen
so R4 retains the original value.&lt;/p&gt;
&lt;h3 id=&quot;lab-3%3A-check-in&quot; tabindex=&quot;-1&quot;&gt;Lab 3: Check-in&lt;/h3&gt;
&lt;h4 id=&quot;explain-how-the-lr-register-is-used-as-part-of-making-a-function-call.-which-instruction-writes-to-the-lr-register%3F-which-instruction-reads-from-it%3F-what-commands-could-you-use-in-gdb-to-observe-the-changes-to-the-lr-register-during-execution-of-a-function-call%3F&quot; tabindex=&quot;-1&quot;&gt;Explain how the lr register is used as part of making a function call. Which instruction writes to the lr register? Which instruction reads from it? What commands could you use in gdb to observe the changes to the lr register during execution of a function call?&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;lr&lt;/code&gt; register is the link register.
You store the&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bl loop
add r1, #1
mov lr #500 @ this stores 500 into LR

loop:
@ do some stuff
@ ...
bx lr @ jump back to `add r1, #1`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One thing the prolog here &lt;code&gt;stmfd sp! {r4, r5, r6, lr}&lt;/code&gt; does
is to support nested functions.
Since we only have one &lt;code&gt;lr&lt;/code&gt; register,
if we had a function calling another function
the previous &lt;code&gt;lr&lt;/code&gt; would get overwritten
and we wouldn&#39;t be able to jump back to the grandparent function.
That&#39;s why you store the &lt;code&gt;lr&lt;/code&gt; at the start of the stack
when a function is called
and load it back into &lt;code&gt;lr&lt;/code&gt; after the function has returned
and that allows you to go back to your grandparent.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;bl&lt;/code&gt; instruction writes to the lr register
but you can also use instructions like &lt;code&gt;mov&lt;/code&gt; to write to the lr register
since it&#39;s just another register (register 14).
The &lt;code&gt;bx lr&lt;/code&gt; instruction reads from the lr register.
(it actually reads from any register).&lt;/p&gt;
&lt;p&gt;We could use &lt;code&gt;disassemble&lt;/code&gt; to look at
the source code of the function currently in scope
and also points to the current line.
We can use &lt;code&gt;info reg&lt;/code&gt; to look at the registers
and &lt;code&gt;step&lt;/code&gt; to go stepwise and keep using &lt;code&gt;info reg&lt;/code&gt; to observe the changes in the &lt;code&gt;lr&lt;/code&gt; register.&lt;/p&gt;
&lt;h4 id=&quot;why-is-it-necessary-to-plug-in-both-tx-and-rx-for-loopback-mode-to-work%3F&quot; tabindex=&quot;-1&quot;&gt;Why is it necessary to plug in both TX and RX for loopback mode to work?&lt;/h4&gt;
&lt;p&gt;If you don&#39;t plug in TX to RX you either don&#39;t receive the transmitted messages
or you don&#39;t transmit any messages at all (if you plug in RX but not TX).&lt;/p&gt;
&lt;h4 id=&quot;on-a-hosted-system%2C-executing-an-incorrect-call-to-strlen-(e.g.-argument-is-an-invalid-address-or-unterminated-string)-can-result-in-a-runtime-error-(crash%2Fhalt).-but-when-running-bare-metal-on-the-pi%2C-every-call-to-strlen-(whether-well-formed-or-not)-will-complete-%E2%80%9Csuccessfully%E2%80%9D-and-return-a-value.-explain-the-difference-in-behavior.-what-is-the-return-value-for-an-erroneous-call%3F&quot; tabindex=&quot;-1&quot;&gt;On a hosted system, executing an incorrect call to strlen (e.g. argument is an invalid address or unterminated string) can result in a runtime error (crash/halt). But when running bare metal on the Pi, every call to strlen (whether well-formed or not) will complete “successfully” and return a value. Explain the difference in behavior. What is the return value for an erroneous call?&lt;/h4&gt;
&lt;p&gt;Let&#39;s answer the second part first.
Recall that the implementation of &lt;code&gt;strlen&lt;/code&gt; iterates through incrementing
memory addresses until we hit a &lt;code&gt;\0&lt;/code&gt;.
Now if we don&#39;t hit a zero &lt;code&gt;strlen&lt;/code&gt; will keep increasing and
the return value is undefined
(it can be arbitarily high depending on the state of the Raspi).&lt;/p&gt;
&lt;p&gt;Here&#39;s our best guess:
when we run it on a hosted system the stack size is limited by the OS
(see
&lt;a href=&quot;https://stackoverflow.com/questions/2780100/is-there-any-limit-on-stack-memory&quot;&gt;this SO answer&lt;/a&gt;)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;But programs compiled with for instance C or C++ allocate a fixed size stack at program startup. The size of the stack can usually be specified at compile time (on my particular compiler it default to 1 MB).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;and we&#39;re guessing that once you try to read values outside of that stack
the OS will throw an error.&lt;/p&gt;
&lt;h2 id=&quot;assignment-3&quot; tabindex=&quot;-1&quot;&gt;Assignment 3&lt;/h2&gt;
&lt;h3 id=&quot;string-functions%2C-stoi&quot; tabindex=&quot;-1&quot;&gt;string functions, stoi&lt;/h3&gt;
&lt;p&gt;Most of the string functions were easy
but the &lt;code&gt;stoi&lt;/code&gt; functions were tricky.
WN and I implemented the functions separately as a learning experience.
He finished much quicker than I did
and was kind enough to review my code,
which was very helpful.&lt;/p&gt;
&lt;h3 id=&quot;xxx_to_base-functions&quot; tabindex=&quot;-1&quot;&gt;xxx_to_base functions&lt;/h3&gt;
&lt;p&gt;start 2030 12/22
end 2215 12/22&lt;/p&gt;
&lt;p&gt;We managed to write a passing &lt;code&gt;string_to_base&lt;/code&gt; function.
It was quite tricky.
We sort of cheated by using &lt;code&gt;printf&lt;/code&gt; in a REPL to debug our functions
rather than using gdb.&lt;/p&gt;
&lt;h3 id=&quot;sprintf&quot; tabindex=&quot;-1&quot;&gt;sprintf&lt;/h3&gt;
&lt;h3 id=&quot;vsnprintf&quot; tabindex=&quot;-1&quot;&gt;vsnprintf&lt;/h3&gt;
&lt;h3 id=&quot;printf&quot; tabindex=&quot;-1&quot;&gt;printf&lt;/h3&gt;
</content>
  </entry>
  <entry>
    <title>Report on CS107E Lab and Assignment 2</title>
    <link href="https://lieuzhenghong.com/stanford_cs107e_notes_lab_2_report/"/>
    <updated>2020-12-20T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/stanford_cs107e_notes_lab_2_report/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;This was the second lab (of seven) of Stanford&#39;s CS107E course.
It may or may not be part of my plan to study a Stanford CS degree
in my spare time.
CS107E is a computer architecture course where you build
a simple personal computer shell on the Raspberry Pi bare metal
(without an OS).&lt;/p&gt;
&lt;p&gt;In this lab we disassembled a C program to understand how C programs
are translated by the compiler into assembly.
This also improved my understanding of assembly.
I learned a bit about the stack
We also learned a bit about Makefiles.&lt;/p&gt;
&lt;p&gt;The assignment is to build a clock that displays the time on
a seven-segment display.
We didn&#39;t have the materials so we moved on to Lab 3 for now.&lt;/p&gt;
&lt;h2 id=&quot;using-gdb&quot; tabindex=&quot;-1&quot;&gt;Using gdb&lt;/h2&gt;
&lt;p&gt;Add a breakpoint by using &lt;code&gt;break&lt;/code&gt;.
Use &lt;code&gt;info reg&lt;/code&gt; to view the registers,
&lt;code&gt;disassemble&lt;/code&gt; to view the assembly code of the current function,
and &lt;code&gt;next&lt;/code&gt; and &lt;code&gt;step&lt;/code&gt; to step through code execution.&lt;/p&gt;
&lt;h2 id=&quot;understanding-makefiles&quot; tabindex=&quot;-1&quot;&gt;Understanding Makefiles&lt;/h2&gt;
&lt;p&gt;The symbols that begin with &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt; in a pattern rule are handled by make using the following interpretations:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;%&lt;/code&gt; is a wildcard symbol when used in a rule; &lt;code&gt;%.o&lt;/code&gt; for example matches any file that ends with &lt;code&gt;.o&lt;/code&gt;
&lt;code&gt;$@&lt;/code&gt; refers to the left part of the rule, before the &lt;code&gt;:&lt;/code&gt;
&lt;code&gt;$&amp;lt;&lt;/code&gt; refers to the first element in the right part of the rule, after the &lt;code&gt;:&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;One more special variable &lt;code&gt;$^&lt;/code&gt; refers to all elements in the right part of the
rule, after the &lt;code&gt;:&lt;/code&gt;, which is to say all of the dependencies.&lt;/p&gt;
&lt;h2 id=&quot;breadboarding-the-clock-circuit&quot; tabindex=&quot;-1&quot;&gt;Breadboarding the clock circuit&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2 id=&quot;assignment-3&quot; tabindex=&quot;-1&quot;&gt;Assignment 3&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Report on CS107E Assignment 1</title>
    <link href="https://lieuzhenghong.com/stanford_cs107e_notes_assignment_1_report/"/>
    <updated>2020-12-19T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/stanford_cs107e_notes_assignment_1_report/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I managed to rope Wei Neng in to do CS107E with me.
This may or may not be part of my plan to self-study
a Stanford CS degree in my spare time.
CS107E is a computer systems/computer architecture course.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CS107e: Computer Systems from the Ground Up is a variant of CS107 that teaches the fundamental concepts of computer systems through bare metal programming on the Raspberry Pi. Bare metal programming means you will not run an operating system on the Raspberry Pi and will make minimal use of libraries. This course also serves as an introduction to embedded systems. The course starts with the microprocessor and moves up to the C programming language, without skipping anything in between. The goal is to build a solid understanding of all aspects of how modern computers execute programs and how program development tools work.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Assignments build upon each other by adding more and more functionality to a core library. They culminate in a simple personal computer shell using a keyboard and display. Finally, students do a project of their choosing where they build a complete hardware-software system.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I took NAND 2 Tetris back in 2017 and I really enjoyed it;
however it trades off depth for breadth
in its whirlwind tour-de-force from bottom to top.
I wanted to take a second course to solidify my understanding
and fill in the gaps.
And since I&#39;ve always loved the idea of building
software on the bare metal,
this &amp;quot;build an OS from scratch on the Raspi&amp;quot;
was very appealing.&lt;/p&gt;
&lt;p&gt;And it comes highly recommended as well.
This is what someone said on Reddit:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I just took 107E this quarter. I would highly, highly recommend 107E over 107. Be prepared for a giant time commitment and more work than 107... but take 107E.
...&lt;br&gt;
That doesn’t even begin to touch the material. Frankly, in terms of time commitment and difficulty, 107E is more challenging than 107. For the first 4-5 weeks, you don’t even have print statements. All you have is, literally, a blinking LED light on your Pi to tell if you’re buggy or OK. You build literally everything from the ground up, with your own code, starting with no operating system and debugger, and there are times when things get hard. Crushingly hard, like spend multiple nights on a single bug hard.&lt;/p&gt;
&lt;p&gt;Also, the grading expectations, at least nominally, are high. The course is curved (this quarter at least), but according to the website, to get an A you have to do 3 or more extensions; get the full system bonus (no major bugs in code); have an outstanding final project; trend towards + in code quality; etc. That’s a lot. Now, the requirements aren’t really that stringent, but this course will easily demand 20 hours a week and your best effort to get the extensions in and avoid falling behind.&lt;/p&gt;
&lt;p&gt;But there’s no feeling quite like when you get your code working, or your console working at the end of the quarter. The workload is high — don’t let the “no exams” fool you, it’s more than 107 easily! — but the reward is incredible, and you get to program on a Raspberry Pi! You get to wire things up on breadboards, mess around with LEDs, transistors, resistors, break things, build things...&lt;/p&gt;
&lt;p&gt;For our final projects this quarter, someone built a freaking Rubik’s cube solver robot! Another person built Pac-Man with NES controllers; another person, a piano game using touch sensors on a glove you wear like Michael Jackson; yet another person, a robotic tea kettle. 107? You’ll be banging your head against some inane heap allocator running on a machine you can’t even see, at the same time you’re building these cool things in 107E.&lt;/p&gt;
&lt;p&gt;The topics covered are actually quite close to 107, as well. Naturally, the focus of 107E is a bit different, as hardware, not just the software that runs on it, is always part of the equation. You build software for your GPIO pins, then your memory allocator, then your strings library, then your graphics library and frame buffer handling... You’re building up a fully-working system in layers each week, step by step, working towards a console with commands you can type. But along the way, you’re also covering assembly, memory allocation, system architecture, processing, etc. and your understanding of those topics is no less than that of a 107 student.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Unfortunately because there seems to be some problem
with my Raspi TTY, I had to share with Wei Neng
and we work through the assignments together.
This is very much against the Stanford Honor Code but
I couldn&#39;t care less since
i) I&#39;m not a Stanford student,
ii) pair work keeps me accountable, and
iii) the only thing that happens if I cheat is
cheating myself of my own learning, so I won&#39;t cheat.&lt;/p&gt;
&lt;h2 id=&quot;what-did-we-have-to-do%3F&quot; tabindex=&quot;-1&quot;&gt;What did we have to do?&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Time taken:&lt;/em&gt; about 10 hours for everything all-in&lt;/p&gt;
&lt;p&gt;In Assignment 1 we were tasked to write a &amp;quot;Larson scanner&amp;quot;,
which is basically just blinking some lights in
an aesthetic-looking scanner pattern.
The catch is that we had to write it in assembly.
In order to make lights blink on the Raspi
you have to write an &amp;quot;ON&amp;quot; bit to the GPIO memory address.
Because it&#39;s assembly, there are no functions, while loops,
or even variables.
And in order to&lt;/p&gt;
&lt;h2 id=&quot;what-was-hard-about-the-task%3F&quot; tabindex=&quot;-1&quot;&gt;What was hard about the task?&lt;/h2&gt;
&lt;p&gt;Something that was very hard is that you can&#39;t
just use any number as an immediate.
So for example
if you try to do &lt;code&gt;mov r1 #584&lt;/code&gt;
the code won&#39;t compile and it will give an error like
&lt;code&gt;invalid constant value&lt;/code&gt;
or something like that.
The rules are something that I haven&#39;t bothered to learn yet
(it has something to do with barrel shifting---see the &amp;quot;What do I still need to know?&amp;quot; section)&lt;/p&gt;
&lt;p&gt;The trick is to add byte-by-byte using an inclusive or command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mov r1 #73
orr r1 #512
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another hard part about writing assembly is that
it&#39;s kind of like a real time system.
Every instruction is mapped to one line of binary code
and that takes one clock cycle (I think).
So everything is driven by the clock cycle
and you can get precision on the order of milliseconds.&lt;/p&gt;
&lt;p&gt;It was actually quite hard to do pulse-width modulation
with a constant delay.
Suppose you want to keep the LED on for 1 second.
That&#39;s some number of clock cycles.
However, when doing pulse-width modulation
you want to flicker it off and on with a short delay between.
The challenge is: how do you vary the brightness
(ergo change the time the bulb is off vs on)
while keeping the &lt;em&gt;total&lt;/em&gt; time the LED on the same?
Remember you don&#39;t have any sort of timer:
you can only declare variables that tick down.
You need a nested loop with the invariant that
the nested loop must run for the same amount of time
regardless of how bright or dim the LED is
(i.e. how long the LED stays off).
So that was pretty tricky.&lt;/p&gt;
&lt;h2 id=&quot;what-did-i-do-well%3F&quot; tabindex=&quot;-1&quot;&gt;What did I do well?&lt;/h2&gt;
&lt;p&gt;I enjoyed writing assembly code in N2T and this time was
no different.
The simplicity of assembly code is really quite nice.
I could feel the assembly that I did in N2T come back to me.
Even though the assembly language taught in N2T
was a toy language, a lot of the concepts were transferrable.
I found that I was able to write more simple/less convoluted
assembly code than Wei Neng, almost certainly
because of my previous practice.&lt;/p&gt;
&lt;h2 id=&quot;what-could-i-have-done-better%3F&quot; tabindex=&quot;-1&quot;&gt;What could I have done better?&lt;/h2&gt;
&lt;p&gt;We worked till 2am/230am until we were super tired,
and we were already far from productive.
I should have called a break earlier
so that I wouldn&#39;t fuck my sleep schedule.&lt;/p&gt;
&lt;h2 id=&quot;what-did-i-learn%3F&quot; tabindex=&quot;-1&quot;&gt;What did I learn?&lt;/h2&gt;
&lt;p&gt;I learned (a small part of) ARM64 assembly.
I also learned about the concept of pulse-width modulation.&lt;/p&gt;
&lt;h2 id=&quot;what-do-i-still-need-to-know%3F&quot; tabindex=&quot;-1&quot;&gt;What do I still need to know?&lt;/h2&gt;
&lt;p&gt;I&#39;m still quite foggy on why some immediate values
are allowed and why others aren&#39;t.
Read
&lt;a href=&quot;https://alisdair.mcdiarmid.org/arm-immediate-value-encoding/#play-with-it&quot;&gt;how ARM encodes immediates&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Browse through
&lt;a href=&quot;https://cs107e.github.io/readings/armisa.pdf&quot;&gt;the ARM instruction set manual&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot; tabindex=&quot;-1&quot;&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;I really enjoyed this assignment,
and I hope I get to code more in assembly next time
(or C at least).&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Geolibertarianism with Harberger Taxes</title>
    <link href="https://lieuzhenghong.com/geolibertarianism_with_harberger_taxes/"/>
    <updated>2020-12-06T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/geolibertarianism_with_harberger_taxes/</id>
    <content type="html">&lt;p&gt;What is Geolibertarianism?&lt;/p&gt;
&lt;p&gt;https://sites.google.com/site/justindkeith/home/geolibertarian-faq#geolib&lt;/p&gt;
&lt;p&gt;Two Crazy Ideas: Public Land Exemptions and Self-Assessed Tax&lt;/p&gt;
&lt;p&gt;https://www.reddit.com/r/georgism/comments/hf636b/two_crazy_ideas_public_land_exemptions_and/&lt;/p&gt;
&lt;p&gt;https://medium.com/blockchannel/reimagining-property-fbce9d3832a4&lt;/p&gt;
&lt;p&gt;Yay Stability Rents (introducing the idea of Harberger taxes)&lt;/p&gt;
&lt;p&gt;https://www.overcomingbias.com/2017/10/for-stability-rents.html&lt;/p&gt;
&lt;p&gt;https://ethresear.ch/t/highlight-robin-hansons-more-owner-forgiving-modified-harberger-tax/5720&lt;/p&gt;
&lt;p&gt;One possibility is to set up a system where users pay the Harberger tax by prepaying funds into a contract, and there exists a separate mechanism where users can submit bids for any item of property; each bid must be fully collateralized. The tax rate that the current owner pays is computed based on the value of the highest bid. The owner has the ability to sell to the highest bidder at the bid price at any time (or the sale happens automatically if the prepaid tax contract runs out of money). This system is more favoring because sales are owner-initiated rather than buyer-initiated. One can also provide owners a further measure of stability by limiting the rate at which their tax can go up (eg. to one doubling per week).&lt;/p&gt;
&lt;p&gt;This kind of owner-forgiving Harberger tax is not very useful for the “market-based eminent domain” use case: if Elon Musk suddenly puts up bids for an entire strip of houses going through a city to build a hyperloop there, then once some owners sell the other owners will know they can extract high prices and would be able to raise their prices (whereas with the traditional harberger tax everything would get snapped up at once). However, it seems very useful in cases where you’re not expecting buyers to want to buy a large set of items at the same time, eg. ENS domains.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Three levels of competency</title>
    <link href="https://lieuzhenghong.com/three_levels_of_competency/"/>
    <updated>2020-11-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/three_levels_of_competency/</id>
    <content type="html">&lt;p&gt;[Forwarded from lieu]
that for many endeavours there are three levels of competence/knowledge&lt;/p&gt;
&lt;p&gt;lieu, [22.11.20 21:03]
[Forwarded from lieu]
the first level is slavishly following / repeating dogma, like following a recipe when cooking, or following a recommended build in dota&lt;/p&gt;
&lt;p&gt;lieu, [22.11.20 21:03]
[Forwarded from lieu]
the second level is being able to make smart substitutions, to riff on an existning recipe, e.g. make ingredient substitutions/know which can be elided, or when in dota adapt the build to your opponent, or when playing guitar know what chords can be substituted for others&lt;/p&gt;
&lt;p&gt;lieu, [22.11.20 21:03]
[Forwarded from lieu]
the third level is knowing the fundamental underpinnings of your field and being able to build something ex nihilo, e.g. creating a new dish with any random arbitrary subset of ingredients, or creating interesting weird builds of your own, or going to the scientific literature to design a specific fitness routine to work for someone with one arm and one leg, etc.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A new method of training: can resting for hours between exercises maximise your gains?</title>
    <link href="https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/"/>
    <updated>2020-11-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/</id>
    <content type="html">&lt;p&gt;~ 1600 words&lt;/p&gt;
&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#microfoundations%3A-what-makes-muscle-grow%3F&quot;&gt;Microfoundations: what makes muscle grow?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#why-long-rests%3F&quot;&gt;Why long rests?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#why-a-5-day-full-body-workout%3F&quot;&gt;Why a 5-day full-body workout?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#why-cluster-sets%2Fblood-flow-restriction-training%3F&quot;&gt;Why cluster sets/blood flow restriction training?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#questions-i-still-have&quot;&gt;Questions I still have&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#will-long-rests-make-your-muscles-cool-down%3F-will-you-have-to-warm-up-between-sets%3F&quot;&gt;Will long rests make your muscles cool down? Will you have to warm up between sets?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#sample-program&quot;&gt;Sample program&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#monday&quot;&gt;Monday&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#tuesday&quot;&gt;Tuesday&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#wednesday&quot;&gt;Wednesday&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#thursday&quot;&gt;Thursday&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#friday&quot;&gt;Friday&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#notes-i-took-from-menno&#39;s-video&quot;&gt;Notes I took from Menno&amp;#39;s video&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/the_lazy_mans_workout_that_also_maximises_your_gains/#what-about-the-notion-of-%22effective-reps%22%3F&quot;&gt;What about the notion of &amp;quot;effective reps&amp;quot;?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;After reading the scientific literature and thinking through first principles,
I&#39;ve been thinking about a training method that I believe (as far as the evidence goes)
maximises hypertrophy but also happens to be very easy and painless.
This training method deviates from most programs in two (three) main ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Advocates full body workouts, 5 days a week&lt;/li&gt;
&lt;li&gt;Advocates long (~15--25 minute) rests between sets, and even longer
rests (~hours) between exercises&lt;/li&gt;
&lt;li&gt;(optional) Consider cluster sets (resting a couple of seconds in between reps) and
blood-flow restriction training&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;While I designed the method for my very particular set of circumstances and
preferences (I have a home gym and prefer squeezing in sets throughout the day
rather than blocking out a large block of time), I believe this method of
training could actually be optimal for muscle growth.&lt;/p&gt;
&lt;p&gt;The key idea is to maximise effective volume and muscle protein synthesis
while minimising metabolic stress and muscle damage.
The long rests between sets/exercises brings to mind the Greasing the Groove
(GtG) protocol but focuses on near-maximal sets
with high (7--8) RPE to maximise muscle tension/volume.&lt;/p&gt;
&lt;h2 id=&quot;microfoundations%3A-what-makes-muscle-grow%3F&quot; tabindex=&quot;-1&quot;&gt;Microfoundations: what makes muscle grow?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TL; DR:&lt;/strong&gt; The science suggests that muscle tension
(force production and stretch)
is the primary (and possibly the &lt;em&gt;only&lt;/em&gt;) driver of growth.
There is little evidence to show that muscle damage (&amp;quot;microtears&amp;quot;)
or metabolic stress (&amp;quot;burn&amp;quot; from lactic acid, &amp;quot;pump&amp;quot;) contribute to hypertrophy,
suggesting that we should maximise muscle tension and minimise muscle
damage/metabolic stress.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The scientific consensus used to believe otherwise.
In
&lt;a href=&quot;https://pdfs.semanticscholar.org/be0a/06fe358cff98b87a5a73b690ccec21caff7d.pdf&quot;&gt;Brad Schoenfield&#39;s seminal paper (2010)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;he writes that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mechanically induced tension produced both by force generation and stretch is
considered essential to muscle growth.. [but is] unlikely to be solely
responsible for hypertrophic gains associated with exercise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He points to muscle damage and metabolic stress as contributing factors,
and concludes that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Current research suggests that maximum gains in muscle hypertrophy are
achieved by training regimens that produce significant metabolic stress while
maintaining a moderate degree of muscle tension. A hypertrophy-oriented
program should employ a repetition range of 6-12 reps per set with rest
intervals of 60-90 seconds between sets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;But in &lt;a href=&quot;https://www.youtube.com/watch?v=hOWoAg8pG8E&quot;&gt;this video&lt;/a&gt;
Schoenfeld updates his model.
He says that the evidence for an additive effect of muscle damage or metabolic stress on hypertrophy
is really equivocal and none of it is compelling.&lt;/p&gt;
&lt;p&gt;In 2017 Menno Henselmans gave a
&lt;a href=&quot;https://www.youtube.com/watch?v=voMnQr7sfmk&amp;amp;feature=emb_title&quot;&gt;talk&lt;/a&gt;
where he cites a lot of papers and claims that both
muscle damage (microtears in the muscle fibers) and
metabolic stress (acidosis, lactic acid buildup, &amp;quot;pump&amp;quot;, etc.)
are &lt;strong&gt;not&lt;/strong&gt; drivers of muscle hypertrophy.
I haven&#39;t read the papers he cited but I trust him.
The TL;DW is that:&lt;/p&gt;
&lt;p&gt;i) muscle damage is a &lt;em&gt;necessary byproduct&lt;/em&gt; of muscle tension,
but does not itself stimulate hypertrophy.
Increased muscle damage causes greater muscle protein synthesis, but no
&lt;em&gt;net&lt;/em&gt; muscle growth; the increased muscle protein synthesis simply
repairs the damaged muscles.
Additionally, blood flow restriction training seems to be
able to induce similar levels of muscle growth with little to no muscle damage.&lt;/p&gt;
&lt;p&gt;ii) training to failure causes metabolic stress to rise exponentially but we
observe little to no increase in muscle growth (S-shaped curve).&lt;/p&gt;
&lt;p&gt;There seems to be no good evidence to believe that muscle damage or
metabolic stress contribute to hypertrophy.
(Also, muscle damage and metabolic stress both hurt, and I don&#39;t like to hurt).
This leads to a pretty counterintuitive conclusion: in order to maximise
hypertrophy,
we should aim to &lt;strong&gt;maximise muscle tension/force production&lt;/strong&gt; while
&lt;strong&gt;minimising muscle damage and metabolic stress&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If we accept this conclusion, that implies that we should
&lt;strong&gt;take long rests between sets&lt;/strong&gt;
and perform &lt;strong&gt;few sets of exercises for a muscle group at a high intensity&lt;/strong&gt;.
Both these adjustments minimise metabolic stress and maximise volume.&lt;/p&gt;
&lt;h2 id=&quot;why-long-rests%3F&quot; tabindex=&quot;-1&quot;&gt;Why long rests?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt;
It allows increased volume---the primary driver of growth---
and also works much better with my schedule/preferences.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Exercise volume can be defined as the product of total repetitions, sets, and
load performed in a training session (Schoenfeld 2010).
If we believe that muscle tension (ergo volume) is the primary driver
of hypertrophy, the idea then is simple:
if we take longer rests, we can do more volume, which means more gains!
Here&#39;s &lt;a href=&quot;https://mennohenselmans.com/optimal-program-design/&quot;&gt;Henselmans&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In conclusion, your rest interval matters primarily because it affects your
training volume. As long as you perform a given amount of total training
volume, it normally doesn’t matter how long you rest in between sets... It’s
the total volume, not how you distribute it over time, that determines the
signal for muscle growth.  However, in practice, ‘work-equated’ doesn’t exist,
as it’s just you, so resting shorter for a given amount of sets decreases how
many reps you can do in later sets and thereby your training volume. This
means for most people, &lt;strong&gt;resting only a minute or less in between sets is
probably detrimental for muscle growth rather than beneficial&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The scientific literature doesn&#39;t seem to examine very long rest periods,
probably because nobody has the time to sit around for ages doing nothing.
But I do because I now have a home gym and can bang out a set in between Pomodoro
timers of 25 minutes.
It&#39;s unlikely that resting for a long period would lower hypertrophy
&lt;em&gt;precisely because&lt;/em&gt; metabolic stress and/or muscle damage don&#39;t seem to be
important for growth (but see the Appendix for concerns about &amp;quot;cooling down&amp;quot;).&lt;/p&gt;
&lt;p&gt;In essence, hitting one muscle group a lot in one session with not-very-long
rests between sets both decreases volume causes a great deal of metabolic stress
compared to doing the same exercises over several days AND taking long rests between them.
The best part is that if you do them spread out you can do more volume which
means more gains---AND you hurt much less.&lt;/p&gt;
&lt;h2 id=&quot;why-a-5-day-full-body-workout%3F&quot; tabindex=&quot;-1&quot;&gt;Why a 5-day full-body workout?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TL;DR: Training each bodypart more frequently maximises muscle protein synthesis.&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://www.ncbi.nlm.nih.gov/pubmed/25739559&quot;&gt;Damas et al. (2015)&lt;/a&gt;
found that
muscle protein synthesis (MPS) in trained individuals returns to baseline just 12 hours
after working out, which means that in order to keep muscle protein synthesis at
its peak for a particular muscle one should be working that muscle every single
day---possibly even two times a day for elite athletes.&lt;/p&gt;
&lt;p&gt;Additionally, muscle growth is a hyperlocal phenomenon: elevated MPS in your
chest isn&#39;t going to make your arms or quads bigger.&lt;/p&gt;
&lt;p&gt;This is why we should work full-body. Since&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MPS is hyperlocal,&lt;/li&gt;
&lt;li&gt;MPS drops off 12 hours after working out,&lt;/li&gt;
&lt;li&gt;MPS causes muscle hypertrophy,&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;it therefore follows that we should work each body part every 12 hours
(or as often as possible, anyway)
to maximise MPS and muscle hypertrophy.&lt;/p&gt;
&lt;p&gt;Additionally, there&#39;s the concept of &amp;quot;maximal effective volume&amp;quot;: there may or may not
be a hard cap of how much volume a muscle group can be worked in a session to
see more gains. See
&lt;a href=&quot;https://mennohenselmans.com/maximum-productive-training-volume-per-session/&quot;&gt;Menno again&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both these factors combine to suggest that body-part splits are suboptimal:
if you really demolish one body part for a workout then not only do
you get fatigued and can&#39;t really maximise volume/get the full mind-muscle connection,
but that massive volume load can only really cause a spike in muscle protein
synthesis for 12 hours anyway.&lt;/p&gt;
&lt;p&gt;Empirical evidence seems to support this:
&lt;a href=&quot;https://europepmc.org/article/MED/31260419&quot;&gt;Zaroni et al. (2019)&lt;/a&gt;
found that a 5-day per week whole-body workout gave significantly greater hypertrophy
on trained men.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The purpose of this study was to compare the effect a split training routine
with muscle groups trained once per week (SPLIT) vs. whole-body split training
routine with muscle groups trained 5 days per week (TOTAL) on neuromuscular
adaptations in well-trained men... TOTAL induced a significantly greater
increase in MT of the forearm flexors and vastus lateralis (p &amp;lt; 0.05)...
&lt;strong&gt;TOTAL may confer a potentially superior hypertrophic effect&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why five days, and not six or seven?
I&#39;m not sure (and would have to do more research on this) but it could be a way
to reduce accumulated fatigue&lt;/p&gt;
&lt;h2 id=&quot;why-cluster-sets%2Fblood-flow-restriction-training%3F&quot; tabindex=&quot;-1&quot;&gt;Why cluster sets/blood flow restriction training?&lt;/h2&gt;
&lt;p&gt;This part is more speculative.&lt;/p&gt;
&lt;p&gt;Cluster sets (sets with built-in, short rest periods of 5-20 or so seconds)
decrease metabolic stress and allow you to get more volume in.
If you rest between sets you can lift more weight more times --&amp;gt; more volume --&amp;gt;
more hypertrophy.&lt;/p&gt;
&lt;p&gt;But take note that in order to maximise muscle fiber recruitment one might want to
work at a high intensity (high % of 1RM):
you don&#39;t want to do cluster sets with too low weight as that might only
recruit the lower-threshold muscle fibers. See the section in the Appendix
(under &amp;quot;What about the notion of &#39;effective reps&#39;&amp;quot;) for details.&lt;/p&gt;
&lt;p&gt;Blood flow restriction training might decrease muscle damage which might be
useful,
but this is really speculative.&lt;/p&gt;
&lt;h2 id=&quot;questions-i-still-have&quot; tabindex=&quot;-1&quot;&gt;Questions I still have&lt;/h2&gt;
&lt;h3 id=&quot;will-long-rests-make-your-muscles-cool-down%3F-will-you-have-to-warm-up-between-sets%3F&quot; tabindex=&quot;-1&quot;&gt;Will long rests make your muscles cool down? Will you have to warm up between sets?&lt;/h3&gt;
&lt;p&gt;Anecdotally, powerlifters seem to rest for ~15 minutes between sets without
having to warm up between sets so maybe this is OK? Not sure.&lt;/p&gt;
&lt;p&gt;You might need to elevate your core temp again between exercises if you&#39;ve
rested a long time between them.&lt;/p&gt;
&lt;h2 id=&quot;sample-program&quot; tabindex=&quot;-1&quot;&gt;Sample program&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TODO&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;5 days a week full body hitting 10-20 sets of volume for each body part
Dumbbell + calisthenics only because that&#39;s what I have.&lt;/p&gt;
&lt;p&gt;Might take a look at
&lt;a href=&quot;https://www.youtube.com/watch?v=nxisr1AalNc&quot;&gt;Jeff Nippard&#39;s video&lt;/a&gt;
for some ideas.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chest:
pushup variations,
incline DB press,
flat DB press,&lt;/li&gt;
&lt;li&gt;Arms:
skullcrushers,
bicep curls,
tricep extensions&lt;/li&gt;
&lt;li&gt;Back:
&lt;ul&gt;
&lt;li&gt;Lats:
unilateral DB rows,
humble rows,
archer pullps,
weighted pullups,&lt;/li&gt;
&lt;li&gt;Traps should be worked by heavy shrugs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Shoulders:
side and front delt don&#39;t need to be isolated
and will be worked with seated or standing DB press
&lt;ul&gt;
&lt;li&gt;Rear delts should be isolated with ~15 sets a week:
unilateral bent over external shoulder rotation,
band face pulls,&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Abs: leg raises, ab slides, double leg thrust&lt;/li&gt;
&lt;li&gt;Legs: lol what are these&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mix between unilateral and bilateral execrises,
calisthenics and dumbbells&lt;/p&gt;
&lt;h3 id=&quot;monday&quot; tabindex=&quot;-1&quot;&gt;Monday&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chest: DB bench&lt;/li&gt;
&lt;li&gt;Shoulders: Seated DB OHP&lt;/li&gt;
&lt;li&gt;Back: DB rows&lt;/li&gt;
&lt;li&gt;Arms: Hammer curl&lt;/li&gt;
&lt;li&gt;Abs:&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;tuesday&quot; tabindex=&quot;-1&quot;&gt;Tuesday&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chest:&lt;/li&gt;
&lt;li&gt;Back: weighted pullups&lt;/li&gt;
&lt;li&gt;Shoulders:&lt;/li&gt;
&lt;li&gt;Arms:&lt;/li&gt;
&lt;li&gt;Abs:&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;wednesday&quot; tabindex=&quot;-1&quot;&gt;Wednesday&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chest: floor press&lt;/li&gt;
&lt;li&gt;Back: weighted shrugs&lt;/li&gt;
&lt;li&gt;Shoulders: Lat raises&lt;/li&gt;
&lt;li&gt;Arms: concentration curls&lt;/li&gt;
&lt;li&gt;Abs: ab roll&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;thursday&quot; tabindex=&quot;-1&quot;&gt;Thursday&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chest:&lt;/li&gt;
&lt;li&gt;Back: archer pullups, face pulls&lt;/li&gt;
&lt;li&gt;Shoulders: Unilateral bent over external shoulder rotation&lt;/li&gt;
&lt;li&gt;Arms:&lt;/li&gt;
&lt;li&gt;Abs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;friday&quot; tabindex=&quot;-1&quot;&gt;Friday&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Chest: DB bench&lt;/li&gt;
&lt;li&gt;Back: Humble row&lt;/li&gt;
&lt;li&gt;Shoulders:&lt;/li&gt;
&lt;li&gt;Arms:&lt;/li&gt;
&lt;li&gt;Abs&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;TODO&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;p&gt;Things that don&#39;t fit in the main article&lt;/p&gt;
&lt;h3 id=&quot;notes-i-took-from-menno&#39;s-video&quot; tabindex=&quot;-1&quot;&gt;Notes I took from Menno&#39;s video&lt;/h3&gt;
&lt;p&gt;Three primary drivers have been proposed for hypertrophy:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mechanical tension&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mechanotransduction (tension on muscle stretch)&lt;/li&gt;
&lt;li&gt;Myogenic signaling (IGF1 IL6) signals&lt;/li&gt;
&lt;li&gt;mTOR signal integration and translation initiation --&amp;gt; (MGF Mechanogrowth factor)&lt;/li&gt;
&lt;li&gt;MPS muscle protein synthesis&lt;/li&gt;
&lt;li&gt;Myonuclear addition&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Muscle damage: no compelling rationale.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;microtears repair, satellite cell activation, inflammatory response,
repaired myofibre and gets larger.&lt;/li&gt;
&lt;li&gt;muscle damage triggers muscle growth, but not NET muscle growth.
Cast doubt ... muscle damage is something we want to avoid. (Which study?)&lt;/li&gt;
&lt;li&gt;Another study: triggering the &amp;quot;repeated bout effect&amp;quot; in the treatment
group. Muscle growth same with big difference in muscle damage.&lt;/li&gt;
&lt;li&gt;Long believe ecc &amp;gt; con for muscle damage &amp;amp; growth.
KAATSU: no muscle damage, adding occlusion gives more muscle growth but no
more muscle damage.
Creatine (seems to) decreases muscle damage yet improve muscle growth.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Metabolic stress
Accumulation of metabolic byproducts in the muscle: lactate, phosphate, hydrogen
ion, along with hypoxia.
Why might it work? Increased inflammation, fiber
recruitment, cellular swelling (ergo PUMP: extracellular water enters the
sarcoplasm outside the myofibers)
HIIT high metabolic stress and muscle damage but little growth? (Cypryan 2017)&lt;/p&gt;
&lt;p&gt;Rest intervals: broscience says long rests for strength, short rest
If you have people resting longer, more muscle growth, you do more volume,
put more tension&lt;/p&gt;
&lt;p&gt;Henselman and Schoenfeld: volume &amp;gt; metabolic stress&lt;/p&gt;
&lt;p&gt;Low reps high reps doesn&#39;t matter, mechanical tension&lt;/p&gt;
&lt;p&gt;Training to failure: metabolic stress rises exponentially but no/little
increases in myuscle growth (S-shaped curve )&lt;/p&gt;
&lt;p&gt;Cluster sets: rest a couple breaths between sets (lot more work done): same
growth, much less metabolic stress.
--&amp;gt; Oliver et al. 2013
(check this study methodology though)&lt;/p&gt;
&lt;p&gt;KAATSU works not via metabolic stress, but rather making exercise harder,
causing more muscle activation + more mechanical tension&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: Mechanical tension is the &lt;em&gt;only&lt;/em&gt; (or by far the primary) cause of hypertrophy!&lt;/p&gt;
&lt;h3 id=&quot;what-about-the-notion-of-%22effective-reps%22%3F&quot; tabindex=&quot;-1&quot;&gt;What about the notion of &amp;quot;effective reps&amp;quot;?&lt;/h3&gt;
&lt;p&gt;&amp;quot;Effective&amp;quot; reps seem to be a thing (ergo you maximise hypertrophy by going
close to failure, with diminishing returns the closer to failure you go).
Some have claimed that this is due to a metabolic stress effect.
However this is probably a muscle recruitment effect (recruiting
higher-threshold fibers) and not a metabolic stress one.&lt;/p&gt;
&lt;p&gt;Goto et al (2005) found that people who took a 30s rest in between 10 reps of lat pulldowns got less growth than people
who did them all in one go.
This is readily explained by the muscle recruitment hypothesis though. As you go
closer and closer to failure you recruit more and more fibers, and recruiting
more fibers means more hypertrophy. So I believe that resting 30s meant that
participants continued to activate their low threshold fibers. They were not
able to get full motor recruitment and thus had less hypertrophy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;BUT&lt;/strong&gt; see also this correction by Grgic and Schoenfeld (2019):
(https://physoc.onlinelibrary.wiley.com/doi/pdfdirect/10.1113/JP278627)
looks like the evidence is equivocal on whether or not load (% of 1RM)
is an important determinant of muscle fiber activation vs hypertrophy.&lt;/p&gt;
&lt;p&gt;Also, a more recent study by Carroll et al. (2019) found that not going to
failure resulted in greater hypertrophy.&lt;/p&gt;
&lt;p&gt;In the interview I posted above Schoenfeld mentioned SOME evidence that acidosis
prevents contractability in the fast twitch fibers. Less contractability means
less fiber recruitment means less hypertrophy. This suggests that decreasing
metabolic fatigue (ergo less acidosis) can directly increase hypertrophy.&lt;/p&gt;
&lt;p&gt;He also says that there is no study yet on whether moderate or low sustained muscle
damage or metabolic stress has an additive effect on hypertrophy, and part of
the reason is that it&#39;s really difficult to isolate the individual effects in an
RCT.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Convergence is (finally) coming</title>
    <link href="https://lieuzhenghong.com/convergence_is_finally_coming/"/>
    <updated>2020-11-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/convergence_is_finally_coming/</id>
    <content type="html">&lt;p&gt;lieu, [26.11.20 14:28]
i think the future will be&lt;/p&gt;
&lt;p&gt;you carry a work phone and a personal phone
and there will be laptop/desktop/tablet &amp;quot;shells&amp;quot;
completely dividing up form from function
You only upgrade one device&lt;/p&gt;
&lt;p&gt;You can keep the shells and peripherals the same&lt;/p&gt;
&lt;p&gt;That is a key value prop imo&lt;/p&gt;
&lt;p&gt;And the best thing is that those shells can be really any form factor you want really
They don&#39;t even have to be restricted to laptop tablet desktop
Could be anything
That&#39;s what i mean by decoupling
Conceivably in the future you might have a touchscreen wall
let&#39;s say
Just plug your phone into the dock
And then the entire wall mounted screen becomes a massive tablet
If you want to do big screen gaming plug it into your TV
for consumer .. the way forward is to wait for apple to do it&lt;/p&gt;
&lt;p&gt;Microsoft doesn&#39;t have the solution because
you need to control both mobile and desktop
and apple is the only person who does
Google has chromebooks which are shite
Microsoft king of desktop only
so apple is the only one who could pull it off
you have a phone which is your primary computer
and you can plug it into anything&lt;/p&gt;
&lt;p&gt;we are decoupling the form of the device
from the brain of the device
just like i plug my laptop into a 28 inch monitor
this is just taking it ot the next step
you have a phone that can plug into a tablet/laptop/desktop shell or &amp;quot;dock&amp;quot;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=lren-G4h84o&amp;amp;list=PLgrIBd4K_trJ1q3-OIVkW0AZKmlWpfDUk&quot;&gt;Your Phone Could Be Your Laptop. Here&#39;s Why It Won&#39;t.&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How to set up bidirectional communication between a Docker container and its host machine using TCP sockets</title>
    <link href="https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/"/>
    <updated>2020-11-15T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#the-problem&quot;&gt;The problem&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#writing-to-and-from-files-in-a-directory&quot;&gt;Writing to and from files in a directory&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#building-bidirectional-communication-over-tcp&quot;&gt;Building bidirectional communication over TCP&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#how-to-build-bidirectional-communication-over-tcp&quot;&gt;How to build bidirectional communication over TCP&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#serialising-and-deserialising-the-data&quot;&gt;Serialising and deserialising the data&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#knowing-when-the-message-has-ended&quot;&gt;Knowing when the message has ended&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;(I wrote this to document the specifics of a feature I shipped at IMDA.
I have reproduced it here because it may be useful to some
(especially future me),
but I haven&#39;t intended it for public consumption.
So it&#39;s probably not going to be well-motivated or interesting to you,
and you may be missing some critical context:
but read on if you want to know how to set this up for yourself
).&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I wrote simple sockets code to allow a host machine and a Docker container
running on it to communicate bidirectionally.
I needed to do this because our machine learning model ran on a Docker container
and we needed to send data to/receive data from it.&lt;/p&gt;
&lt;h2 id=&quot;the-problem&quot; tabindex=&quot;-1&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;We want the machine learning model to be in a Dockerfile
to make setup and configuration easy.
But this introduces a new challenge:
how do we send data from the Jetson (host)
to the machine learning model (Docker container)?&lt;/p&gt;
&lt;p&gt;If the code for the machine learning model were not in a Docker, we could simply
&lt;code&gt;import&lt;/code&gt; the module into the webcam stream code, something like this:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# webcam_stream.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ml_model
img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; get_img_from_webcam_stream&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
bounding_boxes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ml_model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;detect_objects_in&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But we can&#39;t do this now because &lt;code&gt;ml_model&lt;/code&gt; is running in a Docker container.
We need some way to pass the &lt;code&gt;img&lt;/code&gt; from the webcam stream into the Docker
container, and get the &lt;code&gt;bounding_boxes&lt;/code&gt; back.
So how? I thought a lot about this. There were a few different candidates:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spin up HTTP server on the Docker container and make requests&lt;/li&gt;
&lt;li&gt;Use a message broker like Kafka or RabbitMQ&lt;/li&gt;
&lt;li&gt;Mount a host directory on the docker and read/write to files on that directory&lt;/li&gt;
&lt;li&gt;Expose a port and build bidirectional communication over TCP&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It seemed like a very simple task to send data to and from the same machine, so
I wanted to avoid the overhead of spinning up a HTTP server or message broker.
This left the last two options.&lt;/p&gt;
&lt;h3 id=&quot;writing-to-and-from-files-in-a-directory&quot; tabindex=&quot;-1&quot;&gt;Writing to and from files in a directory&lt;/h3&gt;
&lt;p&gt;Suppose you have a &lt;code&gt;webcam_stream.py&lt;/code&gt; and &lt;code&gt;ml_model.py&lt;/code&gt;
that both have access to a shared folder.
If both Python files watch the folder for changes we can get kind-of real-time
communication.
Let &lt;code&gt;webcam_stream.py&lt;/code&gt; write &lt;code&gt;frame_1.ndarray&lt;/code&gt; to the folder.
Then &lt;code&gt;ml_model.py&lt;/code&gt; can read that file in, detect the objects in that first
frame,
and then write a &lt;code&gt;frame_1_bbox.ndarray&lt;/code&gt; file to the folder.
&lt;code&gt;webcam_stream.py&lt;/code&gt; can then read &lt;em&gt;that&lt;/em&gt; file in.&lt;/p&gt;
&lt;p&gt;This is a pretty simple idea: the downsides are that
i) file I/O is slow, and
ii) you will have to write code to handle deleting old files.
It also didn&#39;t seem very elegant to have to constantly create and delete files.
Therefore, I chose not to use this approach in the end.
But since everything in Unix is a file &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, couldn&#39;t we use Unix sockets?&lt;/p&gt;
&lt;h3 id=&quot;building-bidirectional-communication-over-tcp&quot; tabindex=&quot;-1&quot;&gt;Building bidirectional communication over TCP&lt;/h3&gt;
&lt;p&gt;Suppose we had an open port on &lt;code&gt;localhost:6000&lt;/code&gt;
and a way to send and receive data over that connection.
Then we could make &lt;code&gt;ml_model.py&lt;/code&gt; constantly listen on that port
for image data from &lt;code&gt;webcam_stream.py&lt;/code&gt;.
After receiving the image data it would then run it through the ML model
and send the bounding boxes back through the same connection.&lt;/p&gt;
&lt;p&gt;Some pseudocode here:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# webcam_stream.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; get_img_from_webcam_stream&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    bounding_boxes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; send_img_to_ml_model&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; port&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ml_model.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; recv_img_from_stream&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;port&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    bounding_boxes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; detect_objects_in&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    send_img_to_stream&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bounding_boxes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; port&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;how-to-build-bidirectional-communication-over-tcp&quot; tabindex=&quot;-1&quot;&gt;How to build bidirectional communication over TCP&lt;/h2&gt;
&lt;p&gt;I used a low-level Python library called &lt;code&gt;socket&lt;/code&gt;.
This library directly calls the Unix socket syscalls
(again, something I don&#39;t quite understand).&lt;/p&gt;
&lt;p&gt;We first establish a connection using &lt;code&gt;socket.connect&lt;/code&gt;
before sending any data over.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Server-side&lt;/strong&gt;: First we start a listener on the server side.
We &lt;em&gt;bind&lt;/em&gt; the socket to an open port (in this case 6000)
and start listening for connections forever in a &lt;code&gt;while&lt;/code&gt; loop,
calling &lt;code&gt;socket.accept&lt;/code&gt; to accept incoming connections on that socket.
Something to note here is that the &lt;code&gt;socket.accept&lt;/code&gt; call actually returns a new socket when a client &lt;code&gt;connects&lt;/code&gt; to it:
a new socket is created for the connection ready to &lt;code&gt;send&lt;/code&gt; and &lt;code&gt;recv&lt;/code&gt;,
and the original socket continues to listen for new connections &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Client-side&lt;/strong&gt;: The client side is simple:
we just use &lt;code&gt;socket.connect&lt;/code&gt; to connect to the remote socket.&lt;/p&gt;
&lt;p&gt;Here&#39;s what that looks like on the server side:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ml_model.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AF_INET&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SOCK_STREAM&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; sock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setsockopt&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SOL_SOCKET&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SO_REUSEADDR&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    server_address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;server_address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;listen&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;waiting for a connection&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            connection&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; client_address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accept&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And on the client-side:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# webcam_stream.py&lt;/span&gt;
server_address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;localhost&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AF_INET&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SOCK_STREAM&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; sock&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;server_address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once a connection has been accepted we can start the bidirectional sending.
Sadly it&#39;s not as simple as sending the image and receiving the bounding boxes.
There are two main complications:
&lt;em&gt;serialisation&lt;/em&gt; and &lt;em&gt;deserialisation&lt;/em&gt; of the data, and
knowing when the message has ended.&lt;/p&gt;
&lt;h3 id=&quot;serialising-and-deserialising-the-data&quot; tabindex=&quot;-1&quot;&gt;Serialising and deserialising the data&lt;/h3&gt;
&lt;p&gt;The first main complication is
how to send numpy arrays over the TCP connection,
because a TCP connection only accepts bytes.
One way to do it would be to
simply convert the numpy arrays into a string,
convert that into a bytestring using &lt;code&gt;bytes()&lt;/code&gt;,
and send that.&lt;/p&gt;
&lt;p&gt;There&#39;s a better way to do it though.
I use Numpy&#39;s built-in &lt;code&gt;np.save&lt;/code&gt; and &lt;code&gt;np.load&lt;/code&gt;
to write and read to a &lt;code&gt;BytesIO&lt;/code&gt; object,
which is basically a file AFAIK.
The BytesIO file can simply be &lt;code&gt;file.read()&lt;/code&gt; and sent over.&lt;/p&gt;
&lt;p&gt;Take note that writing to a file places a pointer to the end of the file
(not sure how this works)
so we&#39;ll need to do &lt;code&gt;file.seek(0)&lt;/code&gt;to seek to the start of the file
in order to read the file with &lt;code&gt;file.read&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&#39;s what that looks like:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;message &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BytesIO&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;save&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; img&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;seek&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
sock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sendall&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# sock is the connected socket&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When receiving a response we simply use
&lt;code&gt;file.write()&lt;/code&gt; to write to a new &lt;code&gt;BytesIO&lt;/code&gt; object.
and &lt;code&gt;np.load&lt;/code&gt; to get it back into an numpy array.&lt;/p&gt;
&lt;h3 id=&quot;knowing-when-the-message-has-ended&quot; tabindex=&quot;-1&quot;&gt;Knowing when the message has ended&lt;/h3&gt;
&lt;p&gt;TCP connections are open-ended, which means that the receiving server
doesn&#39;t know when to stop receiving.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.python.org/3/howto/sockets.html&quot;&gt;This Python sockets guide&lt;/a&gt;
puts it nicely:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;...you need to realize that there is no EOT on a socket...
If the connection has not been broken, you may wait on a recv forever, because
the socket will not tell you that there’s nothing more to read (for now). Now
if you think about that a bit, you’ll come to realize a fundamental truth of
sockets: messages must either be fixed length (yuck), or be delimited (shrug),
or indicate how long they are (much better), or end by shutting down the
connection.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The simplest way to solve this problem is to simply close the connection
after we&#39;ve sent out the image.
But we don&#39;t want to close the connection because
we want to get a response back from the server
(namely, the bounding boxes).
So we&#39;ll have to specify the message length instead. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;
We&#39;ll simply prepend the message with the message length.
The problem is that the message length itself can also vary,
so we&#39;ll need to pad it to ensure the first &lt;code&gt;N&lt;/code&gt; bytes will be guaranteed to be the header.
If you don&#39;t pad the message length then you might read part of the array in
as your message length.&lt;/p&gt;
&lt;p&gt;First we save the &lt;code&gt;numpy&lt;/code&gt; array into a &lt;code&gt;BytesIO&lt;/code&gt; object using &lt;code&gt;np.save&lt;/code&gt;.
We can get the message length using &lt;code&gt;message.getbuffer().nbytes&lt;/code&gt;,
and can pad the message length string using Python&#39;s string formatting.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# webcam_stream.py&lt;/span&gt;
msg_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getbuffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nbytes
HEADER_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;
b_msg_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;msg_len&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;HEADER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;:&amp;lt;{HEADER_SIZE}&lt;/code&gt; thing right-pads the formatted string with zeros
so that it is exactly 10 characters long.
Here&#39;s an example of what that looks like:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&#39;12345&#39;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;&amp;lt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&#39;12345     &#39;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;&amp;lt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;b&#39;12345     &#39;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;&amp;lt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token string&quot;&gt;&#39;12345     &#39;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# on the server side&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;&amp;lt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;utf-8&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;12345&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the Docker container we first receive the message length and decode it.
&lt;strong&gt;(Note that since we are using UTF-8 encoding, a numeric string of length 10
will be 10 bytes long!)&lt;/strong&gt;
We then keep receiving until the number of bytes we&#39;ve received
equals the message length.
We then send it to the object detection model
(calling the &lt;code&gt;detect&lt;/code&gt; function)
and send the bounding boxes back.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# ml_model.py&lt;/span&gt;
HEADER_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# First receive the header to know how long the message is:&lt;/span&gt;
b_msg_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recv&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HEADER_SIZE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
msg_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b_msg_len&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;decode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;utf-8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Then receive the data in small chunks until we receive msg_len bytes&lt;/span&gt;
full_data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BytesIO&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;full_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getbuffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nbytes &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; msg_len&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;recv&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    full_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
full_data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;seek&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;All data received!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Now loading and using the object detection model&lt;/span&gt;
img &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;load&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;full_data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; allow_pickle&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
bboxes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; detect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Sending data back to the client&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
bbox_bytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BytesIO&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;save&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bbox_bytes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bboxes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
bbox_bytes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;seek&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sendall&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bbox_bytes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This solution has its limitations: it won&#39;t work if
we wanted to send multiple images in a single connection.
If we sent multiple messages then there would be no guarantee
that the first 10 (or whatever) bytes of the message buffer
would be the message length.
But since we close the socket and re-open a new one after each frame,
this is not a problem.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Don&#39;t quite understand the implications of this fact, have to do more research &lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;From https://beej.us/guide/bgnet/html/ &lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;HTTP specifies message length using a &amp;quot;Content Length&amp;quot; or &amp;quot;Transfer Encoding&amp;quot; header field: see
&lt;a href=&quot;https://stackoverflow.com/questions/4824451/detect-end-of-http-request-body#4824738&quot;&gt;this SO link&lt;/a&gt;
for details. &lt;a href=&quot;https://lieuzhenghong.com/bidirectional_socket_communication_with_a_docker_container_and_its_host/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>How to install librealsense and pyrealsense2 on the Jetson NX</title>
    <link href="https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/"/>
    <updated>2020-11-04T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/#prerequisites&quot;&gt;Prerequisites&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/#instructions&quot;&gt;Instructions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/how_to_install_librealsense_on_the_jetson_nx/#future-extensions&quot;&gt;Future extensions&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;GitHub issue &lt;a href=&quot;https://github.com/IntelRealSense/librealsense/issues/7722&quot;&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m going to send in a PR today just to contribute back to the community.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pyrealsense2&lt;/code&gt; is a set of Python bindings for Intel&#39;s &lt;code&gt;librealsense&lt;/code&gt; library.
It is needed to run the
&lt;a href=&quot;https://dev.intelrealsense.com/docs/python2&quot;&gt;code examples showing how to use LibRealSense&#39;s Python wrapper&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This set of instructions is a synthesis of both READMEs here:
&lt;a href=&quot;https://github.com/IntelRealSense/librealsense/blob/master/doc/distribution_linux.md&quot;&gt;Build LibRealSense from source&lt;/a&gt;
&lt;a href=&quot;https://github.com/IntelRealSense/librealsense/tree/master/wrappers/python#building-from-source&quot;&gt;Build Python Wrappers&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Neither of the READMEs give a full set of instructions to follow;
each of them is missing some piece.
I have thus written this how-to mainly for myself to reference in the future,
but also in the hopes that it might save some others&#39; time.
These commands have been tested to work on the Jetson NX running Ubuntu 18.04
and using Python 3.6.9.&lt;/p&gt;
&lt;p&gt;This how-to provides a complete set of instructions to install &lt;code&gt;librealsense&lt;/code&gt;
and its bindings on the Jetson NX.&lt;/p&gt;
&lt;h2 id=&quot;prerequisites&quot; tabindex=&quot;-1&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;You should first disconnect your RealSense Camera if it is connected,
because the &lt;code&gt;/setup_udev_rules.sh&lt;/code&gt; bash script requires your camera to be disconnected.&lt;/p&gt;
&lt;h2 id=&quot;instructions&quot; tabindex=&quot;-1&quot;&gt;Instructions&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Installs librealsense and pyrealsense2 on the Jetson NX running Ubuntu 18.04&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# and using Python 3&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Tested on a Jetson NX running Ubuntu 18.04 and Python 3.6.9&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; upgrade
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; --no-install-recommends &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    python3 &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    python3-setuptools &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    python3-pip &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
	python3-dev

&lt;span class=&quot;token comment&quot;&gt;# Install the core packages required to build librealsense libs&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; libssl-dev libusb-1.0-0-dev pkg-config libgtk-3-dev
&lt;span class=&quot;token comment&quot;&gt;# Install Distribution-specific packages for Ubuntu 18&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; libglfw3-dev libgl1-mesa-dev libglu1-mesa-dev

&lt;span class=&quot;token comment&quot;&gt;# Install LibRealSense from source&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# We need to build from source because&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# the PyPi pip packages are not compatible with Arm processors.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# See link [here](https://github.com/IntelRealSense/librealsense/issues/6964).&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# First clone the repository&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/IntelRealSense/librealsense.git
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ./librealsense

&lt;span class=&quot;token comment&quot;&gt;# Make sure that your RealSense cameras are disconnected at this point&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Run the Intel Realsense permissions script&lt;/span&gt;
./scripts/setup_udev_rules.sh

&lt;span class=&quot;token comment&quot;&gt;# Now the build&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; build &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; build
&lt;span class=&quot;token comment&quot;&gt;## Install CMake with Python bindings (that&#39;s what the -DBUILD flag is for)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## see link: https://github.com/IntelRealSense/librealsense/tree/master/wrappers/python#building-from-source&lt;/span&gt;
cmake &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;/ &lt;span class=&quot;token parameter variable&quot;&gt;-DBUILD_PYTHON_BINDINGS:bool&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true
&lt;span class=&quot;token comment&quot;&gt;## Recompile and install librealsense binaries&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## This is gonna take a while! The -j4 flag means to use 4 cores in parallel&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## but you can remove it and simply run `sudo make` instead, which will take longer&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; uninstall &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; clean &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-j4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;## Export pyrealsense2 to your PYTHONPATH so `import pyrealsense2` works&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;PYTHONPATH&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$PYTHONPATH&lt;/span&gt;:/usr/local/lib/python3.6/pyrealsense2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;librealsense&lt;/code&gt; and &lt;code&gt;pyrealsense2&lt;/code&gt; should now be installed on your computer.
To test this,
download an example Python file
(e.g. &lt;a href=&quot;https://github.com/IntelRealSense/librealsense/blob/master/wrappers/python/examples/opencv_viewer_example.py&quot;&gt;opencv_viewer_example.py&lt;/a&gt;)
and run it with &lt;code&gt;python3 opencv_viewer_example.py&lt;/code&gt;.
You should expect to see a window with both RGBA and depth output.&lt;/p&gt;
&lt;h2 id=&quot;future-extensions&quot; tabindex=&quot;-1&quot;&gt;Future extensions&lt;/h2&gt;
&lt;p&gt;I&#39;m currently trying to build a Dockerfile based on this set of instructions.
Let me know if the instructions don&#39;t work for you by emailing me at
&lt;code&gt;lieu(at)lieuzhenghong(dotcom)&lt;/code&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Pair work: the One Weird Trick to finally ship your side projects</title>
    <link href="https://lieuzhenghong.com/explorations/pair_work/"/>
    <updated>2020-10-08T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/explorations/pair_work/</id>
    <content type="html">&lt;div class=&quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#pair-work-acts-as-a-commitment-device&quot;&gt;Pair work acts as a commitment device&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#pair-work-helps-remove-blockers&quot;&gt;Pair work helps remove blockers&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#pair-work-puts-everyone-on-the-same-page&quot;&gt;Pair work puts everyone on the same page&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#caveats&quot;&gt;Caveats&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#why-this-eluded-me-for-the-longest-time&quot;&gt;Why this eluded me for the longest time&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/pair_work/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Epistemic status: somewhat uncertain.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I may have stumbled upon the &lt;em&gt;One Weird Trick&lt;/em&gt; for maintaining momentum
on side projects. If your side projects are collaborative (most of mine are,
these days), the following (which I call &lt;em&gt;pair work&lt;/em&gt;) really helps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Commit to a date and time period (~2h) with your partner.&lt;/li&gt;
&lt;li&gt;Get on a call.&lt;/li&gt;
&lt;li&gt;One person shares screen. You might use a collaborative editor.&lt;/li&gt;
&lt;li&gt;Work together.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This feels so pedestrian that it doesn&#39;t seem worth writing about.
Maybe everyone already does this but somehow I&#39;ve missed the memo.
In any case---if you haven&#39;t been doing this already, I highly recommend trying it.&lt;/p&gt;
&lt;p&gt;I want to distinguish &lt;em&gt;pair work&lt;/em&gt; from &lt;em&gt;group work&lt;/em&gt;.
&amp;quot;Group work&amp;quot; often means
to portion out a task into smaller subtasks and
assign each person a small bit.&lt;/p&gt;
&lt;p&gt;Also, I specifically use the term &lt;em&gt;pair work&lt;/em&gt; because
I don&#39;t just mean pair &lt;em&gt;programming&lt;/em&gt;---
I believe there are benefits to
pair reading-the-documentation,
pair understanding,
and so on.&lt;/p&gt;
&lt;p&gt;I can personally vouch for the effectiveness of this strategy,
particularly if you have a project that&#39;s been mothballed for quite a while now.
Joshua and I meandered around for weeks without any progress until we decided
to debug together. We got more done in two hours than we did the past three weeks.&lt;/p&gt;
&lt;p&gt;Why and how is pair work so effective?
In my experience, there are three main benefits:
pair work acts as a strong commitment device,
it removes blockers effectively,
and shares information amongst all collaborators &amp;quot;for free&amp;quot;.
It&#39;s very effective despite the apparent loss of parallel productivity
because the bottleneck in knowledge-based side projects is not raw productivity,
but rather motivation, faulty assumptions, and incomplete information.&lt;/p&gt;
&lt;h2 id=&quot;pair-work-acts-as-a-commitment-device&quot; tabindex=&quot;-1&quot;&gt;Pair work acts as a commitment device&lt;/h2&gt;
&lt;p&gt;This is by far the most important benefit to me.
When I start side projects, I always want to work on them but other life stuff
gets in the way: be it revising for exams, preparing for a job interview,
meeting friends, binge watching YouTube, and the like.
Making a public commitment to someone gets you 80% of the way there
because you&#39;ll be afraid to let them down.
But setting a time to &lt;em&gt;work together&lt;/em&gt; with a collaborator gets you the last 20%, because
without the commitment to work together it&#39;s too easy to come up
with plausible-sounding reasons to excuse yourself.&lt;/p&gt;
&lt;h2 id=&quot;pair-work-helps-remove-blockers&quot; tabindex=&quot;-1&quot;&gt;Pair work helps remove blockers&lt;/h2&gt;
&lt;p&gt;Even if you sometimes have the motivation,
you might be put off by a tedious part of the project.
This is me whenever I&#39;m faced with &amp;quot;weed-clearing&amp;quot; work like setting up builds
or debugging &lt;code&gt;import&lt;/code&gt; incompatibilities.
The problem is that the tedious parts of the project still need to be done,
and the more you put it off the more you ruin your productivity.
Tedious work is much less so when done together with your collaborator.&lt;/p&gt;
&lt;p&gt;Working together also helps
when you don&#39;t have a clue about how to tackle a particular problem.
For instance, I was stuck on a pretty nasty bug when building the board game engine,
which blocked me for days as I would dread even &lt;em&gt;trying&lt;/em&gt; to solve the problem
after banging my head against it fruitlessly for so long.&lt;/p&gt;
&lt;p&gt;Talking through a bug with someone else helps a lot;
talking through a bug with someone else &lt;em&gt;also involved in the project&lt;/em&gt;
helps immensely.
And obviously two minds are better than one;
any problem that appeared insurmountable alone always seems to fall quite quickly.&lt;/p&gt;
&lt;p&gt;Pair work also surfaces incorrect assumptions.
Most (if not all) misunderstandings arise because one person has a faulty assumption/
mental model.
Through the process of argument and discussion that naturally occurs in pair work,
these assumptions can quickly be uncovered.&lt;/p&gt;
&lt;p&gt;For instance, Joshua is a very experienced data scientist but has little JS experience.
He had an incorrect understanding of &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt;
(specifically, he didn&#39;t believe that &lt;code&gt;await&lt;/code&gt; blocked execution)
and thus he incorrectly rewrote my code.
But when working together, I was able to surface this incorrect assumption.
This misunderstanding might otherwise have gone unnoticed for a long time.&lt;/p&gt;
&lt;h2 id=&quot;pair-work-puts-everyone-on-the-same-page&quot; tabindex=&quot;-1&quot;&gt;Pair work puts everyone on the same page&lt;/h2&gt;
&lt;p&gt;It may be faster initially for two people to split up and work on different things,
but this causes two silos of knowledge to be formed.
This slows future progress
unless significant time is invested familiarising one other with the
knowledge of each part.
The cost of &lt;code&gt;brain merge&lt;/code&gt;-ing may be greater than
the gains from parallelisation.&lt;/p&gt;
&lt;p&gt;This happened when Joshua read up on the multiplayer server architecture
and I did all the client-side work.
But that meant that Joshua knew nothing about what I was doing on the client side
and what difficulties I was facing, and &lt;em&gt;vice versa&lt;/em&gt; for me.
This would result in us often talking past each other
when discussing how to implement new features.
With such a small team and such an interconnected codebase
we couldn&#39;t &lt;em&gt;not&lt;/em&gt; know every part of the system.
Had we worked together from the start, initial progress would be slower
but overall progress would be faster.&lt;/p&gt;
&lt;h2 id=&quot;caveats&quot; tabindex=&quot;-1&quot;&gt;Caveats&lt;/h2&gt;
&lt;p&gt;This doesn&#39;t work without a partner, obviously.
There are also some tasks where you &lt;em&gt;do&lt;/em&gt; want to work in parallel,
like tasks of an exploratory nature e.g. lit review (just to cast a wider net),
or trivial tasks where being blocked is not an issue.&lt;/p&gt;
&lt;p&gt;You might also get frustrated sometimes if you and your partner disagree on what to do
or how to do something.&lt;/p&gt;
&lt;p&gt;You could probably do pair work with three people (trio work?),
but no more than that.
So this would not be feasible with extremely large projects or extremely
large teams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: Thanks also to Ben Kuhn for pointing out that pair work doesn&#39;t work well
when there is a big gulf of understanding/knowledge between the partners.&lt;/p&gt;
&lt;h2 id=&quot;why-this-eluded-me-for-the-longest-time&quot; tabindex=&quot;-1&quot;&gt;Why this eluded me for the longest time&lt;/h2&gt;
&lt;p&gt;I had conflated pair work with group work.
I hated group work in school.
Everyone felt that everyone else was not doing their fair share of the work,
or believed that others&#39; work was not up to snuff.
It was overall a very grim experience,
and I just assumed that would translate to pair work as well:
that&#39;s just setting N=2, right?
But there&#39;s a world of a difference between
&lt;em&gt;working as a group of two&lt;/em&gt; (splitting the work half-half)
and &lt;em&gt;working as a pair&lt;/em&gt; (doing all the work together).&lt;/p&gt;
&lt;p&gt;Now that I&#39;ve started working as a pair I really can&#39;t recommend it enough.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;So far, I&#39;ve found pair working extremely effective:
primarily as a commitment device
but also
with the (significant) side benefits of being able to unblock yourself quicker
and having knowledge automatically shared amongst collaborators.&lt;/p&gt;
&lt;p&gt;If you do try it out (or have already been practicing it for a while),
I&#39;d love to hear from you about your experiences, and if there are any
pitfalls to watch out for---shoot me an email.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Home gym ideas</title>
    <link href="https://lieuzhenghong.com/home-gym-ideas/"/>
    <updated>2020-09-27T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/home-gym-ideas/</id>
    <content type="html">&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Rather than pay $1,000 for a gym membership my neighbour Bryan and I
are thinking about building our own home gym.&lt;/p&gt;
&lt;p&gt;https://www.tworepcave.com/10581/outdoor-home-gyms-how-to-avoid-rust-or-uv-damage/amp/&lt;/p&gt;
&lt;p&gt;https://medium.com/@johngreavesiii/easy-ways-to-protect-outdoor-gym-equipment-961b72727e6c&lt;/p&gt;
&lt;p&gt;https://garagegymlab.com/ultimate-guide-budget-home-gym/&lt;/p&gt;
&lt;p&gt;Titan Racks:&lt;/p&gt;
&lt;p&gt;https://www.titan.fitness/racks/power-racks/t-3-series/?start=0&amp;amp;sz=30&lt;/p&gt;
&lt;p&gt;10 Best Budget Gyms:&lt;/p&gt;
&lt;p&gt;https://garagegymreviews.com/best-budget-home-gym-setups&lt;/p&gt;
&lt;p&gt;How to build a Home Gym on the Cheap&lt;/p&gt;
&lt;p&gt;https://www.artofmanliness.com/articles/how-to-build-a-home-gym-on-the-cheap/&lt;/p&gt;
&lt;h1 id=&quot;update-4th-october-2020&quot; tabindex=&quot;-1&quot;&gt;Update 4th October 2020&lt;/h1&gt;
&lt;p&gt;Discussed with Bryan: either put it inside my room or outside in the space between
both of our houses.&lt;/p&gt;
&lt;p&gt;Prices are actually pretty reasonable: should be &amp;lt;$2000 for the entire set.&lt;/p&gt;
&lt;p&gt;Got the link from Marc: &lt;a href=&quot;https://www.directhomegym.sg/&quot;&gt;directhomegym.sg&lt;/a&gt; ---
no name Chinese brand that Marc used for his home gym&lt;/p&gt;
&lt;h1 id=&quot;update-7th&quot; tabindex=&quot;-1&quot;&gt;Update 7th&lt;/h1&gt;
&lt;h1 id=&quot;update-9th-october-2020&quot; tabindex=&quot;-1&quot;&gt;Update 9th October 2020&lt;/h1&gt;
&lt;p&gt;I did some research and standing racks are right out because they take up far
too much space.&lt;/p&gt;
&lt;h1 id=&quot;update-sunday-10th-october-2020&quot; tabindex=&quot;-1&quot;&gt;Update Sunday 10th October 2020&lt;/h1&gt;
&lt;p&gt;Bryan seems to be having cold feet about the whole thing.
He balked at the price.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Virtual workspaces --- working in a Minecraft office?</title>
    <link href="https://lieuzhenghong.com/explorations/virtual_workspaces/"/>
    <updated>2020-09-26T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/explorations/virtual_workspaces/</id>
    <content type="html">&lt;div class=&quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#meta-introduction&quot;&gt;Meta-introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#the-virtual-workspace&quot;&gt;The virtual workspace&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#what-some-solutions-look-like-now---spatial-vr%2C-infinite-office&quot;&gt;What some solutions look like now---Spatial VR, Infinite Office&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#the-video-game-world-as-virtual-workspace&quot;&gt;The video game world as virtual workspace&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#why-i-think-this-could-be-a-good-idea&quot;&gt;Why I think this could be a good idea&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#what-you&#39;ve-written-seems-like-shitty-creative-writing!-what&#39;s-the-point-of-all-this%3F&quot;&gt;What you&amp;#39;ve written seems like shitty creative writing! What&amp;#39;s the point of all this?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#this-is-making-my-workflow-harder-on-purpose!&quot;&gt;This is making my workflow harder on purpose!&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#why-minecraft%3F&quot;&gt;Why Minecraft?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#why-spatiality-is-important-in-a-virtual-workspace&quot;&gt;Why spatiality is important in a virtual workspace&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#why-community-is-important-in-a-virtual-workspace&quot;&gt;Why community is important in a virtual workspace&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#examples-in-the-wild&quot;&gt;Examples in the wild&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/virtual_workspaces/#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;meta-introduction&quot; tabindex=&quot;-1&quot;&gt;Meta-introduction&lt;/h2&gt;
&lt;p&gt;I used to write posts on my blog very infrequently
because I dreaded the enormous effort and time commitment it needed.&lt;/p&gt;
&lt;p&gt;In order to increase my output
(rather than constantly having a backlog of posts)
I&#39;m going to be trying a slightly new direction:
writing shorter posts once I get a germ of an idea,
rather than having to have something fully fleshed-out already.&lt;/p&gt;
&lt;p&gt;So these posts are going to be incomplete, imperfect, and incorrect even.
They may not have a clear thesis or introduction and certainly won&#39;t
have a clear answer.
You can think of them as &amp;quot;scratchpad&amp;quot; posts.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Time taken to write this post: ~4 hours&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;I have recently moved back home, after finishing Oxford, and&lt;/li&gt;
&lt;li&gt;I have recently started full-time employment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;My sister took my room while I was at Oxford, and so I&#39;ve had to
rethink what sort of room I wanted to have and how to set it up
so I could have an effective/ergonomic home office arrangement.&lt;/p&gt;
&lt;p&gt;Once I started work I realised that this was only one part of the puzzle.
It&#39;s one thing to have an ergonomic working arrangement
with a standing desk and a split keyboard and external monitors and what not
(I have none of those things).
But there&#39;s another piece of the puzzle: how does one stay motivated while
working from home?
Let me list some of the issues about working from home that I&#39;ve experienced.&lt;/p&gt;
&lt;p&gt;First is simply that there isn&#39;t really a separation between work and play.
The only place I can work is in my room, but at the same time the only place
I can unwind without distractions is also in my room.
And as a i) a software engineer and ii) a sweaty nerd
I use the same laptop for both work and play. This problem was most noticeable when
I was living alone in the hotel room serving my SHN for two entire weeks.&lt;/p&gt;
&lt;p&gt;The fact that there is no separation between work and play matters
because it means that either i) I will get distracted during work, or
ii) work will bleed into my non-work protected periods.&lt;/p&gt;
&lt;p&gt;The second issue about working from home is that of isolation.
So I&#39;ve started working at IMDA for about two weeks now and until now I
haven&#39;t any clue what my colleagues look like (except my ex-colleagues whom
I met during my internship back in Summer 2018).
And even though we are supposedly a project &amp;quot;team&amp;quot;, I get the feeling that we&#39;re
just different people working on different things.
Also the serendipity is gone. When I was doing my internship I could walk around
the office and ask my colleagues what they were working on/ they could give me
advice on whatever I was working on.
Nowadays, even though someone is technically just only a call away,
you won&#39;t want to interrupt them.
The serendipity and the sense of community is greatly reduced.&lt;/p&gt;
&lt;p&gt;Basically, isolation isn&#39;t just a mental health thing ---
it&#39;s also really about camaraderie and the relationship that
one has with one&#39;s coworkers.&lt;/p&gt;
&lt;p&gt;So I&#39;ve been thinking about these three main questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How can I improve the &lt;em&gt;physical&lt;/em&gt; ergonomics of my workspace?&lt;/li&gt;
&lt;li&gt;How can I improve the &lt;em&gt;mental&lt;/em&gt; ergonomics of my workspace?
&lt;ul&gt;
&lt;li&gt;how can I prevent myself from being distracted/ prevent work thoughts
from spilling into my leisure time?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;How can I be less isolated while working from home?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;and I don&#39;t have the answer, but I thought I&#39;d present the &lt;em&gt;virtual workspace&lt;/em&gt;
as a possible solution.&lt;/p&gt;
&lt;h2 id=&quot;the-virtual-workspace&quot; tabindex=&quot;-1&quot;&gt;The virtual workspace&lt;/h2&gt;
&lt;p&gt;What do I mean by a virtual workspace? I define it as a &lt;em&gt;spatial&lt;/em&gt;, &lt;em&gt;multi-user&lt;/em&gt;
virtual world where one can&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;create and move around a customisable space, and&lt;/li&gt;
&lt;li&gt;concurrently do your work tasks (check email, write documents, program...)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I believe a good virtual workspace must be spatial and multi-user.
Additionally, a good virtual workspace should at least be somewhat structured
to &lt;em&gt;encourage&lt;/em&gt; work being done in it. I&#39;ll explain all of these things shortly.&lt;/p&gt;
&lt;h3 id=&quot;what-some-solutions-look-like-now---spatial-vr%2C-infinite-office&quot; tabindex=&quot;-1&quot;&gt;What some solutions look like now---Spatial VR, Infinite Office&lt;/h3&gt;
&lt;p&gt;I&#39;d recommend taking a look at
&lt;a href=&quot;https://spatial.io/&quot;&gt;Spatial&lt;/a&gt;,
&lt;a href=&quot;https://www.vspatial.com/&quot;&gt;vSpatial&lt;/a&gt;, and
&lt;a href=&quot;https://techcrunch.com/2020/09/16/facebook-debuts-infinite-office-a-virtual-reality-office-space/&quot;&gt;Infinite Office&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here are some random screencaps of Spatial,
Spatial VR and Facebook Infinite Office:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/1.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/2.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/3.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/4.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/5.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/6.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/7.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Infinite Office has a very slick video with an attractive woman demonstrating
how to use the Infinite Office.&lt;/p&gt;
&lt;p&gt;I think these solutions are pretty good. They solve the problem of physical
ergonomics (somewhat) by allowing you to be productive almost anywhere in your house, with as many monitors as you&#39;d like
(the VR headset looked cordless in that very slick Infinite Office video).
Spatial gives you a shared virtual office with your coworkers and you can
manipulate 3D virtual objects together in that virtual office space.
Finally, these solutions solve the problem of &amp;quot;mental ergonomics&amp;quot;
with virtual avatars of your colleagues in your &amp;quot;virtual desktop&amp;quot; or &amp;quot;virtual office&amp;quot;.&lt;/p&gt;
&lt;p&gt;There are two shortcomings with this solution, however.
Firstly, they rely heavily on VR to deliver an immersive experience, and
most people don&#39;t have a VR headset yet (I also don&#39;t know whether it&#39;s good
for your eyes to be constantly looking at the VR screens).
And secondly, there&#39;s already one group of programs that are very good at creating attractive spaces that people want to spend time in---video games.
Could we adapt the video game world into a virtual workspace?&lt;/p&gt;
&lt;h3 id=&quot;the-video-game-world-as-virtual-workspace&quot; tabindex=&quot;-1&quot;&gt;The video game world as virtual workspace&lt;/h3&gt;
&lt;p&gt;Video games function very nicely as virtual &lt;a href=&quot;https://en.wikipedia.org/wiki/Third_place&quot;&gt;&amp;quot;third places&amp;quot;&lt;/a&gt; ---
a place separate from home (first place) and
the workplace (second place)
where people hang out, relax, and banter.
I know I&#39;ve spent hundreds of hours collectively
hanging around Henesys or Kerning City in MapleStory,
chilling in Habbo Hotel,
or skilling and chatting around Burthorpe/Lumbridge in RuneScape.
The big question is: could they function as &amp;quot;second places&amp;quot; as well?&lt;/p&gt;
&lt;p&gt;I think they could.
I think a very nice virtual workplace that got 80% of the way there
could be realised
using Minecraft in Creative Mode with some mods:&lt;/p&gt;
&lt;p&gt;In the morning we log in into the multiplayer Minecraft server
and find ourselves in a penthouse suite we built ourselves
with a lovely view of the sunrise.
(The day-night cycle has been tweaked such that it corresponds
to the real day-night cycle of our physical location).
We head into a office---a building that
looks like an enormous castle from the outside but is actually a modern
office inside---by &lt;code&gt;/fly&lt;/code&gt;ing there.
There are already people working in the office
(these could be your colleagues or other friends/random people),
and you can greet them if you so choose.
You walk to your office---kitted out to your exact specifications---
and begin work for the day.&lt;/p&gt;
&lt;p&gt;First you check your mail. You walk to a special mailbox block
and right-click it. This opens up Thunderbird (or your mail client of choice)
in a pop-up window, and you respond to the new mails.
You note that you have been given several new tasks.
You close the mailbox block and your mail client also minimises to the background.
You now walk to your enormous whiteboard in your office
and add new notes to that whiteboard by
right-clicking the whiteboard and typing a note.
Looking at the whiteboard, you take stock of the tasks you still need to do
and formulate a game plan.&lt;/p&gt;
&lt;p&gt;Okay, now it&#39;s time to code. You click another custom block and it opens
Visual Studio Code (or your IDE of choice). You start working on the first task
on the list.&lt;/p&gt;
&lt;p&gt;You need to look up some documentation. You right-click a book labelled
&amp;quot;MDN Reference&amp;quot; on your bookshelf and the MDN reference opens up within the
Minecraft window, left of your VSCode IDE window. You find what you want to find
and close the book.&lt;/p&gt;
&lt;p&gt;Some time later, there&#39;s a ring at the doorbell and you let the person in.
It&#39;s your colleague who has come to catch up and ask you for help with a technical
problem that they&#39;re having. You help him work through it with pair programming
through the shared IDE extension on VSCode.&lt;/p&gt;
&lt;p&gt;After some time, you decide it&#39;s time to take a break. In the physical world,
you put the kettle on. While the water boils,
you leave your (virtual) office
and go to the common area where people are milling around.
You have some small talk in the common area with the regulars of this office
while sipping your tea, asking how their day went and what progress they&#39;ve made.&lt;/p&gt;
&lt;p&gt;Another few hours passes and the sun is setting.
You&#39;re done for the day.
You update the whiteboard, &lt;code&gt;/fly&lt;/code&gt; back home,
and exit the Minecraft server
(or you could continue working on your side projects in the comfort of your own
Minecraft home).&lt;/p&gt;
&lt;h2 id=&quot;why-i-think-this-could-be-a-good-idea&quot; tabindex=&quot;-1&quot;&gt;Why I think this could be a good idea&lt;/h2&gt;
&lt;h3 id=&quot;what-you&#39;ve-written-seems-like-shitty-creative-writing!-what&#39;s-the-point-of-all-this%3F&quot; tabindex=&quot;-1&quot;&gt;What you&#39;ve written seems like shitty creative writing! What&#39;s the point of all this?&lt;/h3&gt;
&lt;p&gt;Okay, I know this sounds a lot like shitty creative writing.
That notwithstanding, I think such a virtual office would have several advantages:&lt;/p&gt;
&lt;p&gt;Firstly, the spatial nature of the virtual world
enforces a strong separation between work and play.
My personal experience is that moving to a different physical location helps
me very much in avoiding procrastination / getting into a work mood.
I&#39;d often go to OWL to study even though my room was an objectively better place
to study (external monitor, larger table..)
just because the act of going to OWL got me in the right mood.
Ditto with heading to the Inzura office during the weekend to work on the game
jam/self-study CS.
Another anecdotal ritual: Tak Huen used to put on a nice shirt
and tie before sitting at his desk to study for finals---he said it helped him
get into the right mindset.
In this case, the act of opening the Minecraft server and traveling to the virtual
workplace and walking to the corner office
is a ritual that tries to imitate the &lt;em&gt;actual&lt;/em&gt; ritual of going to the office
in the age of Covid-19/without the long commmute.
Personally I already try to shutdown my computer and start fresh every day
but this ritual just isn&#39;t strong enough to get me in the mood sometimes.&lt;/p&gt;
&lt;h3 id=&quot;this-is-making-my-workflow-harder-on-purpose!&quot; tabindex=&quot;-1&quot;&gt;This is making my workflow harder on purpose!&lt;/h3&gt;
&lt;p&gt;or, &amp;quot;Why would I walk around clicking things when I can just Alt-Tab?&amp;quot;&lt;/p&gt;
&lt;p&gt;IMO, this is a feature, not a bug. The bottleneck to how much work I get done in
a day is not at all how fast I can look up documentation.
The bottleneck is my motivation and focus.
Notice in the example that individual sites are keyed to books on a bookshelf.
This means that you won&#39;t be able to easily browse the web or get otherwise
distracted if you stay in this Minecraft environment.
If you want to check email/WhatsApp/Telegram you&#39;ll have to click the correct
blocks, and the fact that you have to do that makes that action &lt;em&gt;deliberate&lt;/em&gt;
rather than a reflex almost.&lt;/p&gt;
&lt;h3 id=&quot;why-minecraft%3F&quot; tabindex=&quot;-1&quot;&gt;Why Minecraft?&lt;/h3&gt;
&lt;p&gt;It doesn&#39;t necessarily have to be Minecraft -- it could be any virtual world
like Habbo Hotel, Second Life, Runescape, Maplestory, Animal Crossing, WoW, etc...
I think Minecraft is particularly attractive because i) you can mod it easily,
ii) you have the ability to build your own spaces in a very customisable way.
Also, these other games are too &amp;quot;fun&amp;quot;---there&#39;s too much to do and I think the
temptation to play the game would be too great. Whereas there really isn&#39;t much
to do in MC Creative Mode.&lt;/p&gt;
&lt;h3 id=&quot;why-spatiality-is-important-in-a-virtual-workspace&quot; tabindex=&quot;-1&quot;&gt;Why spatiality is important in a virtual workspace&lt;/h3&gt;
&lt;p&gt;Virtual places with no spatial component exist: I am a avid user of Complice,
where there are workrooms you can join that follow a common Pomodoro timer.
But I think they&#39;re inferior---it&#39;s too easy to ignore the workroom.
I think humans are intensely spatial creatures and we need to be immersed in an
actual space for us to get the full advantages of productivity/connection.
Also, the fact that you&#39;re ensconced in an actual world
where you can only access a curated subset of programs/websites
helps prevent procrastination. If you had a nonspatial world it would just
be another window you could Alt-Tab away.&lt;/p&gt;
&lt;h3 id=&quot;why-community-is-important-in-a-virtual-workspace&quot; tabindex=&quot;-1&quot;&gt;Why community is important in a virtual workspace&lt;/h3&gt;
&lt;p&gt;You could also do this in a single-player world but this wouldn&#39;t address the
problem of isolation. Just as important as the work itself is the rest and
serendipitous chats with coworkers/&amp;quot;co-worlders&amp;quot;.
At the same time, the fact that everyone has their own private room means that
there&#39;s a quiet sanctum for you to do deep work without being interrupted.&lt;/p&gt;
&lt;h3 id=&quot;examples-in-the-wild&quot; tabindex=&quot;-1&quot;&gt;Examples in the wild&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.recurse.com/virtual-rc&quot;&gt;Recurse RC&lt;/a&gt;
built a very barebones virtual world that ticks a lot of the boxes:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/recurse_rc.gif&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/virtual_workspaces/recurse_rc_2.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is Virtual RC. It’s the social space that Recursers enter when they
start their days while in batch, and we’ve designed it with the goal of
facilitating the kind of serendipitous, synchronous, and ephemeral
interactions we think are so important to the experience of doing RC.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The entire world is editable: you can explore, build walls, change colors,
write notes, add links, and create audio chats. You can share what you’re
working on by leaving a note and see at a glance what’s going on by reading
what others have posted. Each of the colorful rooms has a persistent Zoom
meeting associated with it, which you enter by clicking on it. The map
displays who’s in each room in real time, so you can look for a friend and
pop into a room to say hello — much like in the real world!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The calendar blocks display information about scheduled events going on in
the rooms, so that when you open Virtual RC and look around, you could see
that there’s a machine learning study group going on in Hopper, a video game
interest group in Sammet, and a few people working on projects together at
the pairing stations. There might also be Recursers hanging out in the
virtual kitchen or programming together in the quiet space.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is a pretty offbeat idea, but I&#39;d like to explore this further.
It&#39;s certainly not for everybody, but I think there&#39;s a subset of people
who would really welcome this.
Any and all comments are most welcomed.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Thanks to CKY for talking to me about this&lt;/li&gt;
&lt;li&gt;Thanks to Nick for giving me the link to Recurse RC&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Clustering GPS trip data</title>
    <link href="https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/"/>
    <updated>2020-09-11T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-1.-obtaining-the-data&quot;&gt;Step 1. Obtaining the data&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-2.-cleaning-the-data&quot;&gt;Step 2. Cleaning the data&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-3.-exploring-the-data&quot;&gt;Step 3. Exploring the data&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-4.-reducing-and-normalising-the-data&quot;&gt;Step 4. Reducing and normalising the data&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#principal-component-analysis-(pca)&quot;&gt;Principal component analysis (PCA)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#manual-feature-selection&quot;&gt;Manual feature selection&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-4.-perform-clustering-on-the-normalised-and-reduced-data&quot;&gt;Step 4. Perform clustering on the normalised and reduced data&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#things-that-didn&#39;t-work&quot;&gt;Things that didn&amp;#39;t work&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#hierarchical-clustering-----too-slow&quot;&gt;Hierarchical clustering --- too slow&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#pca-and-then-k-means-clustering-----too-uninterpretable&quot;&gt;PCA and then K-means clustering --- too uninterpretable&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#step-5.-perform-data-analysis-on-those-clusters&quot;&gt;Step 5. Perform data analysis on those clusters&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#why-didn&#39;t-k-means-give-good-clusters%3F&quot;&gt;Why didn&amp;#39;t K-means give good clusters?&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#k-means-clustering-may-not-do-well-with-very-uneven-clusters&quot;&gt;K-means clustering may not do well with very uneven clusters&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#k-means-clustering-cannot-deal-with-intracluster-covariance&quot;&gt;K-means clustering cannot deal with intracluster covariance&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#k-means-tries-to-fit-all-points-to-a-cluster-even-if-they-may-be-outliers&quot;&gt;K-means tries to fit all points to a cluster even if they may be outliers&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#ideas-for-future-work&quot;&gt;Ideas for future work&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#using-the-fact-that-we-have-a-corpus-of-guaranteed-car-trips-for-anomaly-detection&quot;&gt;Using the fact that we have a corpus of guaranteed car trips for anomaly detection&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#running-pca-within-clusters-to-compare-the-difference-between-intracluster-and-intercluster-variance&quot;&gt;Running PCA within clusters to compare the difference between intracluster and intercluster variance&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Over the past month we have developed Inzura&#39;s data science capabilities by
creating a data processing library and formalising a data science workflow.
I used the library and workflow to cluster Inzura&#39;s corpus of over 2 million
anonymised trips.&lt;/p&gt;
&lt;p&gt;The general data science workflow I have set out is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Obtain the data&lt;/li&gt;
&lt;li&gt;Clean the data&lt;/li&gt;
&lt;li&gt;Explore the data&lt;/li&gt;
&lt;li&gt;Repeat (try various different approaches to get best results):
&lt;ul&gt;
&lt;li&gt;Normalise and reduce the dimensionality of the data&lt;/li&gt;
&lt;li&gt;Perform the clustering on the reduced data&lt;/li&gt;
&lt;li&gt;Inspect the clusters to see if they make sense&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-1.-obtaining-the-data&quot; tabindex=&quot;-1&quot;&gt;Step 1. Obtaining the data&lt;/h2&gt;
&lt;p&gt;First, I processed the trip data. Recall that a trip is an &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T \times 5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; matrix
where T is the length of the trip. Because many of the trips have different trip
lengths, it&#39;s impossible to cluster them in this form. I therefore needed
to calculate &lt;em&gt;summary statistics&lt;/em&gt; for the trip so I could compare them to each other.&lt;/p&gt;
&lt;p&gt;After consultation with Richard and David, I wrote functions to calculate
85 different metrics on the &lt;code&gt;formatted.json&lt;/code&gt; data. Some of these metrics include:
median absolute velocity, number of stops normalised by trip duration,
maximum tangential acceleration, bendiness (the sum of turning degrees per second
normalised by trip distance). Importantly, this reduces the dimensionality
of any trip from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T \times 5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; to a constant &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;×&lt;/mo&gt;&lt;mn&gt;85&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1 \times 85&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;×&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;85&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, which makes it much
easier to do analysis on.&lt;/p&gt;
&lt;p&gt;Once I had come up with the metrics and the functions to calculate them,
I had to calculate the metrics for all of the trips. As we had more than
2 million anonymised trips, processing all of them in a reasonable amount of time
would have to leverage parallel computation.&lt;/p&gt;
&lt;p&gt;To this end, I wrote a multiprocessing library with Richard&#39;s help
that made use of the &lt;a href=&quot;https://github.com/ray-project/ray&quot;&gt;Ray library&lt;/a&gt;.
The library automatically handles the distribution of tasks to processes.
Because we didn&#39;t want to lose any progress if e.g. the machine failed,
the library also
saves your progress so you can stop and restart the job anytime,
and logs all errors automatically.
I have already extensively documented the library and how to use it elsewhere
and will not repeat it here.&lt;/p&gt;
&lt;p&gt;Processing all the trips on the old bigbeast took several days,
despite a ~12x speedup from parallelisation. This really hammers home the fact
that we needed parallelisation, or we might still be waiting for the data...&lt;/p&gt;
&lt;h2 id=&quot;step-2.-cleaning-the-data&quot; tabindex=&quot;-1&quot;&gt;Step 2. Cleaning the data&lt;/h2&gt;
&lt;p&gt;After all the trips had been processed we were left with a dataset with
~2 million rows and 85 columns.
I plotted histograms for each column of the data to visualise the distributions.
Doing so allowed me to discover that the data was quite dirty. For instance,
there were trips where the average median velocity was something like 1000m/s,
which is impossible unless the person was on a rocket.
This happens because GPS data can sometimes cut in and out when
signal is bad (e.g driving through a tunnel), which leads to an artificially
inflated velocity/acceleration/whatever have you score.&lt;/p&gt;
&lt;p&gt;I re-plotted the data after removing trips that were patently absurd
(average velocity of &amp;gt; 160km/h, maximum acceleration/decceleration of more than 3Gs,
trips &amp;lt;30s long) and observed that most metrics followed a power law distribution,
with some following a normal distribution.
Velocity and acceleration tended to follow a normal distribution while
bendiness/stoppiness/trip length followed a power law distribution. This makes
sense intuitively.&lt;/p&gt;
&lt;p&gt;Here are a few histograms of the filtered data:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/abs_velocity_50pct__filtered_hist.png&quot; alt=&quot;Median absolute velocity, filtered&quot;&gt;&lt;/p&gt;
&lt;p&gt;Median absolute velocity (filtered)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/idleness_value__filtered_hist.png&quot; alt=&quot;Idleness&quot;&gt;&lt;/p&gt;
&lt;p&gt;Idleness (filtered)&lt;/p&gt;
&lt;h2 id=&quot;step-3.-exploring-the-data&quot; tabindex=&quot;-1&quot;&gt;Step 3. Exploring the data&lt;/h2&gt;
&lt;p&gt;To better understand the relationships between the features,
I plotted a correlation matrix.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/correlation_matrix_2.png&quot; alt=&quot;Correlation matrix&quot;&gt;&lt;/p&gt;
&lt;p&gt;As expected, the different summary statistics of the same underlying data
were strongly correlated with one another
(median absolute velocity is very highly correlated with 75th percentile velocity,
for instance). But there were also some nontrivial correlations.
For example, trips that were more &amp;quot;bendy&amp;quot; (measured by the sum of turning degrees
normalised by total trip distance) also tended to be more &amp;quot;stoppy&amp;quot;
(measured by the number of times a vehicle stops for more than 5 seconds
normalised by total trip distance). This makes a lot of sense: This correlation
picks up two different trip types:
&amp;quot;highway&amp;quot; trips where cars don&#39;t stop or bend much at all,
versus &amp;quot;urban&amp;quot; trips where cars stop and turn a lot.&lt;/p&gt;
&lt;h2 id=&quot;step-4.-reducing-and-normalising-the-data&quot; tabindex=&quot;-1&quot;&gt;Step 4. Reducing and normalising the data&lt;/h2&gt;
&lt;p&gt;We have 85 different metrics, too many to run clustering on and get results on.
This is because clustering algorithms don&#39;t work well with high-dimensional points
due to something called the &lt;a href=&quot;https://stats.stackexchange.com/questions/232500/how-do-i-know-my-k-means-clustering-algorithm-is-suffering-from-the-curse-of-dim&quot;&gt;curse of dimensionality&lt;/a&gt;
(but see &lt;a href=&quot;https://stats.stackexchange.com/questions/219373/does-curse-of-dimensionality-really-exist-in-real-data&quot;&gt;this CV post&lt;/a&gt;
for an interesting counterpoint to this).&lt;/p&gt;
&lt;p&gt;Essentially, &lt;a href=&quot;https://homes.cs.washington.edu/~pedrod/papers/cacm12.pdf&quot;&gt;&amp;quot;in high dimensions all examples look alike&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Suppose, for instance, that examples are laid out on a regular grid, and
consider a test example &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. If the grid is d-dimensional, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;’s &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;2d&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
nearest examples are all at the same distance from it. So as the dimensionality
increases, more and more examples become nearest neighbors of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;x_t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, until the
choice of nearest neighbor (and therefore of class) is effectively random&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We can fix this by reducing the number of features we consider.
I used two different ways: first, by reducing the dimensionality of the data
using principal component analysis (PCA), and secondly, by using my domain
knowledge of the problem to do manual feature selection.&lt;/p&gt;
&lt;h3 id=&quot;principal-component-analysis-(pca)&quot; tabindex=&quot;-1&quot;&gt;Principal component analysis (PCA)&lt;/h3&gt;
&lt;p&gt;My initial approach reduced the dimensionality of the data using PCA.
Recall that we have a ~2 million * 85 data set where many features are very
highly correlated with one another. It&#39;s likely that we would be able to explain
a large proportion of the variance without using all of the features.&lt;/p&gt;
&lt;p&gt;PCA is sensitive to scale so I first had to normalise the data.
After removing absurd data,
I used scikit-learn&#39;s &lt;code&gt;MinMaxScaler&lt;/code&gt; to scale all the metrics to lie between 0 and 1.
Then I ran PCA to generate a &amp;quot;scree plot&amp;quot; (shown below), which shows the proportion of
variance explained by each principal component. I found that just three
components were sufficient to explain more than 50% of the variance, and
37 components were sufficient to explain more than 99% of the variance.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/scree_plot_normalised.png&quot; alt=&quot;Scree plot of PCA&quot;&gt;
/&lt;/p&gt;
&lt;h3 id=&quot;manual-feature-selection&quot; tabindex=&quot;-1&quot;&gt;Manual feature selection&lt;/h3&gt;
&lt;p&gt;While the factor analysis was successful, I worried that the components
derived by PCA (and the resulting clusters) would be uninterpretable.
I therefore also did manual feature selection, selecting the following six
values:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Median absolute velocity&lt;/li&gt;
&lt;li&gt;Number of stops normalised by trip duration&lt;/li&gt;
&lt;li&gt;Percentage of GPS points that were snapped to a road link&lt;/li&gt;
&lt;li&gt;Max radial acceleration&lt;/li&gt;
&lt;li&gt;Max positive tangential acceleration&lt;/li&gt;
&lt;li&gt;Idleness&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I chose these features because I thought they would be the most informative.
While I could have chosen more features that were also likely to be informative
(e.g. bendiness and maximum negative tangential acceleration), the more features
one chosses, the more likely one will run into the curse of dimensionality,
and the poorer the clusters will be.&lt;/p&gt;
&lt;p&gt;I did not remove outliers when doing manual feature selection, instead
choosing to take the &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;log(x+1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; transform:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;normalised_df &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filtered_df&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;log1p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I plotted each metric&#39;s distribution after taking the log x+1 transform
and the &lt;code&gt;MinMaxScaler&lt;/code&gt; to standardise between 0 and 1.
The data was surprisingly well-behaved.
Both radial and tangential acceleration seemed to conform to a normal distribution,
while number of stops and percentage snapped followed a power law.
Absolute velocity seemed to follow some sort of truncated normal distribution,
which makes sense because speed limits exist (both legal and physical).
Here are the six histograms:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/abs_velocity_median_hist.png&quot; alt=&quot;Median absolute velocity&quot;&gt;&lt;/p&gt;
&lt;p&gt;Median absolute velocity&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/idleness_value_hist.png&quot; alt=&quot;Idleness&quot;&gt;&lt;/p&gt;
&lt;p&gt;Idleness&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/num_stops_value_hist.png&quot; alt=&quot;Number of stops, normalised&quot;&gt;&lt;/p&gt;
&lt;p&gt;Number of stops, normalised by trip distance&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/rad_accel_max_hist.png&quot; alt=&quot;Max radial acceleration&quot;&gt;&lt;/p&gt;
&lt;p&gt;Maximum radial acceleration&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/tang_accel_pos_max_hist.png&quot; alt=&quot;Max tangential acceleration&quot;&gt;&lt;/p&gt;
&lt;p&gt;Maximum positive tangential acceleration&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/snapped_pct_value_hist.png&quot; alt=&quot;Road link snapped percentage&quot;&gt;&lt;/p&gt;
&lt;p&gt;Percentage of snapped road links&lt;/p&gt;
&lt;h2 id=&quot;step-4.-perform-clustering-on-the-normalised-and-reduced-data&quot; tabindex=&quot;-1&quot;&gt;Step 4. Perform clustering on the normalised and reduced data&lt;/h2&gt;
&lt;p&gt;After several false starts, and in keeping with the KISS principle,
I decided to use the simplest clustering algorithm possible---k-means clustering.
The main problem with K-means clustering is that one must specify
the number of clusters. After discussion with Richard and David, we decided that
the &lt;em&gt;a priori&lt;/em&gt; number of clusters should be six
(walk, car, bus, train, plane, ferry), and so I used that number &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.
As usual, scikit-learn provides a one-liner:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;kmeans &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; KMeans&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n_clusters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; random_state&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fit&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After clustering the dataset, we need to visulise our clusters.
This is not a trivial task as our trips are in 6D space, and I know of no good way
to visualise high dimensional clusters. Instead, I took all possible pairs of
the six metrics and plotted each of them as a 2D scatterplot, which is much
easier to interpret.
There are &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;6&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;30&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;6 * 5 = 30&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;30&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; scatterplots in total
(each metric has a scatterplot with all the other metrics),
but half of them are mirror images, so this leaves 15 total scatterplots.
I used &lt;code&gt;matplotlib&lt;/code&gt; to create a lower triangular matrix of scatterplots,
and the results are as follows:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/all_scatter.png&quot; alt=&quot;Correlation plots between all the different matrices&quot;&gt;&lt;/p&gt;
&lt;p&gt;Although the actual clustering only took one line of code, there was in reality
a significant amount of work that went into it. I ran into several dead ends
that initially seemed promising, and I list them here.&lt;/p&gt;
&lt;h3 id=&quot;things-that-didn&#39;t-work&quot; tabindex=&quot;-1&quot;&gt;Things that didn&#39;t work&lt;/h3&gt;
&lt;h4 id=&quot;hierarchical-clustering-----too-slow&quot; tabindex=&quot;-1&quot;&gt;Hierarchical clustering --- too slow&lt;/h4&gt;
&lt;p&gt;I first tried to use hierarchical clustering so that we didn&#39;t have to specify the
number of clusters but this didn&#39;t work because hierarchical clustering runs in
O(N^3) time, which is too slow for the number of data points we have.
In fact, SciPy ran into a memory error when trying to do heirarchical clustering
on just 1/10th of our dataset.&lt;/p&gt;
&lt;h4 id=&quot;pca-and-then-k-means-clustering-----too-uninterpretable&quot; tabindex=&quot;-1&quot;&gt;PCA and then K-means clustering --- too uninterpretable&lt;/h4&gt;
&lt;p&gt;As mentioned, I used PCA to reduce the dimension of the 85 or so calculated metrics
and then performed K-means clustering on those reduced dimensions.
While this seemed to work OK, it wasn&#39;t really that interpretable.
I think this approach is probably the right way to go in the future.
Right now, though, I would need to have a better understanding of
how different types of trips look like so that I can manually inspect the clusters.&lt;/p&gt;
&lt;h2 id=&quot;step-5.-perform-data-analysis-on-those-clusters&quot; tabindex=&quot;-1&quot;&gt;Step 5. Perform data analysis on those clusters&lt;/h2&gt;
&lt;p&gt;We&#39;ve visualised the clusters. Now let&#39;s take a closer look at them and see what
we can learn.&lt;/p&gt;
&lt;p&gt;The first thing we notice is that there are outlier trips with high absolute
velocity. This is by design as I wanted to cluster all of these outlier trips
together with plane trips which also have a high absolute velocity.
We also see in the second plot from the top left that there are a few outliers
with high absolute velocity and almost 0 snapped percentage: these are likely
either plane trips or trips with poor GPS data.&lt;/p&gt;
&lt;p&gt;The second thing we notice is that the clusters don&#39;t seem all that great.
While we can definitely see distinct clusters, the clusters seem to have
significant overlaps. This could be because there are too many points
to visualise, because 6D space doesn&#39;t map cleanly onto 2D space, or because
the clusters themselves just aren&#39;t that great (more on this later).&lt;/p&gt;
&lt;p&gt;The third thing to notice is that there seems to be a negative correlation
between number of stops and maximum acceleration, as well as a negative correlation
between number of stops and median velocity.
You&#39;ll see this most clearly
when looking at the second plot in the third row, num_stops_value (Y)
against rad_accel_max(X).
This is as we expect.
The negative correlation between number of stops and
maximum could be because cars making trips that stop more
tend to be urban trips (slower)
while cars making trips that stop less tend to be highway trips (faster).
Or it could also be reflecting a difference in trip modality: buses tend to stop
a lot and tend also to be slower/accelerate slower.&lt;/p&gt;
&lt;p&gt;In order to know more about the clusters,
I plotted the number of trips belonging to each cluster in the figure below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/label_percentages.png&quot; alt=&quot;Number of trips belonging to each cluster&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can see that the clusters are unbalanced, which is a good thing,
because the vast majority of trips in our dataset are car trips.
However, they are not unbalanced &lt;em&gt;enough&lt;/em&gt; ---they don&#39;t match
our priors on how likely each type of cluster is likely to be.
Of course, it would be quite unrealistic to expect the clusters k-means
identified to coincide entirely with the clusters we care about.&lt;/p&gt;
&lt;h3 id=&quot;why-didn&#39;t-k-means-give-good-clusters%3F&quot; tabindex=&quot;-1&quot;&gt;Why didn&#39;t K-means give good clusters?&lt;/h3&gt;
&lt;p&gt;We&#39;ve used the simplest possible clustering algorithm (a veritable workhorse),
K-means clustering. However, there are &lt;a href=&quot;https://stats.stackexchange.com/questions/133656/how-to-understand-the-drawbacks-of-k-means&quot;&gt;many shortcomings with K-means clustering&lt;/a&gt;,
which could be the reason why the clusters are not as good as we hoped.&lt;/p&gt;
&lt;h4 id=&quot;k-means-clustering-may-not-do-well-with-very-uneven-clusters&quot; tabindex=&quot;-1&quot;&gt;K-means clustering may not do well with very uneven clusters&lt;/h4&gt;
&lt;p&gt;For instance, k-means may sometimes fail with uneven clusters.
The following image shows an example where k-means fails to cluster correctly:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inzura_exploration_2020/uneven_clusters.png&quot; alt=&quot;K-means fails to cluster correctly with uneven clusters&quot;&gt;&lt;/p&gt;
&lt;p&gt;The reason is because the top-right cluster is very big and the top-left cluster
is very small. So the k-means algorithm would rather forsake the loss of the
small number of points at the top-left and use the &amp;quot;freed-up&amp;quot; cluster to decrease
the loss in the big cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I suspect that this is happening in our case.&lt;/strong&gt; We have a tiny number
of outliers (e.g. plane trips with high average velocity, low percentage snapped,
etc.), and this should be in a cluster of its own, but K-means will not do that
if the number of outliers is too small.&lt;/p&gt;
&lt;h4 id=&quot;k-means-clustering-cannot-deal-with-intracluster-covariance&quot; tabindex=&quot;-1&quot;&gt;K-means clustering cannot deal with intracluster covariance&lt;/h4&gt;
&lt;p&gt;Two other shortcomings with K-means clustering are
laid out very nicely in the &lt;a href=&quot;https://towardsdatascience.com/gaussian-mixture-models-d13a5e915c8e&quot;&gt;following post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first shortcoming is that K-means clustering can&#39;t account for covariance.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One way to think about the k-means model is that it places a circle (or, in
higher dimensions, a hyper-sphere) at the center of each cluster, with a
radius defined by the most distant point in the cluster.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;K-means doesn&#39;t work well if the clusters have some positive or negative covariance
(such that the shape of each cluster is non-circular).&lt;/p&gt;
&lt;h4 id=&quot;k-means-tries-to-fit-all-points-to-a-cluster-even-if-they-may-be-outliers&quot; tabindex=&quot;-1&quot;&gt;K-means tries to fit all points to a cluster even if they may be outliers&lt;/h4&gt;
&lt;p&gt;The second and more important difference is as follows:&lt;/p&gt;
&lt;p&gt;Ideally, a clustering algorithm should be able to label points as outliers
and not force-fit them into an existing cluster.
While Gaussian mixtures can label points as not belonging to any cluster at all,
K-means cannot do this, which means outliers will skew our cluster centers and
thus result in incorrect results.&lt;/p&gt;
&lt;p&gt;It would be helpful to have some sort of &amp;quot;confidence&amp;quot; in whether or not a particular trip belongs to any cluster at all, and if the probability is too low, label
that point an outlier. Gaussian models do this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The second difference between k-means and Gaussian mixture models is that the
former performs hard classification whereas the latter performs soft
classification. In other words, k-means tells us what data point belong to
which cluster but won’t provide us with the probabilities that a given data
point belongs to each of the possible clusters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;ideas-for-future-work&quot; tabindex=&quot;-1&quot;&gt;Ideas for future work&lt;/h2&gt;
&lt;h3 id=&quot;using-the-fact-that-we-have-a-corpus-of-guaranteed-car-trips-for-anomaly-detection&quot; tabindex=&quot;-1&quot;&gt;Using the fact that we have a corpus of guaranteed car trips for anomaly detection&lt;/h3&gt;
&lt;p&gt;We know that the vast majority of recorded trips (&amp;gt; 99%) are car trips.
And we also have what is in fact a &amp;quot;ground truth&amp;quot; with the beacon started trips
from company 5 and 11 (these are trips that are guaranteed to be car trips).&lt;/p&gt;
&lt;p&gt;We should make use of this prior knowledge somehow!
Our current unsupervised learning model doesn&#39;t make use of any of this information,
which is a real waste.&lt;/p&gt;
&lt;p&gt;We can do what is in fact a semi-supervised learning model
(anomaly detection). In essence, this will flag any trips that are too different
from the beacon started trips, be it walk/ferry/train/plane. These trips
can then be flagged out and manually inspected, or some sort of model can be trained
on them.&lt;/p&gt;
&lt;p&gt;I believe that we can use Gaussian mixture models to implement this:
see &lt;a href=&quot;https://towardsdatascience.com/understanding-anomaly-detection-in-python-using-gaussian-mixture-model-e26e5d06094b&quot;&gt;this article&lt;/a&gt;
for a nonrigorous overview. A big advantage of using Gaussian mixture models is
that we can explicitly set &lt;em&gt;a priori&lt;/em&gt; prior probabilities of how likely
any random trip will belong to a particular cluster.&lt;/p&gt;
&lt;h3 id=&quot;running-pca-within-clusters-to-compare-the-difference-between-intracluster-and-intercluster-variance&quot; tabindex=&quot;-1&quot;&gt;Running PCA within clusters to compare the difference between intracluster and intercluster variance&lt;/h3&gt;
&lt;p&gt;Finally, here&#39;s an idea I got from a friend:&lt;/p&gt;
&lt;p&gt;Do the clustering, subsample to a cluster and redo PCA on that cluster.
That&#39;ll show how variance is differently explained between clusters and within a cluster.&lt;/p&gt;
&lt;p&gt;For instance, if you had two clusters, and the PCA found that the loading on
absolute velocity was high,
and then you dialed into one cluster and ran PCA there, and the PCA there found
that the loading on number of stops was high,
then this would suggest that the variance &lt;em&gt;between&lt;/em&gt; clusters was more due to
abs velocity (e.g. plane vs non-plane)
and the variance &lt;em&gt;within&lt;/em&gt; a cluster was more due to number of stops
e.g. buses stop a lot and cars tend not to -- but abs velocity doesnt vary as much
between the two modes of transport.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Over the past month we have developed Inzura&#39;s data science capabilities by
creating a data processing library and formalising a data science workflow.
I used the library and workflow to cluster Inzura&#39;s corpus of over 2 million
anonymised trips.&lt;/p&gt;
&lt;p&gt;Our contribution is not just the results of the data analysis, but also the &lt;em&gt;process&lt;/em&gt;
that I have outlined here. With the library and the workflow established,
future data science tasks will be more streamlined.
We will be able to process any data, get more insights from it and
evaluate the results very quickly in the future.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;One possible method if the number of clusters was unknown &lt;em&gt;a priori&lt;/em&gt;
would be to plot the Bayesian and Aikeke Information Criteria (BIC, AIC),
and just eyeball when the BIC plateaus. &lt;a href=&quot;https://lieuzhenghong.com/2020/09/11/inzura-trip-clustering-project/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Board Game Engine</title>
    <link href="https://lieuzhenghong.com/projects/board-game-engine/"/>
    <updated>2020-09-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/board-game-engine/</id>
    <content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I&#39;ve put this project on hold for now.
GitHub repo &lt;a href=&quot;https://github.com/lieuzhenghong/board-game-framework&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;system-architecture&quot; tabindex=&quot;-1&quot;&gt;System architecture&lt;/h2&gt;
&lt;h3 id=&quot;clientmain.ts%3A&quot; tabindex=&quot;-1&quot;&gt;ClientMain.ts:&lt;/h3&gt;
&lt;p&gt;Client Main initialises&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ClientGameCore.ts
&lt;ul&gt;
&lt;li&gt;GameState&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;UIHandler.ts&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ClientMain.js has an &lt;code&gt;init&lt;/code&gt; function that fetches the two JSON files
(game_state.json and image_map.json)
and initialises ClientGameCore and UIHandler (handles clicks).&lt;/p&gt;
&lt;p&gt;The ClientGameCore inherits GameCore and in turn initialises GameState.&lt;/p&gt;
&lt;h3 id=&quot;gamecore.ts&quot; tabindex=&quot;-1&quot;&gt;GameCore.ts&lt;/h3&gt;
&lt;pre&gt;
  // Idea: store a finite state machine here so that we can be sensitive
  // to context.

  // There are a couple of actions I want to support right now
  // as an MVP:

  // == OPTION TYPE 1 ==
  // Right-click on object to open context menu, then
  // left-click on an option.

  // Choice of options:
  // --&gt; change state of Entity (maybe this is a submenu)
  // --&gt; enter &quot;change of Zone&quot; mode where the next left click on a new Zone
  // changes the entity to that zone, if permitted
  // --&gt; enter &quot;change position&quot; mode where the next left click at any position
  // moves the entity to that position

  // We should also implement the following option type:
  //
  // == OPTION TYPE 2 ==

  // Left-click an object to enter &quot;drag&quot; mode, then
  // move the mouse anywhere to move the entity&#39;s position.
  // Left-click again to drop the entity.
  // Note that this doesn&#39;t change the entity&#39;s zone.

  //             Change State Mode
  //                    ^
  //                    |
  //                    |
  // Base Mode --&gt; Entity UI Mode --&gt;  Change Position Mode
  //   |  ^             |
  //   |  |             |
  //   v  |             v
  // Drag mode    Change Zone mode

  // We will also have a ContextMenu that is generated
  // and probably also some flags like CurrentlyDraggingEntity
  // and EntityCurrentlyDragged

  //
  //                                ________________                _________
  //                                |               |               |        |
  // UI [posx, posy, LMB, RMB] ===&gt; |    GameCore   | Action[] ===&gt; | Server |
  //                                |_______________|          &lt;=== |________|
  //                                        |
  //                                        | Action[]
  //                                        v
  //                                    GameState
  //
  /*
  // == Time-based loop (every 15ms?): ==
  // Client Core sends actions to Server Core from the action queue
  // Server Core accumulates and validates actions from all Client Cores
  // Server Core sends actions to Client Cores
  // Client Core applies actions to GameState
  // Client Core renders GameState

  // == Event-based loop: ==
  // on RightClick on Entity, Client Core generates Context UI
  // ClientCore responds to clicks on Context UI and generates ServerActions

  // on MouseMove or any other Click, Client UI sends mouse positions/clicks to Client Core
  // Client Core converts mouse states to ServerActions 
  // Both types of actions are pushed into an action queue
&lt;/pre&gt;
</content>
  </entry>
  <entry>
    <title>Building a Python parallel processing pipeline package (R-3PO)</title>
    <link href="https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/"/>
    <updated>2020-08-29T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#1-minute-guide&quot;&gt;1 minute guide&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#quickstart-guide&quot;&gt;Quickstart guide&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#cloning-the-repo&quot;&gt;Cloning the repo&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#setting-the-scene&quot;&gt;Setting the scene&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#running-the-code&quot;&gt;Running the code&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#how-it-works-in-more-detail&quot;&gt;How it works in more detail&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#overall-abstraction&quot;&gt;Overall abstraction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#limitations-and-requirements&quot;&gt;Limitations and requirements&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#the-function-contract&quot;&gt;The function contract&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#the-config.yaml-file&quot;&gt;The config.yaml file&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#what-jobbuilder.py-does&quot;&gt;What jobbuilder.py does&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#why-does-this-even-exist%3F&quot;&gt;Why does this even exist?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/29/a-simple-parallel-processing-library/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Richard Jelbert (CEO of Inzura) and I whipped up
a Python parallel processing pipeline package
(just rolls off the tongue, doesn&#39;t it) over a couple of days.
We used it to process a large number (over 3 million) of JSON files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Richard&#39;s Parallel Processing Protocol&lt;/strong&gt;, or R-3PO for short (like C-3PO)
is an embarassingly
trivial package built on top of &lt;a href=&quot;https://github.com/ray-project/ray&quot;&gt;Ray&lt;/a&gt;
to make embarassingly parallel problems embarassingly easy.&lt;/p&gt;
&lt;p&gt;Use case: Suppose you have lots of data files that
need to be processed in the exact same way with the same function.
And suppose you want to save the results of that processing into a CSV file.
This is an &lt;em&gt;embarassingly parallel&lt;/em&gt; problem: it should be easy.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Embarassingly&lt;/em&gt; easy, even: R3PO lets you do it with a &lt;code&gt;config.yaml&lt;/code&gt;
file and two lines of code. It automatically
handles the distribution of tasks to processes,
saves your progress so you can stop and restart the job anytime,
and logs all errors automatically.&lt;/p&gt;
&lt;p&gt;This package is probably useless to you unless your
workflow and use case are very similar to mine.
But if it is, I believe it could save you an hour or two
from needing to write boilerplate code.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;1-minute-guide&quot; tabindex=&quot;-1&quot;&gt;1 minute guide&lt;/h2&gt;
&lt;p&gt;Have the following two files in your directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;config.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;job_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; count_produce
&lt;span class=&quot;token key atrule&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;source_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/produce_log
&lt;span class=&quot;token key atrule&quot;&gt;source_file_part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .json
&lt;span class=&quot;token key atrule&quot;&gt;working_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/working_dir
&lt;span class=&quot;token key atrule&quot;&gt;output_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/output_dir&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;main.py&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# main.py&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; r3po &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; jobbuilder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jobrunner
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; count_fruits &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; count_fruits

&lt;span class=&quot;token comment&quot;&gt;# Build jobs&lt;/span&gt;
build_jobs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./config.yaml&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Now run them&lt;/span&gt;
run_jobs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./config.yaml&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count_fruits&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running &lt;code&gt;python3 main.py&lt;/code&gt; will run the &lt;code&gt;count_fruits&lt;/code&gt; function on all &lt;code&gt;.json&lt;/code&gt;
files in &lt;code&gt;/home/lieu/produce_log/&lt;/code&gt; and log the results in numbered csv files
inside &lt;code&gt;/home/lieu/output_dir/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sounds like something you&#39;d find useful? Read on...&lt;/p&gt;
&lt;h2 id=&quot;quickstart-guide&quot; tabindex=&quot;-1&quot;&gt;Quickstart guide&lt;/h2&gt;
&lt;p&gt;We&#39;ll work though a very simple example available on the &lt;a href=&quot;https://github.com/lieuzhenghong/r3po&quot;&gt;Github repo&lt;/a&gt;.
First, let&#39;s clone the repo and go to the &lt;code&gt;sample&lt;/code&gt; directory:&lt;/p&gt;
&lt;h3 id=&quot;cloning-the-repo&quot; tabindex=&quot;-1&quot;&gt;Cloning the repo&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/lieuzhenghong/r3po
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; r3po/sample&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The directory will look like this:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;r3po&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;sample&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
├── produce_log&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
    ├── file_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_4&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_5&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
├── config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;yaml
├── count_fruits&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;py
├── main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;py&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;setting-the-scene&quot; tabindex=&quot;-1&quot;&gt;Setting the scene&lt;/h3&gt;
&lt;p&gt;Imagine you&#39;re the king of Cornucopia and you own
one bajillion acres of land. You&#39;ve allocated an acre of land to each one of your
loyal subjects for them to farm as they see fit.&lt;/p&gt;
&lt;p&gt;One day, you decide that you&#39;d like to know how much food is produced in Cornucopia.
So you ask your subjects to report their yields.
Your subjects are well-acquainted with both farming and the JSON spec,
so let&#39;s take a look at &lt;code&gt;file_0.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;produce&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;fruits&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;apples&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;bananas&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;cantaloupes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;vegetables&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;carrots&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;cucumbers&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;cabbages&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;meat&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;beef&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;&quot;pork&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now as the king you&#39;re not that interested in the various types of fruits
per se---perhaps you only want the total sum of each type of produce.
Let&#39;s say you want something like the following:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;fruits&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;vegetables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;58&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token string&quot;&gt;&quot;meat&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you write a simple function that does exactly that.
The details are not important, but
&lt;strong&gt;the key is that any such function must take in a filepath string and return a dictionary&lt;/strong&gt; for R3PO to work with it.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# count_fruits.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; json

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count_fruits&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;produce_log_filepath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;produce_log_filepath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;r&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        produce_counts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;load&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;f&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        all_produce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;produce&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; produce_type &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; all_produce&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            produce_counts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;produce_type&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; produce &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; all_produce&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;produce_type&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                produce_counts&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;produce_type&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    all_produce&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;produce_type&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;produce&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; produce_counts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you&#39;d want to run this function for every file.
However, you have a bajillion acres of
land and thus a bajillion JSON files
(instead of the six files in the sample folder)
and so we&#39;d like to speed it up by running the code in parallel.
Let&#39;s see how to do it with the R-3PO pipeline.&lt;/p&gt;
&lt;p&gt;First, let&#39;s open &lt;code&gt;config.yaml&lt;/code&gt; and take a look at the file.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;job_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; count_produce
&lt;span class=&quot;token key atrule&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;source_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/produce_log
&lt;span class=&quot;token key atrule&quot;&gt;source_file_part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; .json
&lt;span class=&quot;token key atrule&quot;&gt;working_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/working_dir
&lt;span class=&quot;token key atrule&quot;&gt;output_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/output_dir&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Most of these are pretty self-explanatory (more details later),
but basically this means that&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;R3PO will spin up two parallel processes,&lt;/li&gt;
&lt;li&gt;look for any file ending with &lt;code&gt;.json&lt;/code&gt; in &lt;code&gt;/home/lieu/produce_log/&lt;/code&gt;,
and&lt;/li&gt;
&lt;li&gt;write the results in &lt;code&gt;/home/lieu/output_dir&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now let&#39;s open the &lt;code&gt;main.py&lt;/code&gt; file and see what&#39;s in it
(a whopping two lines of code):&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# main.py&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; r3po &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; jobbuilder&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jobrunner
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; count_fruits &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; count_fruits

&lt;span class=&quot;token comment&quot;&gt;# Build jobs&lt;/span&gt;
build_jobs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./config.yaml&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Now run them&lt;/span&gt;
run_jobs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./config.yaml&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count_fruits&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not much to say about this. Let&#39;s run it and see what happens:&lt;/p&gt;
&lt;h3 id=&quot;running-the-code&quot; tabindex=&quot;-1&quot;&gt;Running the code&lt;/h3&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# bash pip3 install r3po&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# python3 main.py&lt;/span&gt;

Building job called: count_produce
Reading job &lt;span class=&quot;token builtin class-name&quot;&gt;source&lt;/span&gt; directory and generating master job CSV file&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Scanning &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; files ending with .json
Pending files generated.
Removing old &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; jobfiles&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Writing new &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; jobfiles&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Number of files: &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;
Number of pending files: &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-30 &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;:38:05,916 INFO resource_spec.py:223 -- Starting Ray with &lt;span class=&quot;token number&quot;&gt;5.47&lt;/span&gt; GiB memory available &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; workers and up to &lt;span class=&quot;token number&quot;&gt;2.73&lt;/span&gt; GiB &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; objects. You can adjust these settings with ray.init&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;memory&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;bytes&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;, &lt;span class=&quot;token assign-left variable&quot;&gt;object_store_memory&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;bytes&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-30 &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;:38:06,302 INFO services.py:1191 -- View the Ray dashboard at localhost:8265
Spinning up Ray processes&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Process &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; spawned&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
Process &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; spawned&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
None
None
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336291&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/0.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336291&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/0.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336291&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/0.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;.
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336283&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/1.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336283&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/1.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pid&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;336283&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Processed trip /home/lieu/dev/r3po/sample/output_dir/1.results.csv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;node&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, everything looks good! Let&#39;s take a look at
what has happened. There were a lot of print statements
which are self-explanatory.&lt;/p&gt;
&lt;p&gt;We can see that Ray has spun up
two parallel processes
(exactly what we specified in the config.yaml file).
Additionally,
we can see that R3PO has created an output_dir with
two &lt;code&gt;results.csv&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;We also have a &lt;code&gt;working_dir/&lt;/code&gt; with &lt;code&gt;done.job&lt;/code&gt; and
&lt;code&gt;nodejobfile.txt&lt;/code&gt; files, but we won&#39;t worry about that for now.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;r3po&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;sample&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
├── output_dir&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
    ├── &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;csv
    ├── &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;csv
├── produce_log&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
    ├── file_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_4&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
    ├── file_5&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
├── working_dir&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
    └── tracking&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_0&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_4&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
        └── &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;file_5&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json
            └── done&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;job
    ├── &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodejobfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;txt
    ├── &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nodejobfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;txt
├── config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;yaml
├── count_fruits&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;py
├── main&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Opening up the two &lt;code&gt;results.csv&lt;/code&gt; files,
we can see that the function has
indeed been calculated for all of the input JSON files.
Because we spun up two processes, there are two
&lt;code&gt;results.csv&lt;/code&gt; files:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 0.results.csv&lt;/span&gt;
fruits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;vegetables&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;meat
&lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;58&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;3939&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;58&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;6456&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3743&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# 1.results.csv&lt;/span&gt;
fruits&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;vegetables&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;meat
&lt;span class=&quot;token number&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1539&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;79&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;58&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;5666&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we&#39;re done! These CSVs can then be converted
and concatenated with pandas&#39;s &lt;code&gt;pd.concat&lt;/code&gt; function
to get pandas &lt;code&gt;DataFrames&lt;/code&gt;,
which is the format in which I do the majority of my data analysis.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works-in-more-detail&quot; tabindex=&quot;-1&quot;&gt;How it works in more detail&lt;/h2&gt;
&lt;h3 id=&quot;overall-abstraction&quot; tabindex=&quot;-1&quot;&gt;Overall abstraction&lt;/h3&gt;
&lt;p&gt;This pipeline runs a function &lt;code&gt;f&lt;/code&gt; on a large number of
input files in parallel and logs the results into a CSV.&lt;/p&gt;
&lt;p&gt;It is made up of two files.
The first file &lt;code&gt;jobbuilder.py&lt;/code&gt; reads the &lt;code&gt;source_path&lt;/code&gt; from &lt;code&gt;config.yaml&lt;/code&gt;.
It looks for all files inside &lt;code&gt;source_path&lt;/code&gt; that match a user-specified criteria.
It writes these file paths inside &lt;code&gt;nodejobfile&lt;/code&gt; text files that tell each process
which files to work on.&lt;/p&gt;
&lt;p&gt;The second file &lt;code&gt;jobrunner.py&lt;/code&gt; spins up the processes.
Each process looks at its &lt;code&gt;nodejobfile&lt;/code&gt; text file, and works through the list.&lt;/p&gt;
&lt;p&gt;For each &lt;code&gt;$FILEPATH&lt;/code&gt; listed in &lt;code&gt;nodejobfile&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the process opens the file,&lt;/li&gt;
&lt;li&gt;runs some function &lt;code&gt;f&lt;/code&gt; on that file,&lt;/li&gt;
&lt;li&gt;and (tries to) append the output to a .csv file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the function successfully runs, an empty file called &lt;code&gt;done.job&lt;/code&gt;
is created in &lt;code&gt;&amp;lt;$WORKING_DIR&amp;gt;/tracking/&amp;lt;$FILEPATH&amp;gt;/&lt;/code&gt;as a record of completion.
If the function throws an exception, then a file called &lt;code&gt;error.job&lt;/code&gt;
is created instead.&lt;/p&gt;
&lt;p&gt;Keeping a record of file completion means that
the processes can be terminated and restarted at any time
without going through the same files again.&lt;/p&gt;
&lt;h3 id=&quot;limitations-and-requirements&quot; tabindex=&quot;-1&quot;&gt;Limitations and requirements&lt;/h3&gt;
&lt;p&gt;The pipeline requires the following to work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;config.yaml&lt;/code&gt; file that follows a particular specification&lt;/li&gt;
&lt;li&gt;A function that follows a specific contract (see next section)&lt;/li&gt;
&lt;li&gt;All your input files must end with the same suffix.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;the-function-contract&quot; tabindex=&quot;-1&quot;&gt;The function contract&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;The function you call must take as input an absolute filepath to the file.&lt;/li&gt;
&lt;li&gt;It must return a Dictionary that will be passed to
&lt;a href=&quot;https://docs.python.org/3/library/csv.html#csv.writer&quot;&gt;&lt;code&gt;csv.DictWriter&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Furthermore, every Dictionary object returned &lt;strong&gt;must have the same keys&lt;/strong&gt;.
If it is not able to return such a Dictionary, it must raise an &lt;code&gt;Exception&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;the-config.yaml-file&quot; tabindex=&quot;-1&quot;&gt;The &lt;code&gt;config.yaml&lt;/code&gt; file&lt;/h4&gt;
&lt;p&gt;This is what a config.yaml file should looks like. All fields are required.&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;job_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;trip&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;visualisations
&lt;span class=&quot;token key atrule&quot;&gt;output_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/RJ/trip_processing_research/.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;trip&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;visualisations
&lt;span class=&quot;token key atrule&quot;&gt;processes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;source_file_part&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; formatted.lz4
&lt;span class=&quot;token key atrule&quot;&gt;source_path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /media/lieu/bigdata/anonymous/rjrun
&lt;span class=&quot;token key atrule&quot;&gt;working_dir&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /home/lieu/RJ/trip_processing_research/.generate&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;trip&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;visualisations&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;count_all_files&lt;/code&gt; and &lt;code&gt;count_job_files&lt;/code&gt; are added by the program
and list the number of files in the job and the number of files remaining
in the job respectively.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;job_name&lt;/code&gt; is the name of the processing job. It is used in
&lt;code&gt;print&lt;/code&gt; statements only.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;processes&lt;/code&gt; is the number of parallel processes to spin up.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;source_path&lt;/code&gt; is a filepath string pointing to the folder where
the source files are.
&lt;code&gt;source_file_part&lt;/code&gt; is used for filepath matching:
R3PO will traverse all subfolders inside &lt;code&gt;source_path&lt;/code&gt;
and find all the &lt;code&gt;.json&lt;/code&gt; files. In this case,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;working_dir&lt;/code&gt; is a filepath string that points to a folder
to store intermediate files.
where the nodejobtxts will be, as well as the &lt;code&gt;done.job&lt;/code&gt;
and &lt;code&gt;error.job&lt;/code&gt; files.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;output_path&lt;/code&gt; is a filepath string that points to a folder
where you want the results of the computations to
be written to CSV files. If the folder does not exist,
one will be automatically created.&lt;/p&gt;
&lt;h4 id=&quot;what-jobbuilder.py-does&quot; tabindex=&quot;-1&quot;&gt;What jobbuilder.py does&lt;/h4&gt;
&lt;p&gt;The jobbuilder module is responsible for getting the filepaths of all the
input files and
writing these filepaths to a CSV that jobrunner can read later.
It does not write the filepath if the file has already been processed
or if an error occurred whilst processing that file.&lt;/p&gt;
&lt;p&gt;This is how it does it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read config.yaml file and find &lt;code&gt;source_path&lt;/code&gt;, &lt;code&gt;working_dir&lt;/code&gt;, and
&lt;code&gt;source_file_part&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Create the folder &lt;code&gt;working_dir&lt;/code&gt; if one does not exist&lt;/li&gt;
&lt;li&gt;Look for file paths that match &lt;code&gt;source_path/**/*.source_file_part&lt;/code&gt;,
and do not already have a &lt;code&gt;done.job&lt;/code&gt; or &lt;code&gt;error.job&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Write &lt;code&gt;X.nodejobfile.txt&lt;/code&gt; by dividing the file paths up equally
across all X process nodejobfiles&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;why-does-this-even-exist%3F&quot; tabindex=&quot;-1&quot;&gt;Why does this even exist?&lt;/h2&gt;
&lt;p&gt;Admittedly, the code is pretty trivial, and quite overfitted to my specific
use-case. Why did I even bother packaging it up in the first place?
I offer three reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you think about it, the code is not &lt;em&gt;that&lt;/em&gt; trivial.
It&#39;s easy enough to parallelise code in Python with the &lt;code&gt;multiprocessing&lt;/code&gt;
library. But it can be tricky to write code that allows jobs to terminate
and restart arbitrarily, while not reprocessing already-processed files.&lt;/li&gt;
&lt;li&gt;It follows from point 1 that
this package will save you spending an hour or two reinventing the wheel
if your use-case and dataflow are similar to mine.&lt;/li&gt;
&lt;li&gt;I was lazy and wanted to be able to &lt;code&gt;pip install&lt;/code&gt; rather than &lt;code&gt;git clone&lt;/code&gt;-ing
and moving the files around manually.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for reading!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>GSoC 2020: implementing real-time metrics for MGGG&#39;s Districtr app</title>
    <link href="https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/"/>
    <updated>2020-08-28T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#understanding-the-problem&quot;&gt;Understanding the problem&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#software-infrastructure-in-brief&quot;&gt;Software infrastructure in brief&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#the-solution-in-brief&quot;&gt;The solution in brief&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-1%3A-the-client-sends-the-district-assignment-to-the-server&quot;&gt;Step 1: The client sends the district assignment to the server&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-2%3A-the-server-calculates-metrics-and-responds-to-the-client&quot;&gt;Step 2: The server calculates metrics and responds to the client&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-3%3A-the-client-updates-its-ui-with-the-server&#39;s-response&quot;&gt;Step 3: the client updates its UI with the server&amp;#39;s response&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#the-solution-in-detail&quot;&gt;The solution in detail&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-1%3A-the-client-sends-the-district-assignment-to-the-server-1&quot;&gt;Step 1: The client sends the district assignment to the server&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-2%3A-the-server-calculates-metrics-and-responds-to-the-client-1&quot;&gt;Step 2: The server calculates metrics and responds to the client&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#step-3%3A-the-client-updates-its-ui-with-the-server&#39;s-response-1&quot;&gt;Step 3: the client updates its UI with the server&amp;#39;s response&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#generating-the-distribution-of-cut-edges&quot;&gt;Generating the distribution of cut edges&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#generating-the-histogram&quot;&gt;Generating the histogram&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#drawing-the-red-line-on-the-histogram&quot;&gt;Drawing the red line on the histogram&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#what-i-learned&quot;&gt;What I learned&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#how-to-work-with-a-complex-existing-codebase&quot;&gt;How to work with a complex existing codebase&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#future-work&quot;&gt;Future work&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#improve-performance-of-the-server&quot;&gt;Improve performance of the server&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#i-have-collected-dual-graphs-into-an-open-source-repo.&quot;&gt;I have collected dual graphs into an open-source repo.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#how-to-set-up-the-server-on-pythonanywhere&quot;&gt;How to set up the server on PythonAnywhere&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/#how-the-assignment-object-actually-looks-like&quot;&gt;How the assignment object actually looks like&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;For Google Summer of Code 2020,
I implemented a new feature to MGGG&#39;s flagship webapp &lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/districtr.org&quot;&gt;Districtr&lt;/a&gt;.
Districtr has an existing feature where you can &amp;quot;colour in&amp;quot; districts using a brush tool:
each colour represents a different district.&lt;/p&gt;
&lt;p&gt;My contribution can be seen in the bottom right corner of the below GIF.
As you draw the districts with the brush,
three metrics update in real time:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;the contiguity status (whether districts drawn are one continuous whole or
get broken up in the middle);&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Cut_%28graph_theory%29&quot;&gt;number of cut edges&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;How the number of cut edges compares to a sample of plans generated by the
&lt;a href=&quot;https://arxiv.org/pdf/1911.05725.pdf&quot;&gt;Recom redistricting algorithm&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/mggg/mggg.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Because I know of no way to find contiguity/number of cut edges of a graph partition
in-browser, this thus requires server-side computation.
In this post, I explain how these metrics are calculated,
how I deployed the server that does the calculations,
and how I built the front-end to send requests and display the results.&lt;/p&gt;
&lt;p&gt;The main PR is #212 where I implement cut edges
&lt;a href=&quot;https://github.com/districtr/districtr/pull/212&quot;&gt;here (PR #212)&lt;/a&gt;
but I also implemented contiguity before that
&lt;a href=&quot;https://github.com/districtr/districtr/pull/209&quot;&gt;here (PR #209)&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-problem&quot; tabindex=&quot;-1&quot;&gt;Understanding the problem&lt;/h2&gt;
&lt;p&gt;A state can be thought of as a &lt;a href=&quot;https://en.wikipedia.org/wiki/Dual_graph&quot;&gt;dual graph&lt;/a&gt;,
and a particular district assignment of precincts to districts is
in effect creating a &lt;em&gt;partition&lt;/em&gt; of that dual graph.
Given this partition of the dual graph we can then calculate out whether or not
the subgraphs are contiguous and how many cut edges there are in the partition.&lt;/p&gt;
&lt;p&gt;How should we calculate this? I determined that the best way to do so
was to use &lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/gerrychain.readthedocs.io/&quot;&gt;the GerryChain library&lt;/a&gt; (written in Python).
The biggest reason is &lt;em&gt;dogfooding&lt;/em&gt;: since GerryChain is
being actively developed by the MGGG group, it made sense to use GerryChain
rather than some other library.&lt;/p&gt;
&lt;h2 id=&quot;software-infrastructure-in-brief&quot; tabindex=&quot;-1&quot;&gt;Software infrastructure in brief&lt;/h2&gt;
&lt;p&gt;This is a very simple client-server model.&lt;/p&gt;
&lt;p&gt;The Districtr webapp is built on lit-HTML. The histogram is dynamically drawn with Vega.&lt;/p&gt;
&lt;p&gt;The server is a Flask server that calls GerryChain code.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-in-brief&quot; tabindex=&quot;-1&quot;&gt;The solution in brief&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Upon a brush stroke, the client sends a POST request to the
Flask server (hosted on &lt;a href=&quot;https://pythonanywhere.com/&quot;&gt;PythonAnywhere&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The server calculates the metrics and sends them as a response to the client.&lt;/li&gt;
&lt;li&gt;The client takes the response and rerenders the DOM appropriately.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;step-1%3A-the-client-sends-the-district-assignment-to-the-server&quot; tabindex=&quot;-1&quot;&gt;Step 1: The client sends the district assignment to the server&lt;/h3&gt;
&lt;p&gt;Drawing districts with the brush in the Districtr website updates an
&lt;code&gt;assignment&lt;/code&gt; object. This object looks something like this (but see Appendix):&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19001&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19002&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19003&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19004&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19005&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key is the voting precinct ID and the value is the district it has been assigned to.
For instance, precinct 19001 has been assigned to district 2.&lt;/p&gt;
&lt;p&gt;This &lt;code&gt;assignment&lt;/code&gt; object is sent to the Python server for computation.&lt;/p&gt;
&lt;h3 id=&quot;step-2%3A-the-server-calculates-metrics-and-responds-to-the-client&quot; tabindex=&quot;-1&quot;&gt;Step 2: The server calculates metrics and responds to the client&lt;/h3&gt;
&lt;p&gt;The server receives the &lt;code&gt;assignment&lt;/code&gt; object,
and converts it to a GerryChain &lt;code&gt;Partition&lt;/code&gt; object provided it has that state&#39;s dual graph:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;partition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gerrychain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Partition&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state_graph&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; assignment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the &lt;code&gt;Partition&lt;/code&gt; object we calculate cut edges and contiguity metrics,
then send them to the client.&lt;/p&gt;
&lt;h3 id=&quot;step-3%3A-the-client-updates-its-ui-with-the-server&#39;s-response&quot; tabindex=&quot;-1&quot;&gt;Step 3: the client updates its UI with the server&#39;s response&lt;/h3&gt;
&lt;p&gt;The client updates its UI appropriately with the server&#39;s response. The
histograms are rendered with Vega (more on this later).&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;At a high level, that&#39;s all there is to it! I&#39;ll now explain the solution in detail.&lt;/p&gt;
&lt;h2 id=&quot;the-solution-in-detail&quot; tabindex=&quot;-1&quot;&gt;The solution in detail&lt;/h2&gt;
&lt;h3 id=&quot;step-1%3A-the-client-sends-the-district-assignment-to-the-server-1&quot; tabindex=&quot;-1&quot;&gt;Step 1: The client sends the district assignment to the server&lt;/h3&gt;
&lt;p&gt;The assignment object is not just sent once, but constantly as the user draws
districts on the Districtr app.
In the &lt;code&gt;ToolsEditor()&lt;/code&gt; function in &lt;code&gt;/plugins/tools_plugin_js&lt;/code&gt; there is a &lt;code&gt;brush.on&lt;/code&gt;
event that detects any change in district assignment, and sends the
new assignment to a &lt;code&gt;ContiguityChecker&lt;/code&gt; function. The &lt;code&gt;spatial_abilities()&lt;/code&gt; condition
checks if contiguity checks have been enabled for that particular state.&lt;/p&gt;
&lt;p&gt;(&lt;strong&gt;TODO&lt;/strong&gt;: this function enables/disables contiguity and cut edges all at once.
We should find some way to fix this, or at least rename it.
)&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; c_checker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContiguityChecker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; brush&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

brush&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;colorop&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;isUndoRedo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colorsAffected&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;savePlanToStorage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;spatial_abilities&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;place&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contiguity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;c_checker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colorsAffected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;planNumbers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    planNumbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; colorsAffected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ContiguityChecker&lt;/code&gt; function lives in &lt;code&gt;src/map/contiguity.js&lt;/code&gt;,
where it sends the district assignment to the PythonAnywhere server through
a POST request:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ContiguityChecker&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; saveplan &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;serialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;saveplan&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;GERRYCHAIN_URL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;//mggg.pythonanywhere.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;GERRYCHAIN_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;saveplan&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// code removed for brevity ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-2%3A-the-server-calculates-metrics-and-responds-to-the-client-1&quot; tabindex=&quot;-1&quot;&gt;Step 2: The server calculates metrics and responds to the client&lt;/h3&gt;
&lt;p&gt;The Python server is as simple as can be. It is a Flask server with only one route:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token decorator annotation punctuation&quot;&gt;@app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;route&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; methods&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;POST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Takes a Districtr JSON and returns whether or not it&#39;s contiguous and number of cut edges.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plan_metrics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    plan &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get_json&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# code removed for brevity&lt;/span&gt;
    districtr_assignment &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; plan&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;assignment&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# code removed for brevity&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As we can see, the server just parses the POST request
and then pulls out the Districtr &lt;code&gt;assignment&lt;/code&gt; object.
Now what do we do with it?&lt;/p&gt;
&lt;p&gt;The first step is to convert the Districtr assignment object we&#39;ve received
to a format that GerryChain can work with. There&#39;s already a function that
&lt;a href=&quot;https://gerrychain.readthedocs.io/en/latest/_modules/gerrychain/partition/partition.html&quot;&gt;does something similar&lt;/a&gt;,
but it i) loads from a file instead of an object, and
ii) doesn&#39;t handle incomplete assignments
(i.e. when the user doesn&#39;t fill up the map completely).
I therefore wrote my own code that could handle both of those things.&lt;/p&gt;
&lt;p&gt;(&lt;strong&gt;TODO&lt;/strong&gt;: make a PR to GerryChain to add new classmethod)&lt;/p&gt;
&lt;p&gt;How we handle incomplete assignments is somewhat arbitrary, but I decided to
put all non-assigned nodes into a district of their own (district -1).
After the assignment is complete, we then use the &lt;code&gt;gerrychain.Partition&lt;/code&gt; function
to create a partition and calculate cut edges and contiguity.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;partition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gerrychain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Partition&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state_graph&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; assignment&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Now that we have the partition, calculate all the different metrics&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Calculate cut edges&lt;/span&gt;
cut_edges &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cut_edges&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Split districts&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# TODO timeit this --- how long does it take?&lt;/span&gt;
split_districts &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; part &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; gerrychain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contiguity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;affected_parts&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; part &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        part_contiguous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;is_connected&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;partition&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;subgraphs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;part&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; part_contiguous&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            split_districts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;part&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Contiguity&lt;/span&gt;
contiguity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;split_districts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We send the calculated metrics back to the client:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flask&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jsonify&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;cut_edges&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cut_edges&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;contiguity&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; contiguity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;split&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; split_districts&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-3%3A-the-client-updates-its-ui-with-the-server&#39;s-response-1&quot; tabindex=&quot;-1&quot;&gt;Step 3: the client updates its UI with the server&#39;s response&lt;/h3&gt;
&lt;p&gt;The fetch request the client sends has hopefully returned with no error.
If so, we start updating the UI and do three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;set contiguity status,&lt;/li&gt;
&lt;li&gt;set number of cut edges,&lt;/li&gt;
&lt;li&gt;draw a histogram of cut edges and show where the current plan lies.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;GERRYCHAIN_URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token string-property property&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;saveplan&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; res&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Set contiguity status&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;setContiguityStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Set number of cut edges&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; num_cut_edges &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setNumCutEdges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; state_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// Embed the canvas&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state_name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; saveplan&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;placeId&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; container &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.cut_edges_distribution_vega&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; vega_json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__form_vega_json__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;vegaEmbed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vega_json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

          &lt;span class=&quot;token comment&quot;&gt;// Wait for vegaEmbed to generate the canvas, then draw a line on it&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.marks&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; left_bound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state_info&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lr_bounds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; right_bound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state_info&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lr_bounds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

          &lt;span class=&quot;token function&quot;&gt;__draw_line_on_canvas__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_cut_edges&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; left_bound&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; right_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;setContiguityStatus&lt;/code&gt; and &lt;code&gt;setNumCutEdges&lt;/code&gt; are pretty straightforward
functions where I just change the &lt;code&gt;innerText&lt;/code&gt; of the relevant HTML elements.
If we were doing this in React it would probably be better to store
&lt;code&gt;contiguityStatus&lt;/code&gt; and &lt;code&gt;numCutEdges&lt;/code&gt; as state and have some sort of hook to
update, but this approach works fine:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setContiguityStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;contiguity_object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contiguous &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contiguity_object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;contiguity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;#contiguity-status&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;contiguous
    &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Districts may have contiguity gaps&quot;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Any districts are contiguous&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The most complicated function is rendering the histogram of districting plans
and drawing the red line on the histogram, and I&#39;ll go through that now.&lt;/p&gt;
&lt;h4 id=&quot;generating-the-distribution-of-cut-edges&quot; tabindex=&quot;-1&quot;&gt;Generating the distribution of cut edges&lt;/h4&gt;
&lt;p&gt;First of all, what &lt;em&gt;is&lt;/em&gt; the histogram representing? Where does it come from?
The histogram shows the number of cut edges from 10,000 sample districting plans.
These plans were generated using the &lt;a href=&quot;https://arxiv.org/pdf/1911.05725.pdf&quot;&gt;Recom redistricting algorithm&lt;/a&gt;,
a districting algorithm developed by MGGG.
The maths is complicated, but essentially it&#39;s a Markov Chain technique;
it starts from some random assignment, and to generate a new assignment
it changes the assignment of certain districts in a &amp;quot;smart&amp;quot; way so as to
maintain contiguity, population balance and relative compactness.
Each one of these generated plans has a number of cut edges.
After running the algorithm for 10,000 steps, we&#39;ll have gotten a distribution
of the number of cut edges,
and this is exactly what we are plotting.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/mggg/recom.png&quot; alt=&quot;How districting plans are generated by the Recom algorithm&quot;&gt;
&lt;span style=&quot;font-size:0.8rem;&quot;&gt;
How districting plans are generated by the Recom algorithm. Image from the &lt;a href=&quot;https://arxiv.org/pdf/1911.05725.pdf&quot;&gt;Recom paper&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For each state we have precomputed 10,000 sample districting plans
and stored it in a csv file.
This process takes anywhere from a few hours to a few days, but only has to be done once:
once the distribution of cut edges is known it can simply be used again and again.
The csv files live in
&lt;code&gt;assets/cut_edges_histograms/$STATE_chain_10000/csv&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;generating-the-histogram&quot; tabindex=&quot;-1&quot;&gt;Generating the histogram&lt;/h4&gt;
&lt;p&gt;The next step is drawing the histogram on the UI. I initially used a PNG generated by
&lt;code&gt;matplotlib.hist&lt;/code&gt;, but this turned out to be nonideal because the UI could resize
and PNGs are not responsive. We therefore need to generate histograms dynamically.
and after some searching I decided on Vega-Lite.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://vega.github.io/vega-lite/&quot;&gt;Vega-Lite&lt;/a&gt; is a &amp;quot;high-level grammar of interactive graphics&amp;quot;
that &amp;quot;provides a concise, declarative JSON syntax to create an expressive range
of visualizations for data analysis and presentation&amp;quot;. To create the histogram
I needed to write a JSON object that specified what data to plot and how
I wanted it to be plotted:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Returns the Vega Lite schema needed for rendering the state cut edge histogram dynamically&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__form_vega_json__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;state_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; vega_json &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;$schema&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://vega.github.io/schema/vega-lite/v4.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; state_info&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;state_csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;mark&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;autosize&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;padding&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;maxbins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cut_edges&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;aggregate&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;count&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;axisY&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;axisX&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vega_json&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we use a helper function &lt;a href=&quot;https://github.com/vega/vega-embed&quot;&gt;&lt;code&gt;vegaEmbed&lt;/code&gt;&lt;/a&gt;
to embed the visualisation into the DOM.
VegaEmbed takes a container element and the &lt;code&gt;vega_json&lt;/code&gt; schema
and generates a &lt;code&gt;HTMLCanvasElement&lt;/code&gt; with &lt;code&gt;&amp;lt;canvas class=&#39;marks&#39;&amp;gt;&lt;/code&gt; within the container
element:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;    &lt;span class=&quot;token function&quot;&gt;vegaEmbed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;container&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vega_json&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// here v is the vega view, but we will ignore it&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.marks&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; left_bound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state_info&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lr_bounds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; right_bound &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; state_info&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;state_name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;lr_bounds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;__draw_line_on_canvas__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; num_cut_edges&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; left_bound&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; right_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I take that &lt;code&gt;canvas&lt;/code&gt; element and pass it to my &lt;code&gt;__draw_line_on_canvas__&lt;/code&gt; function,
which draws a line that represents how the current districting plan
compares to the sample of plans.&lt;/p&gt;
&lt;p&gt;You may be wondering:
What is the &lt;code&gt;state_info&lt;/code&gt; object? It is basically a map that tells the code
where to find the data CSV object, and the upper and lower bounds of the number
of cut edges in the 10,000 generated plans.
We need the upper and lower bounds in &lt;code&gt;__draw_line_on_canvas__&lt;/code&gt; to
draw the line, as you&#39;ll see later.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; state_info &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;connecticut&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;state_csv&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../assets/cut_edges_histograms/CT_chain_10000.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;lr_bounds&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;110&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;270&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;iowa&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;state_csv&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../assets/cut_edges_histograms/IA_chain_10000.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;lr_bounds&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;texas&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;state_csv&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../assets/cut_edges_histograms/TX_chain_10000.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;lr_bounds&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2720&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3440&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;drawing-the-red-line-on-the-histogram&quot; tabindex=&quot;-1&quot;&gt;Drawing the red line on the histogram&lt;/h4&gt;
&lt;p&gt;The red line in the image below
shows how the current plan compares to a set of generated plans
in terms of number of cut edges. The main difficulty is that we have a number
of cut edges---but to draw the line, we need to convert that to an x-position
on the histogram.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/mggg/cut_edges_hist.png&quot; alt=&quot;The red line shows how the current plan compares to a set of plans&quot;&gt;&lt;/p&gt;
&lt;p&gt;To do that, we need the upper and lower bounds of the cut edges distribution:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the number of cut edges is below the lower bound, we set line position to 0.&lt;/li&gt;
&lt;li&gt;If it is above the upper bound, we set it to the canvas width.&lt;/li&gt;
&lt;li&gt;And if it lies somewhere in between, then since the x-axis is uniform,
the x-position given a number of cut edges &lt;code&gt;n&lt;/code&gt; is&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;u&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;d&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;xPosition = w * \frac{(n - leftBound)}{(rightBound - leftBound)}.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.363em;vertical-align:-0.936em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.427em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;tB&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;tB&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;tB&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.936em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this example, suppose the canvas is 300px wide, and the lower bound and
upper bound are 32 and 60 cut edges respectively.
Then 39 cut edges would correspond to&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;300&lt;/mn&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mn&gt;39&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;32&lt;/mn&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mn&gt;60&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;32&lt;/mn&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;75&lt;/mn&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;x&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;300px * \frac{39 - 32}{60-32} = 75px .
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8389em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.0908em;vertical-align:-0.7693em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;39&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7693em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8389em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;75&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We then get the canvas&#39;s &lt;code&gt;Canvas2DContext&lt;/code&gt;
and draw a line at the correct x-position, which in this case is 75px.
The code looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__draw_line_on_canvas__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;token parameter&quot;&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  num_cut_edges&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  left_bound&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  right_bound&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; w &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; line_position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// this is going to be a value between 0 and w&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_cut_edges &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; left_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    line_position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_cut_edges &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; right_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    line_position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    line_position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;num_cut_edges &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; left_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;right_bound &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; left_bound&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Line position: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_position&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Line position:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_position&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lineWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;strokeStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line_position&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lineTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line_position&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;closePath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&#39;s it!&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot; tabindex=&quot;-1&quot;&gt;What I learned&lt;/h2&gt;
&lt;h3 id=&quot;how-to-work-with-a-complex-existing-codebase&quot; tabindex=&quot;-1&quot;&gt;How to work with a complex existing codebase&lt;/h3&gt;
&lt;p&gt;In my previous projects I have always started writing code from scratch, and
that&#39;s much easier because code complexity is lower,
you know where everything is,
you understand every single part of what you&#39;re building,
there are no complicated build pipelines,
and you can always just push to &lt;code&gt;origin/master&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This was significantly harder because there was already an existing medium-sized
codebase (~10,000 LOC) running tech stacks/folder structure/build pipelines
unfamiliar to me.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;lieu@pop-os ~/d/districtr &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lieu-branch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; cloc src/ sass/ html/
     &lt;span class=&quot;token number&quot;&gt;158&lt;/span&gt; text files.
     &lt;span class=&quot;token number&quot;&gt;158&lt;/span&gt; unique files.
       &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; files ignored.

github.com/AlDanial/cloc &lt;span class=&quot;token function&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.82&lt;/span&gt;  &lt;span class=&quot;token assign-left variable&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.05&lt;/span&gt; s &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3398.9&lt;/span&gt; files/s, &lt;span class=&quot;token number&quot;&gt;317945.9&lt;/span&gt; lines/s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
-------------------------------------------------------------------------------
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
JavaScript                     &lt;span class=&quot;token number&quot;&gt;110&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;703&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;543&lt;/span&gt;           &lt;span class=&quot;token number&quot;&gt;9030&lt;/span&gt;
Sass                            &lt;span class=&quot;token number&quot;&gt;35&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;424&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;53&lt;/span&gt;           &lt;span class=&quot;token number&quot;&gt;2429&lt;/span&gt;
HTML                            &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;44&lt;/span&gt;             &lt;span class=&quot;token number&quot;&gt;83&lt;/span&gt;           &lt;span class=&quot;token number&quot;&gt;1471&lt;/span&gt;
-------------------------------------------------------------------------------
SUM:                           &lt;span class=&quot;token number&quot;&gt;158&lt;/span&gt;           &lt;span class=&quot;token number&quot;&gt;1171&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;679&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;12930&lt;/span&gt;
-------------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found it very difficult to get the &amp;quot;big picture&amp;quot;: where&#39;s the entry point of
the entire app? What files call what? How and where should I add my code?
How does the build process work? This is much more difficult than implementing
some disembodied function somewhere because in order to add the new component
I had to get a working understanding of the entire codebase.
It took a long time, but it was rewarding to puzzle through it,
and---while I won&#39;t claim to know the codebase well---I now know enough to
implement future features much more quickly.&lt;/p&gt;
&lt;p&gt;Another thing I had to learn was how to use version control properly: forking the
main codebase, using branches, and making PRs back into main. It also forced me
to be more atomic with my commits as I previously had the very bad habit of
coding for hours if not days without a single commit, changing tons of files,
then running the following:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; commit &lt;span class=&quot;token parameter variable&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;add lots of stuff&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; push&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is not good practice, so I&#39;m glad that I kicked the habit.&lt;/p&gt;
&lt;h2 id=&quot;future-work&quot; tabindex=&quot;-1&quot;&gt;Future work&lt;/h2&gt;
&lt;h3 id=&quot;improve-performance-of-the-server&quot; tabindex=&quot;-1&quot;&gt;Improve performance of the server&lt;/h3&gt;
&lt;p&gt;The current server is able to quickly calculate and respond in fractions of a second
for a state like Iowa (0.007s, according to my server logs), but the delay
between sending and receiving a response can be up to 1.5s for the largest states
like Texas. This delay is barely acceptable for a single user but completely
unacceptable when we deploy it into production e.g. with multiple concurrent users.
At the current scale of Districtr, it should be more than sufficient to handle
up to 100 requests/second. It could do 100 Iowa requests/second but not
100 Texas requests/second, so there&#39;s some work to be done.&lt;/p&gt;
&lt;p&gt;I will have to do some benchmarking: why is the server slow?
Is it converting the JSON to a dual graph, generating the partition,
or sending the response back that&#39;s slow? Depending on the answer, we could
either consider horizontal scaling (implementing a load balancer) or moving to the
very recently developed JuliaChain (GerryChain in Julia). (Maybe also Amazon
lambda functions.)&lt;/p&gt;
&lt;p&gt;(&lt;strong&gt;[TODO]&lt;/strong&gt; do benchmarking and ask Bhushan/Matthew about benchmarking in Julia)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT 28/08:&lt;/strong&gt; I did the benchmarking and it turns out that loading the JSON
file in was indeed what was taking so long:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:18:54 /home/mggg/districtr-eda/dual_graphs/mggg-dual-graphs/texas.json
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:18:54 Time taken to load into gerrychain Graph from json: &lt;span class=&quot;token number&quot;&gt;0.8254358768463135&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:18:54 Time taken to form assignment from dual graph: &lt;span class=&quot;token number&quot;&gt;0.008115530014038086&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:18:54 Time taken to form partition from assignment: &lt;span class=&quot;token number&quot;&gt;0.0035495758056640625&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:18:55 Time taken to get &lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt; districts: &lt;span class=&quot;token number&quot;&gt;0.0813145637512207&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Caching the state graph (just adding it to a dictionary and checking if it exists)
makes it much, much quicker. Total response times dropped from 0.85 seconds to ~0.1 seconds.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:51 /home/mggg/districtr-eda/dual_graphs/mggg-dual-graphs/texas.json
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:51 Caching the state graph&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:51 Time taken to load into gerrychain Graph from json: &lt;span class=&quot;token number&quot;&gt;0.7195932865142822&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:51 Time taken to form assignment from dual graph: &lt;span class=&quot;token number&quot;&gt;0.0022351741790771484&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:51 Time taken to form partition from assignment: &lt;span class=&quot;token number&quot;&gt;0.002564668655395508&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:52 Time taken to get &lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt; districts: &lt;span class=&quot;token number&quot;&gt;0.013953685760498047&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 /home/mggg/districtr-eda/dual_graphs/mggg-dual-graphs/texas.json

&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 Retrieving the state graph from memory&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 Time taken to retrieve the state graph from memory: &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;.5299530029296875e-06
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 Time taken to form assignment from dual graph: &lt;span class=&quot;token number&quot;&gt;0.002898693084716797&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 Time taken to form partition from assignment: &lt;span class=&quot;token number&quot;&gt;0.003316164016723633&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2020&lt;/span&gt;-08-28 &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;:38:53 Time taken to get &lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt; districts: &lt;span class=&quot;token number&quot;&gt;0.014100790023803711&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I really enjoyed my time with MGGG and I learned a lot from implementing a
feature onto an existing codebase. I didn&#39;t learn much on the technical level,
but I did learn a lot about working as an actual software engineer
in a team contributing to an established product, rather than as a seat-of-the-pants
hackathon lone-wolf developer. This was my explicit goal when applying to MGGG,
so I am happy with the outcome.&lt;/p&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;h3 id=&quot;i-have-collected-dual-graphs-into-an-open-source-repo.&quot; tabindex=&quot;-1&quot;&gt;I have collected dual graphs into an open-source repo.&lt;/h3&gt;
&lt;p&gt;As mentioned in the text, the server cannot generate a &lt;code&gt;Partition&lt;/code&gt; without
the dual graphs. I&#39;ve thus collected dual graphs from Gabe and Nick and put them
into a repo &lt;a href=&quot;https://lieuzhenghong.com/2020/08/28/MGGG-GSoC-report/github.com/lieuzhenghong/mggg-dual-graphs&quot;&gt;here&lt;/a&gt;. I would welcome
any and all to add to the repo to roll this out to more states.&lt;/p&gt;
&lt;p&gt;(&lt;strong&gt;[TODO]&lt;/strong&gt; --- where is Districtr getting the dual graphs for all the states then??)&lt;/p&gt;
&lt;h3 id=&quot;how-to-set-up-the-server-on-pythonanywhere&quot; tabindex=&quot;-1&quot;&gt;How to set up the server on PythonAnywhere&lt;/h3&gt;
&lt;p&gt;I have written instructions on how to deploy the Flask server on PythonAnywhere
on &lt;a href=&quot;https://github.com/lieuzhenghong/districtr-eda#how-to-set-up-this-server-on-pythonanywhere&quot;&gt;the README.md in the GitHub repo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(&lt;strong&gt;[TODO]&lt;/strong&gt; deploy Flask production server)&lt;/p&gt;
&lt;h3 id=&quot;how-the-assignment-object-actually-looks-like&quot; tabindex=&quot;-1&quot;&gt;How the &lt;code&gt;assignment&lt;/code&gt; object actually looks like&lt;/h3&gt;
&lt;p&gt;I told a little white lie for ease of exposition. The &lt;code&gt;assignment&lt;/code&gt; object &lt;em&gt;actually&lt;/em&gt; looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19001&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19002&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19003&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19004&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token number&quot;&gt;19005&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each key-value pair takes the form of either an &lt;code&gt;Int: Array[Int]&lt;/code&gt; or &lt;code&gt;Int: Int&lt;/code&gt;,
where the key is the voting precinct ID and the value is the district it has been assigned to.
(For some reason, some values will appear as arrays
even though each precinct can only be assigned to one district).&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>A market-based mechanism to preserve Indonesia&#39;s forests</title>
    <link href="https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/"/>
    <updated>2020-08-19T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/</id>
    <content type="html">&lt;div class=&quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#background&quot;&gt;Background&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#the-mechanism-in-brief&quot;&gt;The mechanism in brief&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#an-explanation-of-the-mechanism&quot;&gt;An explanation of the mechanism&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#faqs&quot;&gt;FAQs&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#why-not-pay-the-owners-directly%3F-why-the-need-for-this-complicated-scheme%3F&quot;&gt;Why not pay the owners directly? Why the need for this complicated scheme?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#why-don&#39;t-we-pay-ngos-to-protect-the-forest-instead%3F&quot;&gt;Why don&amp;#39;t we pay NGOs to protect the forest instead?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#wouldn&#39;t-this-incentivise-owners-to-just-sit-on-the-forests-and-not-do-anything-to-collect-their-payout%3F&quot;&gt;Wouldn&amp;#39;t this incentivise owners to just sit on the forests and not do anything to collect their payout?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#are-we-worried-that-if-we-sell-it-to-the-highest-bidder%2C-the-highest-bidder-might-do-unsavoury-things%3F&quot;&gt;Are we worried that if we sell it to the highest bidder, the highest bidder might do unsavoury things?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#what-happens-if-there-is-collusion-amongst-the-bidders%3F&quot;&gt;What happens if there is collusion amongst the bidders?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#why-can&#39;t-the-money-go-back-to-the-philantropist-if-the-forest-burns-down%3F&quot;&gt;Why can&amp;#39;t the money go back to the philantropist if the forest burns down?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#a-system-like-this-doesn&#39;t-benefit-the-poor-farmers!-won&#39;t-the-surplus-go-to-some-finance-bro%3F&quot;&gt;A system like this doesn&amp;#39;t benefit the poor farmers! Won&amp;#39;t the surplus go to some finance bro?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#questions-i-still-have&quot;&gt;Questions I still have&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#acknowledgements&quot;&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#appendix%3A-things-i-cut%2C-links%2C-and-text-dumps&quot;&gt;Appendix: Things I cut, links, and text dumps&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Enormous swathes of virgin forest in Indonesia are being cut and burned down
all the time and this contributes significantly to the climate crisis.
How can we stop this? I propose a decentralised market-based mechanism
that has the following desirable properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scalable&lt;/li&gt;
&lt;li&gt;Decentralised&lt;/li&gt;
&lt;li&gt;Bounded cost for the philantropist&lt;/li&gt;
&lt;li&gt;Owners of the land are better off&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;background&quot; tabindex=&quot;-1&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;Norway has some sort of agreement with Indonesia where they pay Indonesia
$1 billion to reduce their forest emissions: see links
&lt;a href=&quot;https://www.wri.org/blog/2019/02/indonesia-reduces-deforestation-norway-pay&quot;&gt;here&lt;/a&gt;
and
&lt;a href=&quot;https://news.mongabay.com/2019/02/indonesia-to-get-first-payment-from-norway-under-1b-redd-scheme/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The two countries signed the $1 billion pact in 2010, under the REDD+
(reducing emissions from deforestation and forest degradation) mechanism. In
exchange for the funding, Indonesia would have to slow its emissions from
deforestation, which accounts for the bulk of its CO2 emissions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is great and should be applauded.
But this sort of enormous government-to-government approach
has its problems. First of all, what can &lt;em&gt;we&lt;/em&gt; do as private citizens, apart
from lobbying our governments? Also, this approach is &lt;em&gt;slow&lt;/em&gt;: the first payment
was paid out almost &lt;em&gt;ten years&lt;/em&gt; after the agreement was signed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;That it’s taken so long for the first payment to be announced is due to a
combination of the structuring of the agreement and a change in the
Indonesian government since the 2010 signing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I present a market mechanism that might help safeguard the forests, but doesn&#39;t
require long and protracted intergovernmental negotations and can work with
only a few dollars of funding.
The idea is probably not original and I would greatly appreciate if someone
could point me to the relevant literature.&lt;/p&gt;
&lt;h2 id=&quot;the-mechanism-in-brief&quot; tabindex=&quot;-1&quot;&gt;The mechanism in brief&lt;/h2&gt;
&lt;p&gt;In brief, the idea is as follows:
philantropists can sell a &lt;em&gt;ticket&lt;/em&gt; attached to some forested area
that pays out &lt;em&gt;if and only if&lt;/em&gt; that area remains pristine.
People would bid on the price of this ticket and the highest bidder would
stand to gain (Ticket Payout Price - Price Paid for Ticket).
With satellite imagery, we can easily tell whether an area has been logged or not,
and this would serve as a source of truth.&lt;/p&gt;
&lt;h2 id=&quot;an-explanation-of-the-mechanism&quot; tabindex=&quot;-1&quot;&gt;An explanation of the mechanism&lt;/h2&gt;
&lt;p&gt;Here&#39;s how it would work.
Suppose we have a philantropist that wants to preserve some area of forest.
And suppose his maximum willingness to pay for this area of forest is $50,000.
And now suppose we have some satellite feed of this area
(e.g. &lt;a href=&quot;https://zoom.earth/&quot;&gt;zoom.earth&lt;/a&gt;).
Then what the philantropist can do is say the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;I will pay $50,000 to the person who holds this ticket if and only if $AREA
remains forested by $DATE, as determined by satellite imagery. Otherwise,
the $50,000 will be used to fund another similar ticket. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then he simply puts this ticket up for auction. Once someone wins the bid,
the buyer pays the philantropist. The philantropist then puts his funds in escrow,
and some trusted third-party determines whether or not the area has remained
forested by the date specified in the ticket---whereupon the funds will either
be released to the bearer of the ticket, or used to fund a similar future ticket.&lt;/p&gt;
&lt;p&gt;How does this work? The buyer has an incentive to hunt down the farmer/owner
of the forest and come to some deal to make sure that the farmer/owner
doesn&#39;t cut down the land. This will probably take the form of a side payment.
And if the farmer is savvy enough he can of course purchase the ticket himself
and earn free money from doing nothing at all.&lt;/p&gt;
&lt;p&gt;This mechanism has several attractive qualities.&lt;/p&gt;
&lt;p&gt;Firstly, it&#39;s &lt;em&gt;decentralised&lt;/em&gt;: there is no government intervention needed.
This is also &lt;em&gt;scalable&lt;/em&gt;: any person could conceivably sell such a ticket for as
small or as large an area as they want, so if any citizen
wanted to be a Keeper of the Grove it they could do it &lt;em&gt;today&lt;/em&gt;, without
having to lobby their governments to do something. All you&#39;d need is a trusted
third party to i) hold funds in escrow and ii) verify the forest cover of the area,
both of which could be incentivised with some fees.&lt;/p&gt;
&lt;h2 id=&quot;faqs&quot; tabindex=&quot;-1&quot;&gt;FAQs&lt;/h2&gt;
&lt;h3 id=&quot;why-not-pay-the-owners-directly%3F-why-the-need-for-this-complicated-scheme%3F&quot; tabindex=&quot;-1&quot;&gt;Why not pay the owners directly? Why the need for this complicated scheme?&lt;/h3&gt;
&lt;p&gt;How are you going to track down the owners of the land if they live in a forest
in the middle of nowhere? Is there a unified land ownership and designation map?
Is your Indonesian good enough to find out? How likely is it that that the land
ownership map is constantly updated?
What happens if ownership has changed hands without your knowledge?
What happens if the land is co-owned by several smallholders in some sort of
sharecropping arrangement? And so on.&lt;/p&gt;
&lt;p&gt;An Indonesian friend of mine wrote to me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A universal land designation map was initiated in 2014, but it hasn’t come to
completion yet because the project has been delayed over and over again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Rather than having to spend effort to track them down ourselves,
the idea is to pay middlemen an &amp;quot;information arbitrage&amp;quot; fee:
to provide the service of tracking down the owners of the land.
The hope is that these middlemen who buy the ticket will have low-cost ways to
contact and convince the farmers.&lt;/p&gt;
&lt;h3 id=&quot;why-don&#39;t-we-pay-ngos-to-protect-the-forest-instead%3F&quot; tabindex=&quot;-1&quot;&gt;Why don&#39;t we pay NGOs to protect the forest instead?&lt;/h3&gt;
&lt;p&gt;(Thanks Filip)&lt;/p&gt;
&lt;h3 id=&quot;wouldn&#39;t-this-incentivise-owners-to-just-sit-on-the-forests-and-not-do-anything-to-collect-their-payout%3F&quot; tabindex=&quot;-1&quot;&gt;Wouldn&#39;t this incentivise owners to just sit on the forests and not do anything to collect their payout?&lt;/h3&gt;
&lt;p&gt;That is the entire point of this mechanism, yes.&lt;/p&gt;
&lt;h3 id=&quot;are-we-worried-that-if-we-sell-it-to-the-highest-bidder%2C-the-highest-bidder-might-do-unsavoury-things%3F&quot; tabindex=&quot;-1&quot;&gt;Are we worried that if we sell it to the highest bidder, the highest bidder might do unsavoury things?&lt;/h3&gt;
&lt;p&gt;We might be worried about unintended consequences.
For instance, buyers of tickets might start coercing, intimidating,
or assassinating farmers to prevent them from cutting down the forest.
If so, it might be better to give the money to a good NGO---who will
convince/cajole/massage the farmers, rather than to give money to someone
unscrupulous---who will murder the owners of the plot---even if the NGO is
more expensive.&lt;/p&gt;
&lt;p&gt;To this, I have two semi-responses.&lt;/p&gt;
&lt;p&gt;The first is that while this might be possible, another possibility is that the
NGOs are horrendously inefficient and it might be better to give the money to
an amoral corporation instead. Of course, there&#39;s no reason why NGOs can&#39;t bid
on these tickets themselves if they are indeed the most efficient organisation.
The other is that killing people is illegal (maybe this will give some people pause).
Also, why do you need to kill someone if you can just give them
money instead?&lt;/p&gt;
&lt;p&gt;Nonetheless, I see the point. Of course when we optimise for price alone there
are lots of things that we give up.
This is a problem with any sort of market or competitive pricing mechanism,
and isn&#39;t unique to this proposed mechanism.&lt;/p&gt;
&lt;h3 id=&quot;what-happens-if-there-is-collusion-amongst-the-bidders%3F&quot; tabindex=&quot;-1&quot;&gt;What happens if there is collusion amongst the bidders?&lt;/h3&gt;
&lt;p&gt;The whole system falls apart,
but I think any auction system falls apart once there is collusion amongst the buyers.
However, if the market is thick enough then collusion would be difficult to sustain.
Perhaps there might be some clever way for philantropists to demarcate areas to protect
so as to minimise the likelihood of collusion.&lt;/p&gt;
&lt;h3 id=&quot;why-can&#39;t-the-money-go-back-to-the-philantropist-if-the-forest-burns-down%3F&quot; tabindex=&quot;-1&quot;&gt;Why can&#39;t the money go back to the philantropist if the forest burns down?&lt;/h3&gt;
&lt;p&gt;In a previous version of this mechanism I suggested that the $50,000 would either
be released to the buyer, or returned back to the philantropist. I realised
that this would incentivise &amp;quot;philantropists&amp;quot; to sell a lot of tickets,
then commit arson so as not to pay out to make a profit.
Any mechanism must ensure that the philantropist can &lt;em&gt;never&lt;/em&gt; gain from this transaction.
More strongly, it must ensure that nobody can possibly make any profit
if the forest is cut down.
(Does this always hold?
I am unsure if this holds if people start coming up with complicated derivatives
and financial instruments and what not)&lt;/p&gt;
&lt;h3 id=&quot;a-system-like-this-doesn&#39;t-benefit-the-poor-farmers!-won&#39;t-the-surplus-go-to-some-finance-bro%3F&quot; tabindex=&quot;-1&quot;&gt;A system like this doesn&#39;t benefit the poor farmers! Won&#39;t the surplus go to some finance bro?&lt;/h3&gt;
&lt;p&gt;I agree, and while the thought of this is indeed somewhat unsavory, I believe
under a competitive market it should be the case that the finance bros will
bid each other up until the surplus accrues to the farmers.&lt;/p&gt;
&lt;h2 id=&quot;questions-i-still-have&quot; tabindex=&quot;-1&quot;&gt;Questions I still have&lt;/h2&gt;
&lt;p&gt;I&#39;d really be interested in knowing whether this mechanism works,
and whether it has already been thought of by somebody else under a different name.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Of course, this works with any resource that we want to preserve, not just Indonesia&#39;s forests.
You can even sell tickets on areas where the land has &lt;em&gt;already&lt;/em&gt; been cut down,
and pay out iff the land gets reforested.
To handle the issues of escrow, we could do it on the blockchain.&lt;/p&gt;
&lt;p&gt;Have I missed something? Interested in implementing this? Send me a message, please.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgements&quot; tabindex=&quot;-1&quot;&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;Thanks to Filip, Dylan, and Jonathan for reading versions of this article and
giving very helpful comments/asking very illuminating questions.&lt;/p&gt;
&lt;h2 id=&quot;appendix%3A-things-i-cut%2C-links%2C-and-text-dumps&quot; tabindex=&quot;-1&quot;&gt;Appendix: Things I cut, links, and text dumps&lt;/h2&gt;
&lt;p&gt;The key here is to realise that a) the forests are a &lt;em&gt;positive externality&lt;/em&gt;
in the sense that they sequester carbon and reduce global temperatures, and
b) we are much richer than many of the Indonesians who own the forests, and
they need to eat.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.newmandala.org/cultivating-consent/&quot;&gt;https://www.newmandala.org/cultivating-consent/&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bernardinus,* a village elder from the Basik-Basik clan, for instance,
noted that “oil palm companies come here, obtain government permits and plant
oil palm without asking permission from the traditional landowners. They
think no one lives on this land because all they see is forest. Sure,
Indonesia’s largest remaining forests are in Papua. However, people live in
and depend on these forests. Indigenous people like Marind, Mandobo, Auyu,
Jair, and many more. We own this land under customary law. And yet our voices
are not heard”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In a similar vein, Perpetua, a mother-of-four living in Khalaoyam village,
stated that “Decisions about oil palm projects are made in Jakarta, not in
Papuan villages. These decisions are made without our consent or
participation. Of course, there are problems and conflict. It’s like planting
a tree without making sure the soil is fertile and that there is enough water
and shade for the tree to flourish. The tree will grow crooked and struggle
to survive. It’s the same with oil palm projects in Merauke. The problem is
that there is no consultation or consent”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Consent on paper, however, does not guarantee consent in practice.
Bernardinus and Perpetua are just two of dozens of community members who
report not having been involved in or informed about oil palm developments
now taking place in and around their home villages. Another is Kosmas, a
Marind participant at a workshop on sustainable palm oil that I organized in
July 2019, who told me, “I only found out about that oil palm was coming
after the forest had already been cleared. Before that, I knew nothing about
the project”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In a small number of cases, government and corporate bodies have invited
indigenous landowners to participate in sosialisasi before land developments.
But sosialisasi, a term that can be translated loosely as ‘awareness raising’
or ‘public information dissemination’, is also problematic.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Firstly, sosialisasi often takes the form of a one-way transfer of
information about the planned development from the government and companies
to the communities, rather than a two-way conversation in which communities
have a say in whether or not the project will go ahead, and under what
conditions. Secondly, sosialisasi usually takes place in urban centres, such
as Merauke City or Jayapura, rather than in the villages where indigenous
communities are based. Those invited to attend these events are often
handpicked by the government and companies and do not represent the broader
interests or rights of the communities to which they belong. Thirdly,
sosialisasi meetings are frequently supervised or attended by members of the
police and military, who work with oil palm companies in the capacity of
plantation security patrols and brokers. Many Marind are reluctant to speak
out freely under such conditions for fear of consequent reprisal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Meanwhile, Marind villagers who have already voiced their opposition to oil
palm projects during consultations complained of being persistently
approached, and sometimes intimidated, by company personnel and police
officials to surrender their lands for agribusiness development. “They keep
coming and asking us to change our minds,” reported village elder Geronimo.
“We already said no, but they think that if they keep pushing us, we will
agree to collaborate. That is not seeking consent. That is harassment”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Why this harassment? Incentives not aligned. At the moment, oil companies
want to skirt the law any way they can. If we can pay the oil palm companies
or local governments more money to leave the land intact, this problem solves
itself.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The $50,000 needs to be &amp;quot;burned&amp;quot; (to use a crypto term) somehow. It
cannot go back to the philantropist/to charity or to any third party, because
then that person will have a perverse incentive to make sure the area of land
is cut down in order to receive the payout. &lt;a href=&quot;https://lieuzhenghong.com/explorations/forest_exploration/a-market-based-mechanism-to-preserve-indonesia&#39;s-forests/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Rebuilding this website</title>
    <link href="https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/"/>
    <updated>2020-08-03T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/</id>
    <content type="html">&lt;h2 id=&quot;table-of-contents&quot; tabindex=&quot;-1&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#table-of-contents&quot;&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#restoring-existing-functionality&quot;&gt;Restoring existing functionality&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#learning-the-templating-language&quot;&gt;Learning the templating language&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#writing-custom-filters&quot;&gt;Writing custom filters&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#parsing-markdown-snippets&quot;&gt;Parsing Markdown snippets&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#maintaining-backwards-compatibility-with-old-permalinks&quot;&gt;Maintaining backwards compatibility with old permalinks&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#improving-the-website&quot;&gt;Improving the website&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#adding-a-dark-mode&quot;&gt;Adding a dark mode&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#revamping-the-projects-page&quot;&gt;Revamping the projects page&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#supporting-markdown-table-of-contents-and-footnotes&quot;&gt;Supporting Markdown table of contents and footnotes&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#rendering-latex%2C-and-moving-from-mathjax-to-katex&quot;&gt;Rendering LaTeX, and moving from MathJax to KaTeX&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#things-i-still-need-to-do&quot;&gt;Things I still need to do&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#fix-broken-post-links&quot;&gt;Fix broken post links&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#fix-broken-image-links&quot;&gt;Fix broken image links&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#sites-and-blogs-i-drew-reference-from&quot;&gt;Sites and blogs I drew reference from&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/03/blog-rebuild-2020/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blog_redesign_2020/old_blog.png&quot; alt=&quot;The old front page&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blog_redesign_2020/new_blog.png&quot; alt=&quot;The redesigned front page&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;restoring-existing-functionality&quot; tabindex=&quot;-1&quot;&gt;Restoring existing functionality&lt;/h2&gt;
&lt;h3 id=&quot;learning-the-templating-language&quot; tabindex=&quot;-1&quot;&gt;Learning the templating language&lt;/h3&gt;
&lt;h3 id=&quot;writing-custom-filters&quot; tabindex=&quot;-1&quot;&gt;Writing custom filters&lt;/h3&gt;
&lt;h3 id=&quot;parsing-markdown-snippets&quot; tabindex=&quot;-1&quot;&gt;Parsing Markdown snippets&lt;/h3&gt;
&lt;h3 id=&quot;maintaining-backwards-compatibility-with-old-permalinks&quot; tabindex=&quot;-1&quot;&gt;Maintaining backwards compatibility with old permalinks&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.w3.org/Provider/Style/URI.html&quot;&gt;&amp;quot;Cool URIs don&#39;t change&amp;quot;&lt;/a&gt;
consistently emphasises the need for URIs not to change,
mainly because someone may have bookmarked your post&#39;s old URL
and it would be terrible if they couldn&#39;t find it any more.
Eleventy&#39;s default paths when generating posts was different from Jekyll&#39;s,
so I made sure to point the URLs to the same place by putting&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;permalink: &amp;quot;/{{ page.date | date: &#39;%Y/%m/%d&#39; }}/{{page.fileSlug}}/&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the YAML front matter.&lt;/p&gt;
&lt;p&gt;The &amp;quot;Cool URIs don&#39;t change&amp;quot; post recommends
indexing by the creation date of the document,
as it is one thing that doesn&#39;t change.
&amp;quot;If a document is in any way dated, even though it will be of interest for generations,
then the date is a good starter.&amp;quot;
It recommends a URI like &lt;code&gt;http://www.w3.org/1998/12/01/chairs&lt;/code&gt;,
which is indeed what Jekyll uses by default.&lt;/p&gt;
&lt;p&gt;The post further writes &amp;quot;the only exception is a page which is deliberately
a &amp;quot;latest&amp;quot; page for, for example, the whole organization or a large part of it&amp;quot;,
for instance, &lt;code&gt;http://www.pathfinder.com/money/moneydaily/latest&lt;/code&gt;
gives the latest version of the &amp;quot;Money daily&amp;quot; column in &amp;quot;Money&amp;quot; magazine.
If you want to link to the content, however, one would link to it where it appears
separately in the archives as&lt;/p&gt;
&lt;p&gt;&lt;code&gt;http://www.pathfinder.com/money/moneydaily/1998/981212.moneyonline.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In my case the &amp;quot;latest&amp;quot; pages are the index pages: home, about, projects, archive, etc,
and most of the rest of the blog posts are dated.&lt;/p&gt;
&lt;p&gt;For some of my work, I am considering following Gwern&#39;s example to make URIs indexed by a topic sentence: for instance,&lt;/p&gt;
&lt;p&gt;&lt;code&gt;https://www.gwern.net/Ethical-sperm-donation&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;links to a page entitled &amp;quot;The Morality of Sperm Donation&amp;quot;.
The pages are constantly updated:
while the page was first written in 2012,
the last major update to the page was in 2018.
This makes sense for Gwern&#39;s &amp;quot;long content&amp;quot;: the date of document creation is
irrelevant because the pages are constantly updated.
I don&#39;t have much long content on the site yet,
but I hope to start writing some soon.
I think the explorations and explanations would be good candidates.&lt;/p&gt;
&lt;h2 id=&quot;improving-the-website&quot; tabindex=&quot;-1&quot;&gt;Improving the website&lt;/h2&gt;
&lt;h3 id=&quot;adding-a-dark-mode&quot; tabindex=&quot;-1&quot;&gt;Adding a dark mode&lt;/h3&gt;
&lt;h3 id=&quot;revamping-the-projects-page&quot; tabindex=&quot;-1&quot;&gt;Revamping the projects page&lt;/h3&gt;
&lt;h3 id=&quot;supporting-markdown-table-of-contents-and-footnotes&quot; tabindex=&quot;-1&quot;&gt;Supporting Markdown table of contents and footnotes&lt;/h3&gt;
&lt;h3 id=&quot;rendering-latex%2C-and-moving-from-mathjax-to-katex&quot; tabindex=&quot;-1&quot;&gt;Rendering LaTeX, and moving from MathJax to KaTeX&lt;/h3&gt;
&lt;h2 id=&quot;things-i-still-need-to-do&quot; tabindex=&quot;-1&quot;&gt;Things I still need to do&lt;/h2&gt;
&lt;h3 id=&quot;fix-broken-post-links&quot; tabindex=&quot;-1&quot;&gt;Fix broken post links&lt;/h3&gt;
&lt;h3 id=&quot;fix-broken-image-links&quot; tabindex=&quot;-1&quot;&gt;Fix broken image links&lt;/h3&gt;
&lt;h2 id=&quot;sites-and-blogs-i-drew-reference-from&quot; tabindex=&quot;-1&quot;&gt;Sites and blogs I drew reference from&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://practicaltypography.com/&quot;&gt;Practical Typography&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://gwern.net/&quot;&gt;gwern.net&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://reasonabledeviations.com/&quot;&gt;Reasonable Deviations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://iainbean.com/posts/2020/your-blog-doesnt-need-a-javascript-framework/&quot;&gt;Iain Bean&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h3&gt;
</content>
  </entry>
  <entry>
    <title>Building a code sharing MVP with React and the WebSockets API</title>
    <link href="https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/"/>
    <updated>2020-08-02T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/</id>
    <content type="html">&lt;div class=&quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#task&quot;&gt;Task&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#introduction-1&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#questions&quot;&gt;Questions&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#my-attempt&quot;&gt;My attempt&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#question-1-%3A-designing-a-scalable-system-architecture&quot;&gt;Question 1 : Designing a scalable system architecture&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#question-2%3A-build-a-code-sharing-view-with-react-and-expressjs.&quot;&gt;Question 2: Build a code sharing view with React and ExpressJS.&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#room&quot;&gt;Room&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#actions&quot;&gt;Actions&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#schema-for-each-websocket-request-from-client---%3E-server&quot;&gt;Schema for each WebSocket request from client --&amp;gt; server&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#how-does-the-server-respond-to-each-type-of-action%3F&quot;&gt;How does the server respond to each type of action?&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#if-action-%3D%3D%3D-%22join%22%3A&quot;&gt;If action === &amp;quot;JOIN&amp;quot;:&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#if-action-%3D%3D%3D-%22leave%22-(not-implemented)%3A&quot;&gt;If action === &amp;quot;LEAVE&amp;quot; (NOT IMPLEMENTED):&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#if-action-%3D%3D%3D-%22run%22-(implemented-but-not-used)%3A&quot;&gt;If action === &amp;quot;RUN&amp;quot; (IMPLEMENTED BUT NOT USED):&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#if-action-type-%3D%3D%3D-%22share%22%3A&quot;&gt;If action type === &amp;quot;SHARE&amp;quot;:&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#what-sort-of-messages-can-a-client-expect-to-receive%3F&quot;&gt;What sort of messages can a client expect to receive?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/2020/08/02/xccelerate-technical-interview/#faqs&quot;&gt;FAQs&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;h1 id=&quot;task&quot; tabindex=&quot;-1&quot;&gt;Task&lt;/h1&gt;
&lt;h2 id=&quot;introduction-1&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;ThirdSpace is a real-time classroom environment where students can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Execute and submit code to instructors.&lt;/li&gt;
&lt;li&gt;Access files and resources (homework) from instructors.&lt;/li&gt;
&lt;li&gt;Chat with each other, and ask questions.&lt;/li&gt;
&lt;li&gt;View real-time or pre-recorded lectures.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Instructors have separate views where they can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;View submitted code from every student.&lt;/li&gt;
&lt;li&gt;Share their code to the students code editor.&lt;/li&gt;
&lt;li&gt;Post files and resources (homework).&lt;/li&gt;
&lt;li&gt;Create courses with scheduled classes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;questions&quot; tabindex=&quot;-1&quot;&gt;Questions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;To the best of your abilities, please design a scalable system
architecture for ThirdSpace. No code needed.&lt;/li&gt;
&lt;li&gt;Build a simple application with ReactJS and ExpressJS. You may use any JS libraries to your liking. Please see the instructions here.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;my-attempt&quot; tabindex=&quot;-1&quot;&gt;My attempt&lt;/h1&gt;
&lt;h2 id=&quot;question-1-%3A-designing-a-scalable-system-architecture&quot; tabindex=&quot;-1&quot;&gt;Question 1 : Designing a scalable system architecture&lt;/h2&gt;
&lt;p&gt;I break the monolithic environment into separate services:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Code share+submit service&lt;/strong&gt;: Instructors enter private rooms with students,
and can share solutions with students. Students execute and submit code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code viewing service&lt;/strong&gt;: A static view for instructors to view submitted code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat service&lt;/strong&gt;: Real-time chat.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Course view service&lt;/strong&gt;: largely static service to display text, images, and videos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live stream service&lt;/strong&gt;: dedicated service to encode streaming media and chunk it&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ll now go through the overall architecture and show where the individual services fit in.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lieuzhenghong.com/xccelerate_interview/serverless-architecture.png&quot; alt=&quot;Overall architecture&quot;&gt;&lt;/p&gt;
&lt;p&gt;The overall architecture uses Amazon&#39;s API Gateway, AWS Lambda, and Amazon DynamoDB
for scalability. We use these services as we get scalability &amp;quot;for free&amp;quot;, although
I also sketch out non-AWS alternatives.&lt;/p&gt;
&lt;p&gt;Upon authenticating, students enter the ThirdSpace classroom environment.
The student&#39;s client establishes several WebSocket connections to an Amazon API Gateway.
The following WebSocket connections are established through the API Gateway:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Chat service WS&lt;/li&gt;
&lt;li&gt;Code sharing service WS&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additionally, the client also makes the appropriate GET request to the Course view service,
which will display the courses that the students are involved in.&lt;/p&gt;
&lt;p&gt;Suppose the student now wants to chat. He will then send messages through
the established WebSocket to the API Gateway which calls an AWS Lambda function.
The waiting AWS Lambda function calls Amazon DynamoDB for the WebSockets
subscribed to the chat channel, and callback to the API Gateway.
The API Gateway then sends payloads through all the other WebSocket connections.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lieuzhenghong.com/xccelerate_interview/websockets-chat-app.png&quot; alt=&quot;Chat service with Amazon API Gateway&quot;&gt;&lt;/p&gt;
&lt;p&gt;The same principle applies to the code sharing service (we build an MVP in
section 2), which is very similar to the real time chat service. Once again,
students send code through the WebSocket which calls an AWS Lambda function.
The difference is that this function may need to compile the submitted code
(only Javascript can be interpreted client-side) as well. As before, it calls
DynamoDB, and returns payloads to the teacher&#39;s Websocket connection.&lt;/p&gt;
&lt;p&gt;The course view service can be handled with a normal REST API. We can either
use Amazon&#39;s API Gateway with Amazon DynamoDB or a more traditional
architecture running on a server (or multiple servers).&lt;/p&gt;
&lt;p&gt;If we want a more traditional approach: students send GET requests to the
server, and instructors who wish to upload course materials can make a POST
request to the server. We can ensure scalability by using a load balancer,
and course materials can be stored in some shared database.&lt;/p&gt;
&lt;p&gt;Finally, live streaming should be handled with HTTP Live Streaming (HLS).
The following diagram from &lt;a href=&quot;https://developer.apple.com/documentation/http_live_streaming&quot;&gt;Apple&#39;s developer documentation&lt;/a&gt; lays out all the moving parts:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lieuzhenghong.com/xccelerate_interview/HLS-streaming.png&quot; alt=&quot;Live stream service with HLS&quot;&gt;&lt;/p&gt;
&lt;p&gt;We should use a dedicated server to receive AV input from instructors,
do the encoding and stream segmentation
(this could be farmed out to Lambda functions)
and serve them out to the clients.&lt;/p&gt;
&lt;h2 id=&quot;question-2%3A-build-a-code-sharing-view-with-react-and-expressjs.&quot; tabindex=&quot;-1&quot;&gt;Question 2: Build a code sharing view with React and ExpressJS.&lt;/h2&gt;
&lt;p&gt;The code for the app is on a private repository &lt;a href=&quot;https://github.com/lieuzhenghong/Xccelerate-Engineering-Test&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is what an old version of the app looks like (GIF):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://lieuzhenghong.com/xccelerate_interview/xccelerate_mvp.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;There is a React app running on port 3000 and an Express server running on port 3333. Clients communicate with the server using a bidirectional WebSockets connection. The server contains a list of Rooms and can handle actions (instead of routes) such as join (a room), leave (a room), run (some code), and share (some code).
We can see that the teacher&#39;s view updates in real-time as the student
submits his or her code.&lt;/p&gt;
&lt;p&gt;Below is the backend schema:&lt;/p&gt;
&lt;h3 id=&quot;room&quot; tabindex=&quot;-1&quot;&gt;Room&lt;/h3&gt;
&lt;p&gt;This lives in memory but should be stored in a datastore.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Room&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;teacher&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Username&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;sharedCode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;teacher_ws&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WebSocket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;student_ws&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WebSocket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;actions&quot; tabindex=&quot;-1&quot;&gt;Actions&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&amp;quot;JOIN&amp;quot; -- join a room&lt;/li&gt;
&lt;li&gt;&amp;quot;LEAVE&amp;quot; -- leave a room&lt;/li&gt;
&lt;li&gt;&amp;quot;RUN&amp;quot; -- run some code (Student view only)&lt;/li&gt;
&lt;li&gt;&amp;quot;SHARE&amp;quot; -- submit some code to the Teacher in the room (Student view only)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;schema-for-each-websocket-request-from-client---%3E-server&quot; tabindex=&quot;-1&quot;&gt;Schema for each WebSocket request from client --&amp;gt; server&lt;/h4&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Username&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;just a string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;JOIN&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LEAVE&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RUN&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SHARE&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;roomId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RoomID&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;just a string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Student&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Teacher&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// This is action specific&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// If action is &quot;JOIN&quot;:&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;roomId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RoomID
    &lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Student&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Teacher&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// or if action type is Leave, payload is&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;roomId&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; RoomID
    &lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Student&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Teacher&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// or, if action type is Run, payload is&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a &lt;span class=&quot;token constant&quot;&gt;JS&lt;/span&gt; string that can be run
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// or, if action type is Submit, payload is&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;shared_code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a &lt;span class=&quot;token constant&quot;&gt;JS&lt;/span&gt; string corresponding to input code
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;how-does-the-server-respond-to-each-type-of-action%3F&quot; tabindex=&quot;-1&quot;&gt;How does the server respond to each type of action?&lt;/h3&gt;
&lt;h4 id=&quot;if-action-%3D%3D%3D-%22join%22%3A&quot; tabindex=&quot;-1&quot;&gt;If action === &amp;quot;JOIN&amp;quot;:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Look at the payload and check whether:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;The room exists&lt;/li&gt;
&lt;li&gt;If the room exists, whether the role is taken&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Return the Room object or an error message&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;if-action-%3D%3D%3D-%22leave%22-(not-implemented)%3A&quot; tabindex=&quot;-1&quot;&gt;If action === &amp;quot;LEAVE&amp;quot; (NOT IMPLEMENTED):&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;check whether the person is actually in the room with that role&lt;/li&gt;
&lt;li&gt;return either some acknowledgement or return an error message&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;if-action-%3D%3D%3D-%22run%22-(implemented-but-not-used)%3A&quot; tabindex=&quot;-1&quot;&gt;If action === &amp;quot;RUN&amp;quot; (IMPLEMENTED BUT NOT USED):&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Take the payload code and run it on an interpreter&lt;/li&gt;
&lt;li&gt;Return the outcome of the code (could be an error, or some output)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;if-action-type-%3D%3D%3D-%22share%22%3A&quot; tabindex=&quot;-1&quot;&gt;If action type === &amp;quot;SHARE&amp;quot;:&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Take the payload code and broadcast it to the other person in the room&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-sort-of-messages-can-a-client-expect-to-receive%3F&quot; tabindex=&quot;-1&quot;&gt;What sort of messages can a client expect to receive?&lt;/h3&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;responseType&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;JOIN&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;LEAVE&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;RUN&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SHARE&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ERROR&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Room&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// again, action dependent&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// if response_type === &quot;JOIN&quot;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// empty&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Student&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Teacher&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// if response_type === &quot;RUN&quot;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;codeOutput&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// if response_type === &quot;SHARE&quot;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;shared_code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// if response_type === &quot;ERROR&quot;&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token literal-property property&quot;&gt;error_message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;faqs&quot; tabindex=&quot;-1&quot;&gt;FAQs&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Why no tests?&lt;/strong&gt; I didn&#39;t put them in due to time contraints, but I should have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why no routes (GET/POST)?&lt;/strong&gt; Given that the app needed real-time bidirectional communication between client and server, I decided to use WebSockets. And if we use WebSockets we don&#39;t really need routes because WebSockets allows us to send arbitrary JSON very quickly.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Singapore&#39;s GRC system likely advantages the PAP: a game-theoretic analysis</title>
    <link href="https://lieuzhenghong.com/explorations/pap_exploration/pap-smc-grc/"/>
    <updated>2020-07-07T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/explorations/pap_exploration/pap-smc-grc/</id>
    <content type="html">&lt;p&gt;(with huge thanks to Tsun Lok, Bassel and Chin Wee, and thanks to all who
proofread early drafts and gave helpful comments).&lt;/p&gt;
&lt;p&gt;~2000 words&lt;/p&gt;
&lt;h1 id=&quot;overview&quot; tabindex=&quot;-1&quot;&gt;Overview&lt;/h1&gt;
&lt;p&gt;I develop a game-theoretic model of electoral contestation in Singapore and
show that having multi-member GRCs rather than only single-member
constituencies (SMCs) gives the incumbent party more seats if the incumbent&#39;s
&amp;quot;strong&amp;quot; candidates are significantly stronger than the opposition&#39;s ones.&lt;/p&gt;
&lt;p&gt;Given that this assumption is likely to be true, this suggests that the GRC
system advantages the PAP and gives it more seats than it would otherwise win
under a &amp;quot;pure&amp;quot; single-member constituency system like the UK&#39;s.&lt;/p&gt;
&lt;h1 id=&quot;background&quot; tabindex=&quot;-1&quot;&gt;Background&lt;/h1&gt;
&lt;p&gt;First---what&#39;s a GRC? From the &lt;a href=&quot;https://en.wikipedia.org/wiki/Constituencies_of_Singapore&quot;&gt;Wikipedia
page&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Group Representation Constituency (GRC) is a type of electoral constituency
(unique to Singaporean politics. They are multi-member constituencies (usually
4, 5 or 6 seats) which are contested by teams of candidates &lt;strong&gt;from one party&lt;/strong&gt;
or from independents.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In each GRC, at least one candidate in the slate must be from a minority race
(ergo non-Chinese). The ostensible purpose of the GRC system is to ensure
minority representation. It may well do that, but might it inadvertently
benefit the PAP as well?&lt;/p&gt;
&lt;p&gt;GRCs operate with a plurality voting system voting by party slate, meaning that
the party with the largest share of votes wins all the seats in the GRCs. But
this may make us ponder. A strong candidate can single-handedly win all the
seats in the GRC. For instance, if the PAP fielded four chimpanzees and the
late MM Lee in a five-member GRC, it would handily win that GRC (and thus five
seats) through the force of MM Lee alone. In contrast, an electoral system that
only contained single-member constituencies (SMCs) would mean that MM Lee could
only ever win one seat by himself no matter how great he was.&lt;/p&gt;
&lt;p&gt;The reasoning I&#39;ve put forth is quite intuitive: strong MPs can &amp;quot;carry&amp;quot; weak
ones in the GRC system but not the SMC system. But how do we formalise this
intuition? And how large is this effect, if any? I come up with a toy
game-theoretic model to answer these questions. I show not only &lt;em&gt;that&lt;/em&gt; the GRC
system gives the PAP an advantage, but also the extent of this advantage---and
that that this advantage works through magnifying existing advantages that the
PAP already has.&lt;/p&gt;
&lt;h1 id=&quot;building-a-game-theoretic-model&quot; tabindex=&quot;-1&quot;&gt;Building a game-theoretic model&lt;/h1&gt;
&lt;p&gt;First a preliminary note. When modeling it is vitally important to make the
model as simple as possible---and then even simpler than that. Otherwise the
problem becomes completely intractable. And thus this model leaves out many
important considerations by necessity.&lt;/p&gt;
&lt;p&gt;With that said: In any election there are stronger candidates and weaker
candidates. For simplicity, let us consider two types of candidates: (1)
eloquent, long-serving, well-respected candidates (minister-calibre candidates)
and (2) other candidates (perhaps-currently-not-minister-calibre candidates).
For example in Jurong GRC, one might think that Tharman and Xie Yao Quan would
respectively exemplify the qualities of each category.&lt;/p&gt;
&lt;p&gt;Let&#39;s now assume that a &amp;quot;weak&amp;quot; candidate has a strength of 0 and a &amp;quot;strong&amp;quot;
candidate a strength of 1. Let&#39;s further assume the PAP&#39;s stronger candidates
are stronger than the Opposition&#39;s candidates. This can be thought of as an
&amp;quot;incumbency bonus&amp;quot; and you can interpret it in any way you find reasonable.
I am partial to three main explanations for this incumbency bonus:&lt;/p&gt;
&lt;p&gt;Firstly, the PAP&#39;s political dominance may give it a recruiting advantage (as
minister-calibre candidates may not want to risk their careers on joining
Opposition).&lt;/p&gt;
&lt;p&gt;Secondly, the PAP&#39;s political longevity gives it an incumbency advantage. If
two candidates are identical but one has been a minister for ten years and the
other an Opposition MP for five, the former will be perceived as stronger by
the electorate.&lt;/p&gt;
&lt;p&gt;Lastly, the relative friendliness of state media to the PAP&#39;s interests can
also give its candidates an incumbency advantage. Whichever explanation you
prefer, let&#39;s say that &amp;quot;strong&amp;quot; PAP candidates have strength 2 but &amp;quot;strong&amp;quot;
Opposition candidates only 1.&lt;/p&gt;
&lt;p&gt;Now consider this game.&lt;/p&gt;
&lt;p&gt;The 2020 General Elections has 14 SMCs, 6 four-member GRCs, and 11 five-member
GRCs, for a total of 93 (14 + 6 * 4 + 11 * 5) seats. This is a total of 31
districts. Each party wants to find the optimal assignment of strong and weak
candidates over all 31 districts such that:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;in each district, the party that has allocated the higher sum of candidates&#39;
strength will win all the seats in that district;&lt;/li&gt;
&lt;li&gt;both parties seek to maximise the total number of seats they expect to win.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(those with a background in game theory may recognise this as a variant of the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Blotto_game&quot;&gt;Blotto game&lt;/a&gt;).&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This can be a bit confusing, so let&#39;s run through a tiny example. Let&#39;s suppose
that there are only two districts: Yuhua SMC and Jurong GRC. Let&#39;s
further suppose that the PAP has two strong candidates (Grace Fu &amp;amp; Tharman)
while the opposition only has one. If the PAP chooses to field one strong
candidate in each district, its strength in each district is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yuhua SMC: 2&lt;/li&gt;
&lt;li&gt;Jurong GRC: 2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But if it chooses to field both strong candidates in Jurong GRC, its strength
in each district is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yuhua SMC: 0&lt;/li&gt;
&lt;li&gt;Jurong GRC: 4&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now suppose the opposition chooses to field its strong candidate in Yuhua SMC.
Its strength in each district is therefore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yuhua SMC: 1&lt;/li&gt;
&lt;li&gt;Jurong GRC: 0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then if PAP had chosen to field one strong candidate in each district it wins
all six seats, because it wins Yuhua SMC (2 &amp;gt; 1). But if it chose to field both
strong candidates in Jurong GRC it would win only 5 seats as Yuhua SMC would be
lost to the Opposition.&lt;/p&gt;
&lt;p&gt;Hopefully that clarifies.&lt;/p&gt;
&lt;p&gt;One final point: this game can be played either &lt;em&gt;simultaneously&lt;/em&gt; or
&lt;em&gt;sequentially&lt;/em&gt;. In the simultaneous version of the game, both parties choose
where to send their MPs at the same time with no idea what the other party is
doing. In the &lt;em&gt;sequential&lt;/em&gt; version of the game, the PAP first chooses how to
field its candidates. Then the Opposition observes the PAP&#39;s move and then
chooses how to field its candidates. The rationale for this is that the
opposition has &lt;em&gt;some&lt;/em&gt; idea of which incumbent PAP MPs are in which area, and
whether they are strong or not.&lt;/p&gt;
&lt;p&gt;In this exploration I use the sequential game as it is (1) easier to solve and
(2) I suspect that the results will be even more skewed in favour of the PAP if
the Opposition has no last-mover advantage (see Technical Appendix). That is to
say, if we find a PAP advantage when the Opp gets to observe the PAP&#39;s actions,
we should strongly suspect that this advantage will increase when the Opp
&lt;em&gt;doesn&#39;t&lt;/em&gt; get to observe the PAP&#39;s actions.&lt;/p&gt;
&lt;p&gt;So that&#39;s the game-theoretic model. To reiterate:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Each party is endowed with a different number of strong and weak candidates.
The PAP&#39;s strong candidates are worth 2 while the Opposition&#39;s candidates
are worth 1.&lt;/li&gt;
&lt;li&gt;First, the PAP assigns strong and weak candidates to all 31 districts.&lt;/li&gt;
&lt;li&gt;After having observed the PAP&#39;s assignment, the Opposition assigns &lt;em&gt;their&lt;/em&gt;
strong and weak candidates to those 31 districts.&lt;/li&gt;
&lt;li&gt;We compare the strength of each party in each district and add up the
expected number of seats won by every party (Draws give half the seats of
the district to both parties).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We&#39;ve just specified the game, and can now analyse it.&lt;/p&gt;
&lt;h1 id=&quot;methodology&quot; tabindex=&quot;-1&quot;&gt;Methodology&lt;/h1&gt;
&lt;p&gt;The full electoral situation has 31 districts and 93 seats---too large to
analyse quickly---so I decided to shrink it by one-third to make it tractable.
In my reduced game, there are six SMCs and five 5-man GRCs, for a total of 31
(6 * 1 + 5 * 5) seats. I made sure to keep the ratio of SMC and GRC seats
roughly similar to the full electoral case.&lt;/p&gt;
&lt;p&gt;We need one more piece of information to solve the game: the &lt;em&gt;number&lt;/em&gt; of strong
and weak candidates that the PAP and Opposition have. You could attempt to use
your judgment to identify this number, but this would introduce human bias;
instead, I try a variety of different combinations to make sure my results are
robust.&lt;/p&gt;
&lt;p&gt;I didn&#39;t try to do anything fancy when solving the game: I just used a brute
force approach. A sequential game with perfect information can be solved with
&lt;a href=&quot;https://en.wikipedia.org/wiki/Backward_induction#Backward_induction_in_game_theory:_the_ultimatum_game&quot;&gt;&lt;em&gt;backward
induction&lt;/em&gt;&lt;/a&gt;.
Here&#39;s how I went about it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I first generated exhaustively &lt;em&gt;all&lt;/em&gt; possible ways the PAP could assign
candidates to districts. I then did the same for the Opposition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Then, for each of these PAP-assignments, I looked at each of the Opposition&#39;s
assignments and selected the Opposition&#39;s optimal strategy: that is, I found
the Opp-assignment that would give the most seats &lt;em&gt;given that PAP assignment&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This told me what the Opposition&#39;s best response/optimal strategy would be
&lt;em&gt;given each PAP assignment&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Finally, I looked at all the PAP-assignments and Opp-best-responses, and
chose the assignment that maximised the PAP&#39;s number of seats.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;All this was done with Python in a Jupyter Notebook and can be found &lt;a href=&quot;https://colab.research.google.com/drive/1MBDaxu7Ep6yx30llR8Q8T33MinWvxCqH#scrollTo=kWQUvKopW8IZ&quot;&gt;here&lt;/a&gt; (warning: very rough).&lt;/p&gt;
&lt;h1 id=&quot;results&quot; tabindex=&quot;-1&quot;&gt;Results&lt;/h1&gt;
&lt;p&gt;Including GRCs gives the PAP more seats compared to a pure-SMC electoral
landscape. Figure 1 plots the number of seats the PAP wins under both types of
electoral systems with different combinations of strong candidates.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/pap/sens_analysis.jpg&quot; alt=&quot;Figure 1: Sensitivity analysis of different combinations of strong candidates
for each party&quot;&gt;&lt;/p&gt;
&lt;p&gt;The first table shows the number of seats won under the pure-SMC electoral
landscape (i.e. 31 SMCs). For instance, the top left hand corner shows how many
seats the PAP would win if it had five strong candidates and the opposition had
two. The PAP puts its five strong candidates anywhere and the Opp judiciously
avoids those strong candidates. The end result is that the PAP wins five
districts, loses two districts, and draws the remaining (31-5-2 = 24) districts,
winning a total of (24/2 + 5 = 17) seats out of 31.&lt;/p&gt;
&lt;p&gt;The second table shows the number of seats won under a landscape with 6 SMCs
and 5 GRCs. Again, let&#39;s look at the top left hand corner as an example. The
PAP&#39;s optimal strategy is to put one strong candidate in each GRC (thus each
GRC has strength 2). The Opposition chooses to put &lt;em&gt;both&lt;/em&gt; strong candidates in
one of the GRCs to contest it, causing a draw. The PAP thus wins half of the
six SMCs, four GRCs, and half of the final contested GRC, for a total of (6/2 +
4 * 5 + 5/2 = 25.5) seats.&lt;/p&gt;
&lt;p&gt;While in this case the PAP has more strong MPs than the Opposition, we can see
that the PAP benefits under the GRC system regardless of the number of strong
candidates. In fact, the PAP wins more seats (17.5 vs 14.5) even when it has a
numerical advantage (5 strong PAP vs 7 strong Opp). The advantage is magnified
when there is a large discrepancy between the number of strong candidates each
party has.&lt;/p&gt;
&lt;h1 id=&quot;caveats&quot; tabindex=&quot;-1&quot;&gt;Caveats&lt;/h1&gt;
&lt;p&gt;Firstly, my results depend strongly on the &lt;em&gt;incumbency strength bonus&lt;/em&gt; and the
relative ratio of strong MPs for each party. Here each strong PAP candidate is
worth two opposition ones. With a low enough incumbency strength bonus, the
last-mover advantage the Opposition has can give them the advantage.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/pap/sens_analysis_2.jpg&quot; alt=&quot;Figure 2: Robustness check&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2 shows the results of subsequent analyses I ran with a lower incumbency
strength bonus (1.5 vs 2) and a larger range of strong PAP candidates. We can
see that the GRC may actually &lt;em&gt;disadvantage&lt;/em&gt; the PAP if the number of strong
PAP candidates is significantly lower than the number of strong Opposition
candidates. It&#39;s more accurate to think of the GRC system as a
&lt;em&gt;&amp;quot;variance-increasing&amp;quot;&lt;/em&gt; system.&lt;/p&gt;
&lt;p&gt;However, I don&#39;t think looking at the lower end is that interesting, because
(1) it seems unlikely that the PAP has significantly fewer strong candidates
than the opposition, and (2) I strongly suspect that the PAP disadvantage will
disappear completely in the simultaneous game without the WP&#39;s last-mover
advantage.&lt;/p&gt;
&lt;p&gt;Secondly, the results may be specific to a particular range of strong/weak MPs
or a particular makeup of SMCs and GRCs. I&#39;ve tried to ward this
criticism off by trying multiple combinations but may have missed something.
Nonetheless, I&#39;m quite sure---but not 100% certain---that this analysis will
hold for the larger 93-seat game.&lt;/p&gt;
&lt;p&gt;Finally---to be clear, there is nothing &lt;em&gt;inherent&lt;/em&gt; about the GRC system that
benefits the PAP. It is only when paired with the assumption of incumbency
advantage (and a reasonable number of strong v. weak candidates) that the GRC
system becomes structurally favourable for the PAP. This insight is important,
because it allows us to infer whether or not the PAP intentionally benefits
from the GRC system. If it is, then we should expect to observe either a
decrease in GRC size or an increase in the number of SMCs relative to GRCs in
the future if the Opposition gains in relative size and strength.&lt;/p&gt;
&lt;h1 id=&quot;conclusion-and-discussion&quot; tabindex=&quot;-1&quot;&gt;Conclusion and discussion&lt;/h1&gt;
&lt;p&gt;Provided that the incumbency strength bonus is high enough, the GRC system
advantages the PAP by letting it win more seats than it would have under a
traditional single-member system. We should thus carefully consider whether the
purported benefits to minority representation outweigh the increased
disproportionality that results.&lt;/p&gt;
&lt;p&gt;Future research should try to solve the simultaneous version of this Blotto
game, and try to find a relationship between the incumbency strength bonus and
the number of extra seats won.&lt;/p&gt;
&lt;h1 id=&quot;technical-appendix&quot; tabindex=&quot;-1&quot;&gt;Technical appendix&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Claim&lt;/strong&gt;: The simultaneous Blotto game will always give the PAP more seats
compared to the sequential Blotto game.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proof&lt;/strong&gt;: Is this actually true? TBD. (Ask Bassel for help).&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>My 2020 fitness routine</title>
    <link href="https://lieuzhenghong.com/fitness_routine/"/>
    <updated>2020-07-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/fitness_routine/</id>
    <content type="html">&lt;div class = &quot;toc&quot;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#goals&quot;&gt;Goals&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#anterior-pelvic-tilt&quot;&gt;Anterior pelvic tilt&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#strengthening-the-glutes-and-stretching-the-hip-flexors&quot;&gt;Strengthening the glutes and stretching the hip flexors&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#strengthening-the-abs&quot;&gt;Strengthening the abs&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#internal-shoulder-rotation&quot;&gt;Internal shoulder rotation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#flexibility&quot;&gt;Flexibility&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#strength-and-hypertrophy&quot;&gt;Strength and hypertrophy&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#pull&quot;&gt;Pull&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#push&quot;&gt;Push&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#warm-up&quot;&gt;Warm-up&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#part-1%3A-elevating-your-core-temperature.&quot;&gt;Part 1: Elevating your core temperature.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#part-2%3A-dynamic-warm-up.&quot;&gt;Part 2: Dynamic warm-up.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#part-3%3A-sport-specific-warm-up.&quot;&gt;Part 3: Sport-Specific Warm Up.&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/fitness_routine/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;This is going to be a reference page so I know
what to do and
why I&#39;m doing it.&lt;/p&gt;
&lt;p&gt;The goal is for my routine to be &lt;em&gt;zero-friction&lt;/em&gt;:
make sure I exercise every day and maintain the meta-stable habit.
Otherwise I will definitely slack off.&lt;/p&gt;
&lt;h1 id=&quot;goals&quot; tabindex=&quot;-1&quot;&gt;Goals&lt;/h1&gt;
&lt;p&gt;My priorities are to shore up my weaknesses and
then build upon my strengths.
In decreasing order of priority, therefore, my goals are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix my anterior pelvic tilt&lt;/li&gt;
&lt;li&gt;Fix my internal shoulder rotation&lt;/li&gt;
&lt;li&gt;Increase flexibility&lt;/li&gt;
&lt;li&gt;Increase strength and hypertrophy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To that end, I&#39;ll be doing the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Stretch every day with Starting Stretching (SS) routine&lt;/li&gt;
&lt;li&gt;(For internal shoulder rotation) Add doorway face pulls,
subscapularis and pec minor stretches to the SS routine&lt;/li&gt;
&lt;li&gt;(For APT) Add modified sprinter lunge to the SS routine&lt;/li&gt;
&lt;li&gt;Perform 6-day push-pull bodyweight routine&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;anterior-pelvic-tilt&quot; tabindex=&quot;-1&quot;&gt;Anterior pelvic tilt&lt;/h2&gt;
&lt;p&gt;I have mild anterior pelvic tilt (APT).
The natural angle of anterior pelvic tilt should be 3-4 degrees downward
on the waistline, mine is a bit more than that, I think.&lt;/p&gt;
&lt;p&gt;To remedy this, I&#39;ll be following Athlean-X&#39;s tips for anterior pelvic tilt
(video &lt;a href=&quot;https://www.youtube.com/watch?v=K-CrEi0ymMg&quot;&gt;here&lt;/a&gt;].&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Don’t stretch hamstrings&lt;/li&gt;
&lt;li&gt;Strengthen glutes with the &amp;quot;modified sprinter lunge&amp;quot; shown in the video
(around 4:31)&lt;/li&gt;
&lt;li&gt;Stretch lower back&lt;/li&gt;
&lt;li&gt;Stretch hip flexors (part of Starting Stretching, more later)&lt;/li&gt;
&lt;li&gt;Strengthen abs without engaging hip flexors&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;strengthening-the-glutes-and-stretching-the-hip-flexors&quot; tabindex=&quot;-1&quot;&gt;Strengthening the glutes and stretching the hip flexors&lt;/h3&gt;
&lt;h3 id=&quot;strengthening-the-abs&quot; tabindex=&quot;-1&quot;&gt;Strengthening the abs&lt;/h3&gt;
&lt;p&gt;I will be doing two main exercises that don&#39;t strengthen the hip flexors
because training the hip flexors can exacerbate APT.
&lt;a href=&quot;https://www.youtube.com/watch?v=gIhCuqtC0r0&quot;&gt;Athlean-X link&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many different ab exercises enlist the help of the hip flexors as a prime
mover. This occurs a lot in lower ab exercises but can also occur in things
as simple as the crunch. If you allow your ab training to include too many of
these you will wind up simply over strengthening the hip flexors more and
leads to a vicious cycle of more pain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&#39;ve chosen two main exercises from the video to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Side plank (with optional leg lift)&lt;/li&gt;
&lt;li&gt;Gymnast &amp;quot;captain&#39;s chair&amp;quot; back protraction&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I will be doing these ab exercises in my daily hypertrophy routine
(more on this later).&lt;/p&gt;
&lt;h2 id=&quot;internal-shoulder-rotation&quot; tabindex=&quot;-1&quot;&gt;Internal shoulder rotation&lt;/h2&gt;
&lt;p&gt;I have very bad internal shoulder rotation due to a combination of
i) benching too much without doing as much horizontal pull work and
ii) spending too much time in internal shoulder rotation (typing on keyboard)&lt;/p&gt;
&lt;p&gt;Again following
&lt;a href=&quot;https://www.youtube.com/watch?v=oLwTC-lAJws&quot;&gt;Athlean-X&#39;s recommendations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Editing a YouTube comment here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;2:50, Thoracic spine stretch: Stomach on ground, arms above head 45* angle,
rotate back while keeping chest wide open, working your way to the left and
right side&lt;/li&gt;
&lt;li&gt;5:48, &lt;em&gt;Subscapularis stretch&lt;/em&gt;: 30 seconds:
externally rotate arm as much as you can,
hook arm against doorway.
While arm is kept back way rotate your chest out in the other direction&lt;/li&gt;
&lt;li&gt;07:08, &lt;em&gt;Pec minor stretch&lt;/em&gt;:
hold shoulder back against door,
pinch shoulder blades together,
raise arm up&lt;/li&gt;
&lt;li&gt;08:26, &lt;em&gt;Band pull-aparts&lt;/em&gt;:
Externally rotate arms away with thumbs pulled back,
keeping shoulders/traps down, 20 sets of 1&lt;/li&gt;
&lt;li&gt;10:27, &lt;em&gt;Band serratus/lower trap exercise&lt;/em&gt;:
Whilst holding a resistance band,
protract your arms (without rounding the back).
Externally rotate arms out just enough to feel band tension.
Raise above the head, down, reset, repeat&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;m going to do the first three stretches every day as riders to the SS routine.&lt;/p&gt;
&lt;p&gt;I will also be doing
&lt;a href=&quot;https://www.youtube.com/watch?v=I-XpxwHqc8g&amp;amp;feature=youtu.be&amp;amp;t=260&quot;&gt;doorway face pulls&lt;/a&gt;.
Face pulls strengthen the posterior deltoids which should help pull back the shoulders.&lt;/p&gt;
&lt;h2 id=&quot;flexibility&quot; tabindex=&quot;-1&quot;&gt;Flexibility&lt;/h2&gt;
&lt;p&gt;I am very inflexible.
I can&#39;t touch my toes, my hamstrings are very tight, my shoulders are tight,
everything that can be tight is tight.
I would like to do the splits eventually.
Here&#39;s what that looks like now:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/fitness/splits_attempt.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m doing Starting Stretching every day, but skipping the hamstring stretch.
Here&#39;s an infographic:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/fitness/starting_stretching.jpg&quot; alt=&quot;Starting Stretching infographic&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;strength-and-hypertrophy&quot; tabindex=&quot;-1&quot;&gt;Strength and hypertrophy&lt;/h2&gt;
&lt;p&gt;I&#39;ll be starting with a Push-Pull bodyweight bodybuilding routine
that I found on /r/naturalbodybuilding, exercising six times a week.&lt;/p&gt;
&lt;p&gt;The PDF is in this directory and
the Reddit post is
&lt;a href=&quot;https://www.reddit.com/r/naturalbodybuilding/comments/fivvhv/the_quarantine_workout_template/.compact&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;pull&quot; tabindex=&quot;-1&quot;&gt;Pull&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Heavy vertical pull 2-5&lt;/li&gt;
&lt;li&gt;Medium intensity horizontal pull 2-5&lt;/li&gt;
&lt;li&gt;Bicep isolation 2-5&lt;/li&gt;
&lt;li&gt;Side delt isolation 2-8&lt;/li&gt;
&lt;li&gt;Heavy hamstring exercise 2-5&lt;/li&gt;
&lt;li&gt;Medium intensity hamstring exercise 1-5&lt;/li&gt;
&lt;li&gt;Abs 3&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;push&quot; tabindex=&quot;-1&quot;&gt;Push&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Heavy horizontal press 2-5&lt;/li&gt;
&lt;li&gt;Medium intensity incline press 2-5&lt;/li&gt;
&lt;li&gt;Triceps isolation 2-5&lt;/li&gt;
&lt;li&gt;Heavy quad compound 2-5&lt;/li&gt;
&lt;li&gt;Medium intensity quad compound 2-5&lt;/li&gt;
&lt;li&gt;Straight legged calf exercise 3-8&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For ab work I&#39;ll be doing the exercises I wrote in the previous section:
these are&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Side plank (with optional leg lift), and&lt;/li&gt;
&lt;li&gt;Gymnast &amp;quot;captain&#39;s chair&amp;quot; back protraction.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&#39;ll be replacing some of the exercises with dumbbell work:
for instance, I&#39;ll be using DBs for lat raises,
and could consider DB squats if pistol squats get too easy.&lt;/p&gt;
&lt;p&gt;I might also consider working in vertical presses
sometimes to replace the incline press e.g. DB shoulder press.&lt;/p&gt;
&lt;h3 id=&quot;warm-up&quot; tabindex=&quot;-1&quot;&gt;Warm-up&lt;/h3&gt;
&lt;p&gt;Pasting directly from the
&lt;a href=&quot;https://www.reddit.com/r/naturalbodybuilding/comments/fivvhv/the_quarantine_workout_template/fxs16z5/&quot;&gt;Reddit post&lt;/a&gt;
for reference:&lt;/p&gt;
&lt;p&gt;Do this before every session:&lt;/p&gt;
&lt;h4 id=&quot;part-1%3A-elevating-your-core-temperature.&quot; tabindex=&quot;-1&quot;&gt;Part 1: Elevating your core temperature.&lt;/h4&gt;
&lt;p&gt;Here you can either do 3-5 minutes of LIGHT cardio (brisk walk/bike
ride/elliptical), or super light full body exercises like the ones you can
see in this video. Since the only objective here is elevating your body
temperature, you absolutely don&#39;t want to get tired, out of breath or sore,
just stop when you feel like you&#39;re warm enough. Breaking a sweat is ok.&lt;/p&gt;
&lt;h4 id=&quot;part-2%3A-dynamic-warm-up.&quot; tabindex=&quot;-1&quot;&gt;Part 2: Dynamic warm-up.&lt;/h4&gt;
&lt;p&gt;Here you want to move explosively through the ranges of motion you&#39;re going
to be using in the workout. Follow this protocol:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;10 leg swings front to back (explosive).&lt;/li&gt;
&lt;li&gt;10 leg swings side to side (explosive).&lt;/li&gt;
&lt;li&gt;10 big arm circles forward (explosive).&lt;/li&gt;
&lt;li&gt;10 big arm circles backwards (explosive).&lt;/li&gt;
&lt;li&gt;10 cross body arm slaps (explosive).&lt;/li&gt;
&lt;li&gt;5 repetitions (per leg) of a lunge with torso rotation
(only if for you it&#39;s a light exercise and doesn&#39;t tire you).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, the regular training session starts. Then, do the following
before every exercise that&#39;s going to work a muscle group for the first time
in the session (for example if in the same session you have two exercises for
the chest, then do the following only before the first one):&lt;/p&gt;
&lt;h4 id=&quot;part-3%3A-sport-specific-warm-up.&quot; tabindex=&quot;-1&quot;&gt;Part 3: Sport-Specific Warm Up.&lt;/h4&gt;
&lt;p&gt;Do a set of 5 reps from the previous level of the exercise you&#39;re about to
do. So if you&#39;re warming up to do the horizontal press level 3, in this
instance do one set of 5 reps of the horizontal press level 2. If you&#39;re
warming up for a level 1 exercise, and its intensity can be lowered as
explained here, do the lower intensity version; and if the intensity can&#39;t be
lowered, do 5 partial reps: 2 partials from the bottom part of the movement,
and 3 partials from the top part of the movement. If you&#39;re about to do an
exercise without a specific level, use a lighter exercise that targets the
same muscle group.&lt;/p&gt;
&lt;p&gt;Rest for a few seconds and then do your working exercise for half of the
reps. So if you&#39;re warming up to do incline push-ups, and last time you got
12 reps in your first set, then in this instance do one set of incline
push-ups for 6 reps. Rest for a minute, and start your regular working sets.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;My current routine is a big departure from my earlier days
where the only thing I wanted to do was get big with as little effort as possible.
I suppose I&#39;m paying the price now with the imbalances that have occurred
as a result.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>How many solar panels would be needed to 100% solar-power Singapore?</title>
    <link href="https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/"/>
    <updated>2020-06-02T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/</id>
    <content type="html">&lt;div class=&#39;toc&#39;&gt;
&lt;nav class=&quot;table-of-contents&quot;&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#summary&quot;&gt;Summary&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#background-and-motivation&quot;&gt;Background and motivation&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#strategy&quot;&gt;Strategy&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#demand-side%3A-how-much-energy-does-singapore-demand%3F&quot;&gt;Demand-side: how much energy does Singapore demand?&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#supply-side&quot;&gt;Supply-side&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#how-much-energy-hits-the-ground%3F-global-horizontal-irradiance-(ghi)&quot;&gt;How much energy hits the ground? Global Horizontal Irradiance (GHI)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#how-much-energy-can-we-collect%3F&quot;&gt;How much energy can we collect?&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#efficiency-of-the-solar-panel&quot;&gt;Efficiency of the solar panel&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#miscellaneous-losses&quot;&gt;Miscellaneous losses&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#supply-side-graph&quot;&gt;Supply-side graph&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#putting-it-all-together&quot;&gt;Putting it all together&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#how-does-that-area-actually-look-like%3F&quot;&gt;How does that area actually look like?&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#appendix&quot;&gt;Appendix&lt;/a&gt;&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#tilt-of-the-solar-panels&quot;&gt;Tilt of the solar panels&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#transmission-losses&quot;&gt;Transmission losses&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#storage-losses%2C-batteries-needed%2C-and-how-much-area-those-batteries-would-occupy&quot;&gt;Storage losses, batteries needed, and how much area those batteries would occupy&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/nav&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Principal investigators: Michael and Celine&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;summary&quot; tabindex=&quot;-1&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;We use horizontal irradiance data, Singapore&#39;s half-hourly power demand
statistics and solar panel schematics to calculate the area of solar panels
(and battery storage) needed to meet Singapore&#39;s energy demands. We
calculate that an area of &lt;strong&gt;30,000 hectares&lt;/strong&gt; would be more than sufficient,
provided we have enough battery storage.&lt;/p&gt;
&lt;p&gt;I&#39;m certain that I&#39;ve missed something: all feedback and corrections are most welcome.&lt;/p&gt;
&lt;p&gt;Thanks very much to Michael and Celine for researching this problem with me:
whatever errors remain are mine alone.&lt;/p&gt;
&lt;h2 id=&quot;background-and-motivation&quot; tabindex=&quot;-1&quot;&gt;Background and motivation&lt;/h2&gt;
&lt;p&gt;I saw this infographic from the Straits Times talking about an
ambitious plan to build a huge solar farm and cable the energy over to Singapore.
This piqued my interest, so I went to &lt;a href=&quot;https://www.suncable.sg/&quot;&gt;the company&#39;s website&lt;/a&gt;
to learn more.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/straits_times_infographic.jpg&quot; alt=&quot;Straits Times claims that the farm will provide 1/3rd of SG&#39;s energy&quot;&gt;&lt;/p&gt;
&lt;p&gt;What I found puzzled me. The Straits Times infographic claims that the farm will
occupy 15,000 hectares and provide a third of Singapore&#39;s energy.
But the website claims that the farm will occupy 12,000 hectares and provide
a fifth of Singapore&#39;s energy.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/sun_cable_figures.jpg&quot; alt=&quot;But Sun Cable claims 1/5th&quot;&gt;&lt;/p&gt;
&lt;p&gt;So which is it? 1/5th or 1/3rd?
No matter how you slice it the numbers don&#39;t make sense.
So I decided to take matters into my own hands and calculate it myself.
I want to find out:
what area of solar panels would we need to provide 100% of Singapore&#39;s energy?&lt;/p&gt;
&lt;h2 id=&quot;strategy&quot; tabindex=&quot;-1&quot;&gt;Strategy&lt;/h2&gt;
&lt;p&gt;We&#39;ll tackle this question in two main parts: on the supply and on the demand side.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How much energy does Singapore demand?&lt;/li&gt;
&lt;li&gt;How much energy can be produced per unit area?
&lt;ul&gt;
&lt;li&gt;How much energy falls onto the ground per unit area?&lt;/li&gt;
&lt;li&gt;How much of that energy can we soak up per unit area?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;demand-side%3A-how-much-energy-does-singapore-demand%3F&quot; tabindex=&quot;-1&quot;&gt;Demand-side: how much energy does Singapore demand?&lt;/h2&gt;
&lt;p&gt;How much power does Singapore demand? The answer depends of course on &amp;quot;over what period&amp;quot;?
Because solar power varies greatly throughout the day,
we should take the highest-resolution snapshot of the data.&lt;/p&gt;
&lt;p&gt;The best I could get was half-hourly power demand figures obtained from
Singapore&#39;s &lt;a href=&quot;https://data.gov.sg/dataset/half-hourly-system-demand&quot;&gt;Data.gov.sg&lt;/a&gt;.
The dataset starts in 2012 and ends in 2017 but I extrapolated it to 2020
(by taking the geometric mean).&lt;/p&gt;
&lt;div id=&quot;observablehq-744a5081&quot;&gt;
&lt;p&gt;The chart below plots how power demand varies throughout the day in Watts.
Pick any date from 22 Feb 2020 to 20 June 2020 to see how
power demand varied during that day.&lt;/p&gt;
  &lt;!-- include first chart --&gt;
  &lt;div class=&quot;observablehq-date_picker_1&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;observablehq-demand_chart&quot;&gt;&lt;/div&gt;
&lt;p&gt;Surprisingly, power usage tends to dip during working hours and
go up during the wee hours of the night. I&#39;m not sure why this is the case:
maybe I made a mistake?&lt;/p&gt;
&lt;h2 id=&quot;supply-side&quot; tabindex=&quot;-1&quot;&gt;Supply-side&lt;/h2&gt;
&lt;p&gt;How much power can we collect from the sun?
If we know the amount of sunlight that shines on a unit area,
and we know the efficiency of the solar panels,
then the total power collected is&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;f&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;TotalPower = Power/m^2 * Area * Efficiency
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;er&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1076em;&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;cy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And as long as the total power produced
exceeds the power demanded by Singapore, we&#39;re in the green!&lt;/p&gt;
&lt;p&gt;It&#39;s not that easy, of course.
The amount of sunlight incident upon a unit area depends on
things like weather conditions and the time of day.
And efficiency depends on ambient temperature and the angle of solar panels,
among other things. We&#39;ll have to make several simplifying assumptions to proceed.&lt;/p&gt;
&lt;h3 id=&quot;how-much-energy-hits-the-ground%3F-global-horizontal-irradiance-(ghi)&quot; tabindex=&quot;-1&quot;&gt;How much energy hits the ground? Global Horizontal Irradiance (GHI)&lt;/h3&gt;
&lt;p&gt;From Wikipedia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Solar irradiance is the power per unit area (watt per square metre, W/m2),
received from the Sun in the form of electromagnetic radiation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Irradiance on the Earth&#39;s surface depends on the tilt of the measuring surface,
which we&#39;ll account for later. At the moment, we&#39;ll use a simplifying measure:
that of &lt;em&gt;horizontal irradiance&lt;/em&gt; (GHI), which measures the power
received by a horizontal surface per unit area.&lt;/p&gt;
&lt;p&gt;We need to get time-series GHI data because solar irradiance changes
dramatically throughout the day (the sun rises and sets, after all).
I got the GHI data from the &lt;a href=&quot;http://dkasolarcentre.com.au/download?location=nt-solar-resource&quot;&gt;DKA Solar Centre&lt;/a&gt;.
The DKA Solar Center describes the data in the following way:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A series of four Class A meteorological stations across the Northern
Territory collect high resolution solar and climate resource data from
locations in Darwin, Katherine, Tennant Creek and Alice Springs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I used the data from the Darwin meteorological station, but on reflection
I should&#39;ve used Tennant Creek because that&#39;s where the site would have been built.&lt;/p&gt;
&lt;h3 id=&quot;how-much-energy-can-we-collect%3F&quot; tabindex=&quot;-1&quot;&gt;How much energy can we collect?&lt;/h3&gt;
&lt;p&gt;Knowing how much energy hits the surface is one thing, but what we &lt;em&gt;really&lt;/em&gt;
care about is how much energy we can collect. This is the most finicky bit
of the calculation, because there are many many different factors that affect efficiency.
To make the problem tractable we group the losses into three,
in decreasing order of importance:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &amp;quot;base&amp;quot; efficiency of the solar panel&lt;/li&gt;
&lt;li&gt;The angle of the solar panels (in appendix)&lt;/li&gt;
&lt;li&gt;All other losses (e.g. dirt/soiling/conversion/temperature/whatever)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Feel free to skip any of these sections as they are quite finicky
and not that important for the big picture.&lt;/p&gt;
&lt;h4 id=&quot;efficiency-of-the-solar-panel&quot; tabindex=&quot;-1&quot;&gt;Efficiency of the solar panel&lt;/h4&gt;
&lt;p&gt;I calculated the &amp;quot;base&amp;quot; efficiency of the solar panels to be 16.4%.
That is, for every 1kWh of energy that hits the ground, the solar panel
would produce 0.16 kWh. I got this number as follows:&lt;/p&gt;
&lt;p&gt;Referencing the spec sheets given by &lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/&quot;&gt;Sun Cable&#39;s solar panel supplier&lt;/a&gt;,
each solar panel module has a width of 5550mm and a length of 37330mm.
The area is therefore 207.8 sq m.&lt;/p&gt;
&lt;p&gt;How much power does it generate? According to the spec sheet,
the module produces 34.2 kWp. But what sort of unit is this?
It turns out that kWp stands for &amp;quot;kilowatt-peaks&amp;quot;, or nominal power,
and we&#39;ll need this value to calculate the efficiency.&lt;/p&gt;
&lt;p&gt;From Wikipedia:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The nominal power of PV devices is measured under Standard Test Conditions...
Specifically, the light intensity is 1000 W/m2, with a spectrum similar to
sunlight hitting the earth&#39;s surface at latitude 35°N in the summer (airmass
1.5), the temperature of the cells being 25 °C.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And so we can get the efficiency of the solar module by dividing the kWp
by the area of the solar module.
This module produces 34.2 kWp at peak with 207.8 sqm which means
that the efficiency is 16.4%.
That is, if irradiance were &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1kW/m^2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
you&#39;d get &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0.16&lt;/mn&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mi&gt;W&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;m&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0.16kW/m^2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.0641em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.16&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8141em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; from the solar panel.&lt;/p&gt;
&lt;p&gt;What does this mean? It means that for every m^2 of solar panels we install,
we would get &lt;strong&gt;0.16kW&lt;/strong&gt; of power per &lt;strong&gt;1kW&lt;/strong&gt; of horizontal irradiance.
This is exactly what we need: just multiply the horizontal irradiance data
by 0.16. Of course, there are still other power losses, which we&#39;ll now consider.&lt;/p&gt;
&lt;h4 id=&quot;miscellaneous-losses&quot; tabindex=&quot;-1&quot;&gt;Miscellaneous losses&lt;/h4&gt;
&lt;p&gt;There are a ton of other miscellaneous power losses.
The &lt;a href=&quot;https://solargis.com/maps-and-gis-data/tech-specs&quot;&gt;SolarGIS website&lt;/a&gt;
lists &amp;quot;solar radiation, air temperature, and terrain&amp;quot;
as factors in calculating energy output, as well as &amp;quot;losses due to dirt and soiling&amp;quot;
and the &amp;quot;cumulative effect of other conversion losses&amp;quot;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the simulation, losses due to dirt and soiling was estimated to be
3.5%. The cumulative effect of other conversion losses (inter-row shading,
mismatch, inverters, cables, transformer, etc.) is assumed to be 7.5%. The
power plant availability is considered to be 100%.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The SolarGIS website gives &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;3.5&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;7.5&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;11&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;3.5 + 7.5 = 11%&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3.5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;7.5&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;11&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, but here we&#39;ll be conservative.
We&#39;ll take an additional fudge factor and say that 15% of energy is lost.
And thus the ratio of power produced (PVOUT) to incident power (GHI) is&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;V&lt;/mi&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;0.164&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;0.85.&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PVOUT = GHI * 0.164 * 0.85 .
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;V&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;O&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.164&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.85.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We&#39;ll use this value henceforth.&lt;/p&gt;
&lt;h3 id=&quot;supply-side-graph&quot; tabindex=&quot;-1&quot;&gt;Supply-side graph&lt;/h3&gt;
&lt;p&gt;In the previous section we calculated that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;13.9&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;%&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;13.9\%&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;13.9%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; (0.164 * 0.85) of energy
from the sun would be converted into usable energy.
The following graph displays how GHI and PVOUT vary throughout the day
per unit area.&lt;/p&gt;
&lt;!-- graph here --&gt;
  &lt;div class=&quot;observablehq-date_picker_2&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;observablehq-supply_chart&quot;&gt;&lt;/div&gt;
&lt;p&gt;Again, you can use the date scrubber to view all the days in the dataset.
Check out 9 March 2020: it seems to have been a particularly overcast day,&lt;/p&gt;
&lt;h2 id=&quot;putting-it-all-together&quot; tabindex=&quot;-1&quot;&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;We&#39;ve built the demand and supply sides,
and all we need to do now is to put them together!
The graph below superposes the demand and supply graphs.&lt;/p&gt;
&lt;p&gt;The supply graph starts off tiny, but grows as we increase the area of solar panels.
Move the slider to increase the area of solar panels and watch the supply graph grow.
Assuming we have enough battery storage,
we have enough solar panels to fulfill Singapore&#39;s peak power demands
when the area under the red curve (total solar energy that is collected for a given area)
exceeds the area under the blue curve (total power demand of Singapore).&lt;/p&gt;
&lt;p&gt;I&#39;ve calculated the difference in these two areas (total net supply) in MW.
Using the slider, increase the area of solar panels
until the total net supply becomes positive.&lt;/p&gt;
  &lt;!-- graph here --&gt;
  &lt;div class=&quot;observablehq-total_net_supply&quot;&gt;&lt;/div&gt; MW
  &lt;div class=&quot;observablehq-area_needed_hectares&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;observablehq-area_input_1&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;observablehq-duck_chart&quot;&gt;&lt;/div&gt;
&lt;p&gt;Depending on the day&#39;s weather conditions, the area of solar panels needed
to generate more power than demand also varies. Try using the date picker again.&lt;/p&gt;
&lt;p&gt;The graph belows shows the minimum area of solar panels needed to meet daily demand.
Increase the area of solar panels (red line) to see how much area we would need
to meet demand on most days.&lt;/p&gt;
  &lt;!-- graph here --&gt;
  &lt;div class=&quot;observablehq-area_input_2&quot;&gt;&lt;/div&gt;
  &lt;div class=&quot;observablehq-area_each_day_chart&quot;&gt;&lt;/div&gt;
&lt;p&gt;We can see that at 40,000 square hectares we would have a huge surplus on most days
and would only fail to meet demand for three days in the entire period.
With battery storage one could bank up the surplus energy and draw it down
during cloudy days.&lt;/p&gt;
&lt;h3 id=&quot;how-does-that-area-actually-look-like%3F&quot; tabindex=&quot;-1&quot;&gt;How does that area actually look like?&lt;/h3&gt;
&lt;p&gt;In the image below, I&#39;ve marked in red the square area of solar panels
needed to fully power Singapore (~30,000 hectares). This is what that looks like
(map from Google Maps):&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/australia_area_crop_2.png&quot; alt=&quot;Zoomed in version of Australia&quot;&gt;&lt;/p&gt;
&lt;p&gt;A length of 100 pixels corresponds to a 500km distance.
1 pixel therefore represents 5km, and a 1x1 pixel square represents an area of 25 sq km.
And 30,000 hectares is 300 sq km, which is a 3x4 rectangle---which is what
I&#39;ve drawn on the map.&lt;/p&gt;
&lt;p&gt;Zooming out to the entirety of Australia:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/australia_area_crop.png&quot; alt=&quot;Full size image of Australia&quot;&gt;&lt;/p&gt;
&lt;p&gt;Australia is huge: all the solar panels would occupy an area only one-tenth
the size of Darwin (3600 sq km).&lt;/p&gt;
&lt;p&gt;The area of Singapore is (very generously) 900 sq km, so this corresponds to about a 6x6 pixel square.
Placing the solar panels in Singapore, they&#39;d occupy more than one-third of
our land area (so not a great idea).
Here I&#39;ve zoomed out and marked the (approximate) square area of Singapore:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/australia_area_full_size.png&quot; alt=&quot;Australia in Singapore&quot;&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Building a solar farm to power all of Singapore is actually not
&lt;em&gt;that&lt;/em&gt; ambitious. The largest extant solar farm as of 2020 is the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Pavagada_Solar_Park&quot;&gt;Pagavada Solar Park&lt;/a&gt;
in India (2050 MW), which covers an area of 53 sq km. Our hypothetical solar farm
is six times that---which sounds big---but India&#39;s building these solar parks
&lt;a href=&quot;https://en.wikipedia.org/wiki/Ultra_Mega_Solar_Power_Projects&quot;&gt;like nobody&#39;s business&lt;/a&gt;.
The &lt;a href=&quot;https://en.wikipedia.org/wiki/Bhadla_Solar_Park&quot;&gt;Bhadla Solar Park&lt;/a&gt;
(2245 MW) is 45 sq km, and the upcoming
&lt;a href=&quot;https://www.power-technology.com/projects/dholera-solar-park-gujarat/&quot;&gt;Dholera Solar Park&lt;/a&gt;
is a whopping 5000MW (which will be ~ 100 sq km).
The solar park proposed by Sun Cable is only a bit larger than Dholera Solar Park,
and the solar park that would meet Singapore&#39;s energy demands is only two or
three times the size: well within the realms of possibility.&lt;/p&gt;
&lt;p&gt;Future work should calculate the amount of battery storage needed
to store enough surplus so as to handle bouts of inclement weather.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;appendix&quot; tabindex=&quot;-1&quot;&gt;Appendix&lt;/h2&gt;
&lt;p&gt;Things that I didn&#39;t deem important enough to put into the main text&lt;/p&gt;
&lt;h3 id=&quot;tilt-of-the-solar-panels&quot; tabindex=&quot;-1&quot;&gt;Tilt of the solar panels&lt;/h3&gt;
&lt;p&gt;The tilt of the solar panel affects power generation.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/solar_exploration/tilted_array.gif&quot; alt=&quot;How tilt affects incident irradiance&quot;&gt;&lt;/p&gt;
&lt;p&gt;It turns out that &amp;quot;for a fixed tilt angle, the maximum power over the course of a year is
obtained when the tilt angle is equal to the latitude of the location&amp;quot;
&lt;a href=&quot;https://www.pveducation.org/pvcdrom/properties-of-sunlight/solar-radiation-on-a-tilted-surface&quot;&gt;(source: PVeducation.org)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The spec sheet says that the angle of these solar panels is 20 degrees
and the latitude of Tennant Creek is 19 degrees,
so we&#39;re basically as close to optimal as we can get.&lt;/p&gt;
&lt;h3 id=&quot;transmission-losses&quot; tabindex=&quot;-1&quot;&gt;Transmission losses&lt;/h3&gt;
&lt;p&gt;Wikipedia Super Grid Article says that the latest generation of High-voltage direct current power lines can transmit energy with losses of only 1.6% per 1000km:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sun Cable is using a High Voltage Direct Current Lines, which have quoted transmission losses as less than 3% per 1,000km. (Source: Wikipedia)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The distance between Singapore and Darwin, Australia is around 4,000km.&lt;/p&gt;
&lt;p&gt;Thus, we’d get around &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;4.0&lt;/mn&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;%&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;12.0&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;%&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;4.0*3\% = 12.0\%&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3%&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8056em;vertical-align:-0.0556em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;12.0%&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; losses - one-eighth of the energy produced would be lost on transport.&lt;/p&gt;
&lt;h3 id=&quot;storage-losses%2C-batteries-needed%2C-and-how-much-area-those-batteries-would-occupy&quot; tabindex=&quot;-1&quot;&gt;Storage losses, batteries needed, and how much area those batteries would occupy&lt;/h3&gt;
&lt;p&gt;TODO: not that much, batteries are pretty dense. Wouldn&#39;t add more than 10%
of the area of the solar panels.&lt;/p&gt;
&lt;p&gt;From random Googling, battery storage seems to be 85% efficient.&lt;/p&gt;
&lt;script type=&quot;module&quot;&gt;
  import {Runtime, Inspector} from &quot;https://cdn.jsdelivr.net/npm/@observablehq/runtime@4/dist/runtime.js&quot;;
  import define from &quot;https://api.observablehq.com/@lieuzhenghong/solar-power-observable-take-2.js?v=3&quot;;
  (new Runtime).module(define, name =&gt; {
    if (name === &quot;date_picker_1&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-date_picker_1&quot;)();
    if (name === &quot;demand_chart&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-demand_chart&quot;)();
    if (name === &quot;date_picker_2&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-date_picker_2&quot;)();
    if (name === &quot;supply_chart&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-supply_chart&quot;)();
    if (name === &quot;total_net_supply&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-total_net_supply&quot;)();
    if (name === &quot;area_needed_hectares&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-area_needed_hectares&quot;)();
    if (name === &quot;area_input_1&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-area_input_1&quot;)();
    if (name === &quot;duck_chart&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-duck_chart&quot;)();
    if (name === &quot;area_input_2&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-area_input_2&quot;)();
    if (name === &quot;area_each_day_chart&quot;) return Inspector.into(&quot;#observablehq-744a5081 .observablehq-area_each_day_chart&quot;)();
  });
&lt;/script&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.pveducation.org/pvcdrom/properties-of-sunlight/solar-radiation-on-a-tilted-surface&quot;&gt;source&lt;/a&gt; &lt;a href=&quot;https://lieuzhenghong.com/explorations/solar_exploration/solar-panels-sg/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Theopol Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_theopol/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_theopol/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A15005W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>QE Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_qe/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_qe/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A12747W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>PolSoc Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_polsoc/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_polsoc/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A12737W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Micro Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_micro/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_micro/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A12749W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Macro Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_macro/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_macro/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A12748W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Game Theory Final Exams</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_gt/"/>
    <updated>2020-06-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_gt/</id>
    <content type="html">&lt;p&gt;You can find the PDF &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_A12761W1.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Politics Thesis</title>
    <link href="https://lieuzhenghong.com/ppe_final_exams_thesis/"/>
    <updated>2020-04-23T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_final_exams_thesis/</id>
    <content type="html">&lt;p&gt;tl;dr summary &lt;a href=&quot;https://lieuzhenghong.com/thesis_tldr/&quot;&gt;here&lt;/a&gt;
Thesis on GitHub &lt;a href=&quot;https://raw.githubusercontent.com/lieuzhenghong/human-compactness/d3c0072a117acf1fbb1a0f73f4b48569a08622d6/40_docs/1026376_Thesis%20in%20Politics.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1023538_Thesis_Gibbs_Prize.pdf&quot;&gt;Gibbs Prize for best thesis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Very proud of this work. I spent almost an entire year, and hundreds of hours on this. It couldn&#39;t have been done without the time and effort Bassel, Filip, Martin, Tak Huen, Sergi, Andy, Jonathan Rodden, Nick Eubank, and Prof. Stephanopoulos lavished on me.&lt;/p&gt;
&lt;p&gt;Comments from markers &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_Markers_Comments.pdf&quot;&gt;here&lt;/a&gt; &lt;a href=&quot;https://files.lieu.gg/docs/ppe_work/1026376_Politics_Thesis_Marker_2_Comments.pdf&quot;&gt;and here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Comments from Stephanopoulos (via email):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hi  Zhenghong,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Just a quick note that I read, and was very impressed by, your thesis. I think it&#39;s a remarkable piece of work: one of the first pieces to explore the tradeoffs between different redistricting goals using simulations. If I can assist in any way down the road, please let me know.&lt;/p&gt;
&lt;p&gt;NS&lt;/p&gt;
&lt;p&gt;On Thu, May 7, 2020 at 3:56 PM Nicholas Stephanopoulos &lt;a href=&quot;mailto:nicholas.stephanopoulos@gmail.com&quot;&gt;nicholas.stephanopoulos@gmail.com&lt;/a&gt; wrote:&lt;/p&gt;
&lt;p&gt;Hi Zhenghong,&lt;/p&gt;
&lt;p&gt;Nice to hear from you again! I&#39;m delighted that my spatial diversity work was useful, and I&#39;m looking forward to reading your thesis. I love the idea of looking at how different redistricting criteria are related to one another in hypothetical maps. Hope you&#39;re managing okay in this crazy time.&lt;/p&gt;
&lt;p&gt;NS&lt;/p&gt;
&lt;p&gt;On Thu, May 7, 2020 at 10:41 AM Lieu Zheng Hong &lt;a href=&quot;mailto:lieuzhenghong@gmail.com&quot;&gt;lieuzhenghong@gmail.com&lt;/a&gt; wrote:&lt;/p&gt;
&lt;p&gt;Dear Prof Stephanopoulos,&lt;/p&gt;
&lt;p&gt;I hope you and your loved ones are well during these unprecedented times.&lt;/p&gt;
&lt;p&gt;I have recently submitted my undergraduate thesis. In it I examine whether or not there is a trade-off between compactness and communities of interest when drawing districts, both of which are mandated by legislatures in the U.S. I operationalise communities of interest with your measure of spatial diversity. I draw hundreds of thousands of counterfactual plans, meant to represent the set of plans an unbiased districting commission would conceivably draw.&lt;/p&gt;
&lt;p&gt;I find the following results:&lt;/p&gt;
&lt;p&gt;1. Districts&#39; spatial diversity varies a lot between states (your finding), but not so much within states. Each state occupies only a narrow band in the range of possible spatial diversity scores, no matter how we draw the districts.
2. Small urban districts are usually more spatially diverse.
3. Whether or not there is a trade-off between compactness and spatial diversity depends on the compactness measure we choose (Polsby-Popper, Convex Hull, Reock, etc..). Some compactness measures trade-off spatial diversity with compactness, while others synergise well with compactness.&lt;/p&gt;
&lt;p&gt;I&#39;ve attached it here in case you wanted to take a look. Comments are most welcomed, of course.&lt;/p&gt;
&lt;p&gt;Without exaggeration, I couldn&#39;t have done it without your measure and your data. The spatial diversity measure forms the bedrock of all analyses---without the measure, there would be no thesis. So please accept my sincere gratitude!&lt;/p&gt;
&lt;p&gt;Thanks very much and take care,
Zhenghong Lieu&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building a deep learning pipeline + model with Keras and PlaidML</title>
    <link href="https://lieuzhenghong.com/2019/09/17/"/>
    <updated>2019-09-17T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/09/17/</id>
    <content type="html">&lt;p&gt;I built and iterated on a deep learning model that replicates the outputs of
an existing rule-based system while having 100x faster inference. As a
prerequisite to iterating on the model I also built a deep learning pipeline
that did:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Data reading and cleaning&lt;/li&gt;
&lt;li&gt;Feature extraction and selection&lt;/li&gt;
&lt;li&gt;Data normalisation&lt;/li&gt;
&lt;li&gt;Model checkpointing and saving&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I iterated over 6 major model configurations (training ~50 models overall) and
got the model RMSE to fall from 0.23 (simple RNN) to 0.128. This significantly
improves upon a baseline model (RMSE = 0.22) but there is still room for improvement.&lt;/p&gt;
&lt;p&gt;The pipeline I built will speed up future iteration significantly. I will
continue the project with the Oxford Strategy Group (Digital), where I might
lead the team of consultants.&lt;/p&gt;
&lt;p&gt;(Summer 2019 internship with Inzura)&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;motivation&quot; tabindex=&quot;-1&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Inzura AI has a proprietary algorithm called the &amp;quot;Driver Profiler&amp;quot;, which is a
complex rule-based system that measures how drivers drive. It derives
quantities like acceleration and velocity from GPS data. It looks up driver
position in a road network database to check for speeding (this road network
database allowed me to do data analysis on average speeds in &lt;a href=&quot;https://lieuzhenghong.com/2019/09/12/big-data-analysis-on-a-distributed-raspi-cluster/&quot;&gt;another project I
did for
Inzura&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;From all this data it identifies speeding/braking/accelerating/turning events
and scores them. For instance a hard acceleration would be scored poorly.&lt;/p&gt;
&lt;p&gt;Finally, it aggregates all the events to give a &amp;quot;trip score&amp;quot;, which is how
safely the driver drove on the trip.&lt;/p&gt;
&lt;p&gt;This rule-based system works well but has two limitations. First, the database
lookups take a lot of time (latency) and necessitate an always-online device.&lt;/p&gt;
&lt;p&gt;Second, most of the code for the driver profiler is written in Python. Richard
Jelbert, the CEO and co-founder of Inzura, wanted to deploy a version of the
driver profiler on dashcams. However, dashcams are embedded systems that run
C/C++.&lt;/p&gt;
&lt;p&gt;A deep learning model solves both of these problems in one fell swoop. Once
trained, it can run inference completely offline, and there are libraries that
compile Keras models to C++. Additionally, offline inference means &lt;em&gt;real-time
inference&lt;/em&gt;: the model could provide real-time feedback to a driver on his
performance, which is something that was impossible before.&lt;/p&gt;
&lt;h2 id=&quot;feature-selection-%2F-extraction&quot; tabindex=&quot;-1&quot;&gt;Feature selection / extraction&lt;/h2&gt;
&lt;p&gt;There was a lot of data in every second of the trip, but I restricted myself to
values that could be calculated relatively quickly and did not require any
database lookups. That meant only things like velocity, acceleration, turn
radius, not road type or speed limit.&lt;/p&gt;
&lt;p&gt;I eventually settled on four features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Absolute velocity&lt;/li&gt;
&lt;li&gt;Tangential acceleration&lt;/li&gt;
&lt;li&gt;Radial acceleration&lt;/li&gt;
&lt;li&gt;Angle&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;data-cleaning&quot; tabindex=&quot;-1&quot;&gt;Data cleaning&lt;/h2&gt;
&lt;p&gt;There were anomalies in the data: whitespace issues, null values, wrong values,
etc. I had to write code that fixed all of that, which was trivial but tedious. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/09/17/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;keras-generator&quot; tabindex=&quot;-1&quot;&gt;Keras generator&lt;/h2&gt;
&lt;p&gt;I wrote a Python generator to read the training data into my Keras model.&lt;/p&gt;
&lt;p&gt;A
&lt;a href=&quot;https://stackoverflow.com/questions/1756096/understanding-generators-in-python&quot;&gt;generator&lt;/a&gt;
is a &amp;quot;function which returns an object on which you can call next, such that
for every call it returns some value, until it raises a &lt;code&gt;StopIteration&lt;/code&gt;
exception, signaling that all values have been generated. Such an object is
called an iterator.&amp;quot;&lt;/p&gt;
&lt;p&gt;The big benefit of a generator is that they deal with data one piece at a time,
and so we don&#39;t have to put the whole dataset into memory. With a small number
of trips this isn&#39;t a problem---50,000 trips may only take up ~2GB in
memory---but will be an issue in the future.&lt;/p&gt;
&lt;p&gt;One hiccup: A generator must be infinite in order to work with Keras. That is,
when it reaches the end of the training data is must loop back again to the
start. This took some effort to code (I discovered this &lt;a href=&quot;https://stanford.edu/~shervine/blog/keras-how-to-generate-data-on-the-fly#&quot;&gt;very helpful
link&lt;/a&gt;
too late) but will be very helpful when we start training with millions of
trips.&lt;/p&gt;
&lt;p&gt;[TODO] code here&lt;/p&gt;
&lt;h2 id=&quot;normalisation&quot; tabindex=&quot;-1&quot;&gt;Normalisation&lt;/h2&gt;
&lt;p&gt;[TODO] code here&lt;/p&gt;
&lt;p&gt;I wrote some simple code to calculate the mean and variance of each feature. I
fed the mean and variances into the Keras generator in order to normalise each
feature before it was used to train the model.&lt;/p&gt;
&lt;p&gt;This was actually quite a slow process: it took about 30 minutes to run. (This
is to be expected as there are ~340 million numbers to add). This is a prime
candidate for parallelisation with the &lt;a href=&quot;https://lieuzhenghong.com/2019/09/17/2019/09/12/big-data-analysis-on-a-distributed-raspi-cluster.html&quot;&gt;Raspberry Pi 4 cluster
computer&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;model-checkpointing&quot; tabindex=&quot;-1&quot;&gt;Model checkpointing&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://machinelearningmastery.com/check-point-deep-learning-models-keras/&quot;&gt;Checkpointing my
model&lt;/a&gt;
helped to save my progress by constantly saving intermediate models. What you
do is you train on the training set and only save a model when the validation
loss is lower than the best validation loss so far. That means that one can
save the best-performing model without worrying about overfitting.&lt;/p&gt;
&lt;p&gt;But of course this meant that my initial train/test split would not work. I had
to divide it into train/validation/test with a 40000/5000/5000 split.&lt;/p&gt;
&lt;p&gt;Here&#39;s what checkpointing looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Epoch 00033: val_loss improved from 0.14147 to 0.14128, saving model to cnn_6.7-33-0.1413.hdf5
Epoch 34/50
200/200 [==============================] - 465s 2s/step - loss: 0.1418 - val_loss: 0.1359

Epoch 00034: val_loss improved from 0.14128 to 0.13595, saving model to cnn_6.7-34-0.1359.hdf5
Epoch 35/50
200/200 [==============================] - 440s 2s/step - loss: 0.1391 - val_loss: 0.1395
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;iteration&quot; tabindex=&quot;-1&quot;&gt;Iteration&lt;/h2&gt;
&lt;p&gt;I started off with 10,000 trips. Each trip has length anywhere between
180-10000+ seconds. I extracted the four features at every time step. Null
values were taken to be 0.&lt;/p&gt;
&lt;p&gt;The ground truth is &lt;em&gt;six&lt;/em&gt; subscores that range from 0 to 1: my models try to
minimise the root-mean-squared-error (RMSE) between its predicted subscores and
the actual subscores.&lt;/p&gt;
&lt;h3 id=&quot;mk-i%3A-simple-rnn&quot; tabindex=&quot;-1&quot;&gt;Mk I: Simple RNN&lt;/h3&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SimpleRNN&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;input_shape&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Returns a 6x1 vector: predicting 6 different scores&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;optimizer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;adam&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;loss&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;root_mean_squared_error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Train and test loss 0.23. I had to abandon the RNN because the training was too
slow. It took 40 minutes to train one epoch of 10,000 trips. This is because
each trip had a different length and so I couldn&#39;t increase the batch size. We
could have padded with 0s, but at the time I didn&#39;t want to, and decided to
move to CNNs instead.&lt;/p&gt;
&lt;p&gt;I thought a CNN architecture might work here because I knew the rule-based
system was detecting &amp;quot;events&amp;quot;.&lt;/p&gt;
&lt;h3 id=&quot;mk-ii%3A-cnn-with-linear-activation&quot; tabindex=&quot;-1&quot;&gt;Mk II: CNN with linear activation&lt;/h3&gt;
&lt;p&gt;Train and test loss 0.22---not much difference from the RNN model, but by
introducing padding I was able to increase the batch size and thus reduce
training time by 10x, to 3-4 minutes per epoch.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 input_shape&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;optimizer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;adam&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;loss&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;root_mean_squared_error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mk-iii%3A-cnn-with-relu&quot; tabindex=&quot;-1&quot;&gt;Mk III: CNN with RELU&lt;/h3&gt;
&lt;p&gt;Changing the convolutional layers to use RELU rather than linear activation
functions made a big difference (thanks Jon Chuang), reducing the loss from
0.23 to 0.20 --- just scraping a win against the naive prediction. (Mk III).
Furthermore, it seems like I would get more gains from training with more
epochs.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;model &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Sequential&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 input_shape&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pool_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filters&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; kernel_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; strides&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
				 padding&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;same&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; activation&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;relu&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Flatten&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;optimizer&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;adam&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;loss&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;root_mean_squared_error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;mk-iv%3A-cnn-with-many-more-filters-and-dropout&quot; tabindex=&quot;-1&quot;&gt;Mk IV: CNN with many more filters and dropout&lt;/h3&gt;
&lt;p&gt;(Henceforth, I&#39;ll be omitting the code because all CNNs look the same, I was
just tweaking the parameter size and adding more layers)&lt;/p&gt;
&lt;p&gt;I then moved in a different direction --- instead of going deeper (adding more
layers), I went wide (adding more filters). This was Mk. IV with 4 CNN layers
and 100/160 filters. Sadly, the model didn’t perform that well. But I learned
two things from this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Training speed was not affected! In other words, adding more filters gives
you more power “for free” --- at the cost of memory.&lt;/li&gt;
&lt;li&gt;Wide filters do not overfit --- in other words, go hog wild with adding
larger layers.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;mk-v%3A-cnn-with-batch-normalisation&quot; tabindex=&quot;-1&quot;&gt;Mk V: CNN with batch normalisation&lt;/h3&gt;
&lt;p&gt;Emboldened by this, I decided to build Mk. V: exactly like Mk III, but
increasing the size of the convolutional layers.&lt;/p&gt;
&lt;p&gt;I trained 7 more models, trying a combination of different techniques:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5.1 add dropout layer --- training loss 0.2044, test loss 0.2050&lt;/li&gt;
&lt;li&gt;5.2 change max pool layers to have size =2&lt;/li&gt;
&lt;li&gt;5.3 change stride size = 1: training and test loss 0.20&lt;/li&gt;
&lt;li&gt;5.4 append another Conv1D layer at the end with stride size = 2, training
loss 0.2042, test loss also 0.204&lt;/li&gt;
&lt;li&gt;5.5 remove pooling layers : almost bricks the computer, huge-ass dense layer
(2.6 million parameters): training loss 0.1964, test loss 0.2146&lt;/li&gt;
&lt;li&gt;5.6 add back the pooling layers: training loss 0.1977, test loss 0.200&lt;/li&gt;
&lt;li&gt;5.7 add batch norm in between Conv1D layers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I knew that all of these models were underfitting as they were not doing much
better than the benchmark. So I decided to use MORE layers.&lt;/p&gt;
&lt;h3 id=&quot;mk-vi%3A-cnn-with-more-layers&quot; tabindex=&quot;-1&quot;&gt;Mk VI: CNN with MORE layers&lt;/h3&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;_________________________________________________________________
Layer &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 Output Shape              Param &lt;span class=&quot;token comment&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
conv1d_1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;2100&lt;/span&gt;
_________________________________________________________________
conv1d_2 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
max_pooling1d_1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
conv1d_3 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
conv1d_4 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
max_pooling1d_2 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1250&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
conv1d_5 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1250&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
conv1d_6 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1250&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;         &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
max_pooling1d_3 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
conv1d_7 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
conv1d_8 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;625&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
max_pooling1d_4 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;312&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
conv1d_9 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;312&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
conv1d_10 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;312&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;50100&lt;/span&gt;
_________________________________________________________________
max_pooling1d_5 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MaxPooling1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;156&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
conv1d_11 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;156&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;token number&quot;&gt;7515&lt;/span&gt;
_________________________________________________________________
conv1d_12 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Conv1D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;           &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;1140&lt;/span&gt;
_________________________________________________________________
dropout_1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dropout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;            &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
flatten_1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Flatten&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;          &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1170&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
_________________________________________________________________
dense_1 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                &lt;span class=&quot;token number&quot;&gt;74944&lt;/span&gt;
_________________________________________________________________
dense_2 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Dense&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                 &lt;span class=&quot;token number&quot;&gt;390&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Mk 6.1: I removed batch normalisation and added more layers for a total of 12
convolution layers. This gave me the lowest test loss so far. &lt;strong&gt;Train/test loss 0.1928/0.1857.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reason why the test loss is smaller than the training loss is because of
dropout. From &lt;a href=&quot;https://stats.stackexchange.com/a/205831/229360&quot;&gt;a StackOverflow post&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One possibility: If you are using dropout regularization layer in
your network, it is reasonable that the validation error is smaller than
training error. Because usually dropout is activated when training but
deactivated when evaluating on the validation set. You get a more smooth
(usually means better) function in the latter case.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.2: I trained for more epochs (40 rather than 20) and got a train/test
loss of &lt;strong&gt;0.1698/0.1820&lt;/strong&gt;. I realised that the model was beginning to overfit
and so I got 40,000 more trips.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.3: I trained for 50 epochs on 50,000 trips. Training time per epoch took
~20 minutes, which meant the entire training took &lt;strong&gt;15 hours&lt;/strong&gt;. I got a
training loss of &lt;strong&gt;0.163&lt;/strong&gt; and a test loss of &lt;strong&gt;0.1599&lt;/strong&gt;. This is good news
--- adding more data stopped the model from overfitting.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.4: forgot to write what I did&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.5: Instead of batch normalisation, I normalised &lt;em&gt;all&lt;/em&gt; the inputs and
trained the same model again. This really helped! The neural network was able
to achieve the lowest-ever training and test loss. &lt;strong&gt;Training loss: 0.1475.
Test loss: 0.1280&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.6: removed dropout layer and trained for 25 epochs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mk 6.7: Instead of stopping the training at a specific number of epochs, I
decided to start checkpointing, and continuously train until the validation
loss plateaued. In this way I could plot a &lt;a href=&quot;https://stats.stackexchange.com/questions/51490/how-large-a-training-set-is-needed/51527#51527&quot;&gt;learning
curve&lt;/a&gt;
and determine whether I needed more data or a more powerful model.&lt;/p&gt;
&lt;p&gt;Here I made &lt;a href=&quot;https://lieuzhenghong.com/2019/09/17/#pointing-the-validation-set-to-be-the-same-as-the-test-set&quot;&gt;silly embarassing mistake #2&lt;/a&gt;. I fixed it but didn&#39;t have the time to rerun the training.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I stopped the deep learning project here to focus on the Raspberry Pi cluster project.&lt;/p&gt;
&lt;h2 id=&quot;silly%2C-embarassing-mistakes-i-made&quot; tabindex=&quot;-1&quot;&gt;Silly, embarassing mistakes I made&lt;/h2&gt;
&lt;h3 id=&quot;not-taking-advantage-of-multiprocessing&quot; tabindex=&quot;-1&quot;&gt;Not taking advantage of multiprocessing&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;predict_generator&lt;/code&gt;
&lt;a href=&quot;https://keras.io/models/model/#predict_generator&quot;&gt;function&lt;/a&gt; there are
several arguments you can pass it to enable multi-CPU operation. One argument
was &lt;code&gt;multiprocessing=True&lt;/code&gt; which I did set. But what I had neglected to
change was &lt;code&gt;workers&lt;/code&gt;, which defaults to 1 if unspecified. Once I set
&lt;code&gt;workers=10&lt;/code&gt; we got---predictably---a 10x speedup in training.&lt;/p&gt;
&lt;h3 id=&quot;using-the-same-data-for-both-the-validation-and-test-set&quot; tabindex=&quot;-1&quot;&gt;Using the same data for both the validation and test set&lt;/h3&gt;
&lt;p&gt;A silly mistake I made with list slicing meant that my validation set was the
same as my test set. I saw the validation loss keep decreasing to 0.09 and
was incredibly pleased; I thought it was too good to be true. It was!&lt;/p&gt;
&lt;h2 id=&quot;my-thoughts&quot; tabindex=&quot;-1&quot;&gt;My thoughts&lt;/h2&gt;
&lt;p&gt;Before I started this project I had a naive idea of deep learning. I was
implicitly assuming the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Nice clean-ish data&lt;/li&gt;
&lt;li&gt;Nice environment to do deep learning already set up for you&lt;/li&gt;
&lt;li&gt;Nice well-defined requirements and unambiguous loss metric&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;None of those assumptions held true in this project. In particular I had to
set up CUDA on my machine (to enable GPU acceleration) and that was really
difficult. Eventually I used PlaidML instead of Tensorflow for the backend
because it played nice with my GPU.&lt;/p&gt;
&lt;p&gt;There&#39;s &lt;em&gt;so much glue code&lt;/em&gt; that goes into a &amp;quot;business&amp;quot; machine learning
model. The actual Keras machine learning code that specifies the model is only
a couple dozen lines, but I have hundreds of lines of code that clean the data,
normalise the data, choose the right subset of the data, read the data, save
the model, run predictions with that model, ... and so on.&lt;/p&gt;
&lt;p&gt;Finally, there are many insidious bugs that can bite you silently in deep
learning projects. This is probably due to my relative inexperience---I hope
that by documenting the silly mistakes here, I&#39;ll not make them again.&lt;/p&gt;
&lt;h2 id=&quot;things-i&#39;ve-learned&quot; tabindex=&quot;-1&quot;&gt;Things I&#39;ve learned&lt;/h2&gt;
&lt;p&gt;This was the first non-toy deep learning project I have done. Because there
was no senior data scientist to guide me, I made many silly mistakes and
didn&#39;t follow best practices.&lt;/p&gt;
&lt;p&gt;The most novel part for me was learning about, and writing, the architecture
that supports the deep learning model.&lt;/p&gt;
&lt;p&gt;Input normalisation improves training significantly. I saw the training/test
loss fall from 0.16 to 0.13 just by normalising the input.&lt;/p&gt;
&lt;p&gt;In the course of the project I went through some of the courses in Andrew
Ng&#39;s &lt;a href=&quot;https://www.coursera.org/specializations/deep-learning&quot;&gt;Deep Learning
Specialisation&lt;/a&gt;. I
didn&#39;t find the specialisation very useful but it was good in giving me some
deep learning intuitions.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Although I didn&#39;t get to finish the project, I still learned a lot. I had to
touch every single part of the deep learning pipeline---not just the model
code itself---which I really appreciated. A big thanks to Richard for
giving me this opportunity.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I watched &lt;a href=&quot;https://www.youtube.com/watch?v=MiiWzJE0fEA&quot;&gt;this Youtube talk&lt;/a&gt; on a probabilistic programming language that can &lt;em&gt;infer&lt;/em&gt; missing data using Bayesian techniques. This is definitely something I want to explore. &lt;a href=&quot;https://lieuzhenghong.com/2019/09/17/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Building an Bayesian SMS sender</title>
    <link href="https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/"/>
    <updated>2019-09-16T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/</id>
    <content type="html">&lt;p&gt;I architected and built a system that programmatically sends SMSes and tracks
each one to see if it has been clicked. I used the pipeline to conduct a
behavioural economics experiment on ~2000 users to investigate the effect of
loss-aversive framing on clickthrough rates. I used Bayesian statistics
(Thompson sampling) to maximise the number of people who were reached by the
optimal SMS.&lt;/p&gt;
&lt;p&gt;I also sent various other SMSes (a total of ~10,000 messages). Overall,
my interventions increased the number of active users by ~25% over a period of
two months.&lt;/p&gt;
&lt;p&gt;(Summer 2019 internship with Inzura)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;As far as I am aware, this is the first behavioural economics experiment that
uses Thompson sampling. There are very good reasons why most experiments don&#39;t
(I elaborate upon this later), but I argue that the multi-armed bandit approach
I used had several advantages over traditional A/B testing.&lt;/p&gt;
&lt;p&gt;I had previously written a &lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/&quot;&gt;more technical
post&lt;/a&gt; on
Bayesian inference and Thompson sampling. Those interested in the details (or
interested in picking apart my misunderstandings) are most welcome to peruse
it. This post will talk about &lt;em&gt;why&lt;/em&gt; I built the pipeline and the architecture
of the pipeline, not the maths.&lt;/p&gt;
&lt;p&gt;I have deliberately been vague about the details of the policy and campaign, to
safeguard the privacy of our client.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;motivation&quot; tabindex=&quot;-1&quot;&gt;Motivation&lt;/h2&gt;
&lt;p&gt;Our client is a large insurer who had rolled out a new policy that used our
app. If the policyholder uses the app to record his driving (and fulfills some
other conditions), he will be eligible for a cashback. However, people were not
installing the app. Our working hypothesis was that people had either forgotten
about the app, or had forgotten that they had to install it/use it to be
eligible for a cashback. Therefore, we wanted to send reminder SMSes to these
customers and see if we could get more uptake of the app.&lt;/p&gt;
&lt;p&gt;As we were going into this blind, we wondered what sort of SMSes would be most
effective. We decided to send three SMSes---a neutral reminder SMS, a
&amp;quot;positive&amp;quot; SMS, and a &amp;quot;negative&amp;quot; SMS&lt;/p&gt;
&lt;p&gt;Our purpose was twofold: i) to get as many people to install the app, and
ii) to see which type of SMS was the most effective.&lt;/p&gt;
&lt;h3 id=&quot;why-three-types-of-smses%3F&quot; tabindex=&quot;-1&quot;&gt;Why three types of SMSes?&lt;/h3&gt;
&lt;p&gt;Behavioural economics predicts that people are loss-averse: that is, they feel
the pain of a loss more acutely than they feel the pleasure of an equivalent
gain. My hypothesis was that an SMS worded to trigger loss aversion (&amp;quot;Install
the app now or lose the cashback you&#39;re eligible for&amp;quot;) would be more effective
than an SMS worded positively (&amp;quot;Install the app now to gain a cashback&amp;quot;), which
would in turn be more effective than a neutral reminder SMS (&amp;quot;Install the app
now&amp;quot;).&lt;/p&gt;
&lt;h3 id=&quot;why-frame-the-experiment-as-a-multi-armed-bandit%3F&quot; tabindex=&quot;-1&quot;&gt;Why frame the experiment as a multi-armed bandit?&lt;/h3&gt;
&lt;p&gt;The gold standard of causal inference is to do a randomised controlled trial:
randomly divide, say, 2400 participants into groups of 800 each, then send 800
the neutral (control), 800 the positive, and 800 the negative. Record the
number of successes (clicked SMS) and failures (did not click SMS) for each
treatment.&lt;/p&gt;
&lt;p&gt;This is Good and Rigorous™. In particular, it maximises our certainty about the
performance of each treatment. In most experimental contexts, this is fine.
Most experiments try to uncover some fact about the world, and to maximise our
certainty in the truth of those facts. But there are three additional
considerations with this experiment design when it comes to the real world.&lt;/p&gt;
&lt;p&gt;The first and biggest consideration is that nobody is going to let you run it
because this is leaving money on the table. With this design 2/3rds (1600) of
the customers will be getting a suboptimal SMS. In a business environment, we
want to &lt;strong&gt;maximise the number of customers who receive the optimal SMS&lt;/strong&gt;, not
really maximise the certainty of our knowledge.&lt;/p&gt;
&lt;p&gt;The second consideration is that we don&#39;t really want to be certain about the
performance of every treatment. We want to be certain of the &lt;em&gt;best&lt;/em&gt; treatment,
which means that a uniform allocation (800 SMSes to each group) is nonideal.
&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The third consideration is that we don&#39;t have to send all the SMSes at the same time.
We can send a subset of the SMSes and use that initial data to draw tentative
conclusions about which SMS is the best.&lt;/p&gt;
&lt;p&gt;Given that we want to maximise the number of customers who receive the optimal
SMS, the traditional experimental design is nonoptimal. But we don&#39;t know which
SMS is best, so how do we find out as quickly as possible, and then maximise
the number of customers who receive it?&lt;/p&gt;
&lt;p&gt;It turns out that this problem can be neatly modeled as a &amp;quot;multi-armed bandit&amp;quot;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are walking around the casino floor where there are ten slot machines,
each with a different probability of paying out. How should one pull the slot
machines in order to maximise one’s payout over the long run?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this case, we have three slot machines (neutral, positive and negative
SMSes). And since we don&#39;t know &lt;em&gt;which&lt;/em&gt; arm is best, we have to send some SMSes
initially to find out.&lt;/p&gt;
&lt;p&gt;But there&#39;s a balance to be struck here. We want to spend some time learning,
but after we&#39;re &amp;quot;pretty sure&amp;quot; about what the best arm is, we should keep
pulling the best arm all the time. This is known as the explore vs exploit
tradeoff (or, more pithily, &amp;quot;learn or earn&amp;quot;). We can see now why the initial
experiment design was not fit for purpose: it&#39;s very good at learning, but no
good at earning. (And we&#39;re trying to earn money here!)&lt;/p&gt;
&lt;h3 id=&quot;why-thompson-sampling%3F&quot; tabindex=&quot;-1&quot;&gt;Why Thompson sampling?&lt;/h3&gt;
&lt;p&gt;There are many proposed algorithms to solve the multi-armed bandit problem:
these include epsilon-greedy, upper confidence bounds (UCB) and Thompson sampling.&lt;/p&gt;
&lt;p&gt;I spent about a week
&lt;a href=&quot;https://lilianweng.github.io/lil-log/2018/01/23/the-multi-armed-bandit-problem-and-its-solutions.html#bandit-strategies&quot;&gt;reading&lt;/a&gt;
&lt;a href=&quot;http://iosband.github.io/2015/07/19/Efficient-experimentation-and-multi-armed-bandits.html&quot;&gt;the&lt;/a&gt;
&lt;a href=&quot;http://iosband.github.io/2015/07/28/Beat-the-bandit.html&quot;&gt;literature&lt;/a&gt; and
thinking about it and eventually decided on Thompson sampling. More details are
covered in my &lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/&quot;&gt;more technical
post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;experiment-design&quot; tabindex=&quot;-1&quot;&gt;Experiment design&lt;/h2&gt;
&lt;p&gt;I decided on the following three SMSes (neutral, positive and negative):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You have not logged any trips. The &amp;lt;POLICY&amp;gt; you have purchased
requires you to log trips regularly on the &amp;lt;APP&amp;gt; app.
Install the app and start logging your trips today. Any problems, call &amp;lt;NUM&amp;gt;, or
email &amp;lt;EMAIL&amp;gt;. Click here to start: http://&amp;lt;*&amp;gt;.inz.ai/&amp;lt;SMS_ID&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You have not logged any trips. The &amp;lt;POLICY&amp;gt; you have purchased requires you to
log trips regularly on the &amp;lt;APP&amp;gt; app. Install the app and start logging your
trips today to be eligible for your (up to) &amp;lt;AMT&amp;gt; cashback! Any problems, call
&amp;lt;NUM&amp;gt;, or email &amp;lt;EMAIL&amp;gt;. Click here to start: http://&amp;lt;*&amp;gt;.inz.ai/&amp;lt;SMS_ID&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;You have not logged any trips. The &amp;lt;POLICY&amp;gt; you have purchased requires you to
log trips regularly on the &amp;lt;APP&amp;gt; app. Install the app and start logging your
trips today or you will lose your (up to) &amp;lt;AMT&amp;gt; cashback! Any problems, call
&amp;lt;NUM&amp;gt;, or email &amp;lt;EMAIL&amp;gt;. Click here to start: http://&amp;lt;*&amp;gt;.inz.ai/&amp;lt;SMS_ID&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While traditional multi-armed bandits allow you to pull one arm at a time and
wait for the results, we didn&#39;t have the luxury of time here. Here we have to
send thousands of SMSes in a short period of time, and we can&#39;t wait for the
result of an SMS to come in (a user might take days to click an SMS if at all)
before sending the next one. The simplest way is to simply send more SMSes in
one go, but I wasn&#39;t sure if this would affect any of the nice guarantees (e.g.
regret bounds) of Thompson sampling. I tried &lt;a href=&quot;https://stats.stackexchange.com/questions/416951/multi-armed-bandit-where-you-must-pull-n-pulls-in-t-timesteps&quot;&gt;asking
StackExchange&lt;/a&gt; but got no response.&lt;/p&gt;
&lt;p&gt;I had to push through in any case. The modified Thompson sampling procedure
works as follows. I start by sending a total of 300 SMSes per batch: in
expectation, 100/100/100 of each type. Some of these SMSes will be clicked on
and some will not.&lt;/p&gt;
&lt;p&gt;Once the results come in, the algorithm will preferentially choose to send more
of the better-performing SMS and fewer of the worst-performing one. For
instance, after the first round the algorithm might send 124/80/96.&lt;/p&gt;
&lt;p&gt;As more batches are sent, the algorithm builds up a better and better picture
of the relative efficacy of each SMS, and will converge upon sending the best
SMS exclusively.&lt;/p&gt;
&lt;p&gt;In this experiment I sent 6 batches of SMSes.&lt;/p&gt;
&lt;h2 id=&quot;architecture&quot; tabindex=&quot;-1&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;I knew what SMSes I wanted to send; I now had to build a system that would
allow me to send it.&lt;/p&gt;
&lt;p&gt;There are four key parts of this pipeline:&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Inzura server that contained customer data&lt;/li&gt;
&lt;li&gt;NGINX server to log clicked SMSes&lt;/li&gt;
&lt;li&gt;PostgreSQL database to log customer data and status of all SMSes sent&lt;/li&gt;
&lt;li&gt;Multi-armed-bandit code to calculate the optimal number of each SMS to send&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I logged clicked SMSes in the following way:&lt;/p&gt;
&lt;h3 id=&quot;sms-tracking-architecture&quot; tabindex=&quot;-1&quot;&gt;SMS tracking architecture&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/sms_pipeloop_0.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: The most important part is to measure the effectiveness of each SMS variant
(neutral, positive or negative). I generate unique SMS IDs (3 alphanumeric characters + checksum)
for each SMS and append them to a template string, making a unique SMS
string. I then make GET requests to the service that sends SMSes, the Ant API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2 and 3&lt;/strong&gt;: The user receives an unique SMS with a link at the end. Upon
clicking it, the user is taken to a &lt;em&gt;logging server&lt;/em&gt; on the &lt;code&gt;inz.ai&lt;/code&gt; domain,
which logs the ID of the SMS and redirects the user to the app store.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4&lt;/strong&gt;: I download the server&#39;s logs and process it, and update my database
of which SMSes have been clicked.&lt;/p&gt;
&lt;h3 id=&quot;data-analysis-and-mab-architecture&quot; tabindex=&quot;-1&quot;&gt;Data analysis and MAB architecture&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/sms_pipeloop_1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now that I had a system to log SMS clicks, I had to implement the experiment.&lt;/p&gt;
&lt;p&gt;First I had to create a PostgreSQL database and decide upon the schema for it.&lt;/p&gt;
&lt;p&gt;Secondly, I had to pull customer data from the Inzura server and add it to
the PostgreSQL database to identify eligible customers (we
obviously don&#39;t want to send reminder SMSes to customers who have already
installed the app).&lt;/p&gt;
&lt;p&gt;Third, I had to write the Thompson sampling code that would read the data
from the database (the slot machine labeled &amp;quot;MAB&amp;quot;). It calculates the optimal
number of each SMS to send given the SMSes&#39; past performances.&lt;/p&gt;
&lt;p&gt;Finally, we generate unique SMSes and give them to the Ant API, and the cycle
restarts. I call this a &amp;quot;pipeloop&amp;quot; because it&#39;s a pipeline that loops upon itself.&lt;/p&gt;
&lt;h3 id=&quot;thompson-sampling-code&quot; tabindex=&quot;-1&quot;&gt;Thompson sampling code&lt;/h3&gt;
&lt;p&gt;This is the code that performs Thompson sampling. First, some definition:&lt;/p&gt;
&lt;p&gt;Each arm is a tuple of the number of clicks and no-clicks of each SMS plus one.
For instance, if I had sent 100 SMSes and there were 7 clicks, then the arm
would be (8, 94).&lt;/p&gt;
&lt;p&gt;The code takes a tuple of arms e.g. &lt;code&gt;[(8, 94), (15, 87), (2, 103)]&lt;/code&gt; and the
number of samples we want to take (ergo the number of SMSes we want to send
this batch). It will then give us the optimal number of each SMS to send. In
the example above, the algorithm will tell us to send more of the 2nd SMS, some
of the 1st SMS, and almost none of the 3rd.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&#39;&#39;&#39;
Thompson sampling code
&#39;&#39;&#39;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; collections &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; namedtuple
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; numpy &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; np
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; random
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; iteround &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; saferound

Arm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; namedtuple&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Arm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;alpha beta&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;thompson_sample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&#39;&#39;&#39;
Takes as input arms and number of pulls we need to make, and
returns a tuple of arms to pull
&#39;&#39;&#39;&lt;/span&gt;
    samples &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    arms_to_pull &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; n &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        samples&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; arm &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arms&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            samples&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sample&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# pick the best arm&lt;/span&gt;
        arm_to_pull &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; samples&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;samples&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        arms_to_pull&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm_to_pull&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; arms_to_pull

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beta&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;arm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;alpha&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; arm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beta&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;results&quot; tabindex=&quot;-1&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;I got a null result. There wasn&#39;t much of a difference between loss-aversive
SMSes (negative framing), positive SMSes and neutral SMSes.&lt;/p&gt;
&lt;p&gt;Because we are using Bayesian statistics here, we can calculate the probability
that loss-aversive SMSes are more effective than neutral or positive ones
directly.&lt;/p&gt;
&lt;p&gt;I calculated the following using a simulation approach:&lt;/p&gt;
&lt;p&gt;There is a &lt;strong&gt;26.6%&lt;/strong&gt; probability that &lt;span style=&quot;color:blue&quot;&gt;loss-aversive
SMSes&lt;/span&gt; are more effective than &lt;span style=&quot;color:red&quot;&gt;neutral&lt;/span&gt; SMSes.&lt;/p&gt;
&lt;p&gt;There is a &lt;strong&gt;60.7%&lt;/strong&gt; probability that &lt;span style=&quot;color:blue&quot;&gt;loss-aversive
SMSes&lt;/span&gt; are more effective than &lt;span style=&quot;color:green&quot;&gt;positive&lt;/span&gt; SMSes.&lt;/p&gt;
&lt;p&gt;Obviously none of these results are very credible.&lt;/p&gt;
&lt;p&gt;Code for the simulation:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; random
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; numpy &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; np

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sample&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;np&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beta&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tup&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tup&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

N &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000000&lt;/span&gt;

neutral &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sample&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;69&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;828&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
positive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sample&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;154&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
negative &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sample&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;266&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;negative&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; neutral&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;negative&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; positive&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
d &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; c &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; N&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following diagrams are &lt;a href=&quot;https://en.wikipedia.org/wiki/Beta_distribution&quot;&gt;beta
distributions&lt;/a&gt;. Think of them
as a measure of our uncertainty in the effectiveness of each SMS. The x-axis
measures the effectiveness of each SMS, and the y-axis measures our degree of
certainty. The higher and sharper the distribution, the more certain we are
about the effectiveness of an SMS.&lt;/p&gt;
&lt;p&gt;The diagrams show the evolution of the estimates over time by SMS
variant: &lt;span style=&quot;color:red&quot;&gt;red&lt;/span&gt; is neutral, &lt;span
style=&quot;color:green&quot;&gt;green&lt;/span&gt; is positive, and &lt;span
style=&quot;color:blue&quot;&gt;blue&lt;/span&gt; is negative. Overall we can see that the
distributions lie very closely to one another.&lt;/p&gt;
&lt;p&gt;When we begin, we have no idea how effective the SMSes are, so we assume that
all SMSes form a uniform distribution. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;
&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_0.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As we send SMSes and get the results back we begin to update our beliefs about
the SMSes. Here the &lt;span style=&quot;color:red&quot;&gt;neutral&lt;/span&gt; SMSes seem to do
best and thus the Thompson sampling algorithm chooses to send a lot of it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;But the good performance of the neutral SMSes is quickly revealed to be a fluke
as more SMSes are sent out.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_3.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_4.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/sms_pipeloop/prior_5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Eventually after all the SMSes have been sent we realise that all of the SMSes
are about the same in effectiveness.&lt;/p&gt;
&lt;p&gt;Due to time constraints, I could not run further experiments: I did A/B testing
henceforth sending multiple reminder messages and again got null results. So
I&#39;m glad this was a very robust null finding :P&lt;/p&gt;
&lt;p&gt;Nonetheless, my further interventions were able to increase the number of
active users by around ~25%. I will not reveal numbers here for privacy
reasons, but this had a real business impact because Inzura gets paid per
monthly active user.&lt;/p&gt;
&lt;h2 id=&quot;what-i-learned&quot; tabindex=&quot;-1&quot;&gt;What I learned&lt;/h2&gt;
&lt;p&gt;I gained valuable practice in designing an experiment and carrying it to
completion. I had originally wanted to kill two birds with one stone and use
this for my BEE thesis, but a null finding isn&#39;t particularly exciting, so I
will keep looking. &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I learned quite a lot about Bayesian inference in the course of designing the
experiment, and would like to learn more about it. When I have more bandwidth I
will consider doing the &lt;a href=&quot;https://www.coursera.org/specializations/probabilistic-graphical-models&quot;&gt;Probabilistic Graphical Models MOOC by Daphne
Koller&lt;/a&gt;,
and reading Judea Pearl&#39;s co-authored book on DAGs (highly recommended by Bassel).&lt;/p&gt;
&lt;p&gt;I had to learn SQL in order to build the databases. In the course of doing this
project I worked through the &lt;a href=&quot;https://lagunita.stanford.edu/courses/DB/2014/SelfPaced/about&quot;&gt;Stanford Databases MOOC by Jennifer
Widom&lt;/a&gt;. I
completed &lt;code&gt;DB1 Introduction and Relational Databases&lt;/code&gt;, &lt;code&gt;DB4 Relational Algebra&lt;/code&gt;, &lt;code&gt;DB5 SQL&lt;/code&gt; and &lt;code&gt;DB8 Relational Design Theory&lt;/code&gt;. DB4 and DB8 helped me
design the schema and DB5 improved my very hackish/amateur queries into much
more elegant and readable ones.&lt;/p&gt;
&lt;p&gt;Lastly, I was able to stretch my mind by architecting a complex system. It&#39;s
kind of like thinking about the Lego parts you&#39;ll need to 3D-print to build the
rocket ship you have in mind. It was a good exercise to think about what parts
I needed in the system and how they would talk to each other. (I guess this is
what senior SWEs like Chris and David do in their sleep.) I&#39;ve greatly
simplified the architecture in my breezy explanation---the actual architecture
I built has more moving parts, and it was quite challenging for me.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I am very glad that my knowledge of statistics and behavioural economics could
be brought to bear in this project. I have always gone through my degree
thinking that it was useless for doing anything technical.&lt;/p&gt;
&lt;p&gt;This project gave me an idea about my comparative advantage in data science.
While it isn&#39;t difficult for a computer science major to learn statistics, many
of them might not have done so. If I max out my statistics and maintain my
ability to write software I could be some sort data-scientist data-engineer
hybrid; not a &amp;quot;pure&amp;quot; data scientist but someone who likes to get his hands
dirty wrangling the code and building the systems.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This is the problem of &amp;quot;best arm identification&amp;quot;. For N &amp;gt; 2, it isn&#39;t optimal to pull all arms equally. If one arm is very obviously worse than the rest, the algorithm shouldn&#39;t waste time on pulling it more. &lt;a href=&quot;https://www.microsoft.com/en-us/research/wp-content/uploads/2017/01/COLT10_ABM.pdf&quot;&gt;this paper&lt;/a&gt; (Best Arm Identification in Multi-Armed Bandits) has more details. See also &lt;a href=&quot;https://icml.cc/Conferences/2009/papers/229.pdf&quot;&gt;this paper&lt;/a&gt; on Heoffding and Bernstein races where the objective is to try to establish the best action at a given confidence level with the fewest pulls. &lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The choice of a uniform prior was because I had never run an experiment like this before, and had no idea what the clickthrough rate of an SMS was supposed to be. For subsequent experiments I would initialise the priors at around a 0.07 click rate. &lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Yes, I know I&#39;m contributing to publication bias---but my grades are on the line here... &lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Doing distributed data analysis on a Raspberry Pi cluster</title>
    <link href="https://lieuzhenghong.com/2019/09/12/big-data-analysis-on-a-distributed-raspi-cluster/"/>
    <updated>2019-09-12T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/09/12/big-data-analysis-on-a-distributed-raspi-cluster/</id>
    <content type="html">&lt;p&gt;(Summer 2019 internship with Inzura)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This is the second project I&#39;ve done with Raspberry Pis. The first one was a
&lt;a href=&quot;https://lieuzhenghong.com/2017/05/30/building-a-raspberry-pi-console/&quot;&gt;Raspberry Pi game console&lt;/a&gt;
done back in 2017.&lt;/p&gt;
&lt;p&gt;As far as I know, this is the largest Apache Spark Raspi cluster that has been
published online. There&#39;s an &lt;a href=&quot;https://dev.to/awwsmm/building-a-raspberry-pi-hadoop-spark-cluster-8b2&quot;&gt;eight-node Raspi 4 cluster
here&lt;/a&gt;
and a &lt;a href=&quot;https://www.raspberrypi.org/magpi/pi-spark-supercomputer/&quot;&gt;six-node Raspi 2 cluster
here&lt;/a&gt; but i) ours is
the biggest and ii) we have actually used the cluster to do &amp;quot;real&amp;quot; data
analysis.&lt;/p&gt;
&lt;h2 id=&quot;results&quot; tabindex=&quot;-1&quot;&gt;Results&lt;/h2&gt;
&lt;p&gt;I calculated average traffic speeds of a sample of 50,000 trips in the UK.
These trips were recorded from drivers who used Inzura&#39;s mobile app. The
vast majority of trips were in Northern Ireland, and I&#39;ve chosen to zoom in on
the traffic data in Belfast, Northern Ireland. These are &lt;a href=&quot;https://en.wikipedia.org/wiki/Choropleth_map&quot;&gt;chloropleth
maps&lt;/a&gt;: roads with low average
speeds are dark purple, and roads with high average speeds bright yellow.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/UK_cropped.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is a really high-resolution image, best opened and viewed in full-size.
It shows the extent of coverage of the trips that I sampled. We can see that
while the data covers the entirety of the UK, most of the trips are from
Northern Ireland (NI).&lt;/p&gt;
&lt;p&gt;As we zoom into NI we see that almost the entire landmass has been traversed.
We can clearly make out city centers, and the roads that connect them: Belfast
is by far the largest and most prominent---although one can make out other
cities like Bangor and Lisburn near it. We can also see Donegal and Omagh
in the west.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/ireland_big.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can glean some insights even at this distance. We can see that
average speeds in cities tend to be low (dark purple), while roads that connect
cities have higher average speeds.&lt;/p&gt;
&lt;p&gt;Let&#39;s zoom in a little:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_1000000.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can now clearly see the shape of Belfast and the cities near it. There&#39;s an
interesting funnel shape at the top, almost like it&#39;s feeding into Belfast
proper. There&#39;s also what looks like extensions of the city to the south-west:
are these part of Belfast too, or cities in their own right?&lt;/p&gt;
&lt;p&gt;From the road network alone we can see that towns usually set up near the
coast: the road network on both sides of the bay is much denser than bits
closer inland.&lt;/p&gt;
&lt;p&gt;Now let&#39;s zoom in to Belfast proper:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_250000.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At this zoom level the layout of the city can clearly be discerned. Streets
near the center of the city are laid out in a neat and densely-packed grid
pattern, which gives way to a sparser, more organic layout toward the&lt;/p&gt;
&lt;p&gt;We can even see some ferry routes from the pier! These are routes to the
mainland and the Isle of Man.&lt;/p&gt;
&lt;p&gt;Most interestingly, we can see an S-shaped road that snakes through the city.
It starts from the southwest and winds its way up northeast. We can see that it
is a different colour from the rest of the city&#39;s roads, which are mostly dark
purple: this road has segments of yellow and green.&lt;/p&gt;
&lt;p&gt;Here&#39;s the same image with the background darkened so we can see the colours
more clearly:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_250000_dark.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We can really make out the S-shaped road here, and a couple more besides.
There&#39;s a road leading down from the northeast that looks like a main
connection to the northeastern coast.&lt;/p&gt;
&lt;p&gt;One final zoom in to 1:25000 scale:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_100000.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The shape (and colour) of the S-shaped road is apparent now.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_25000_dark.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Average speeds on the S-shaped road decrease when there is a bend in the road,
and when there is an intersection. Notice also that roads on the periphery tend
to have higher average velocities, although this could be because there is not
enough data on them (thus throwing off the averages).&lt;/p&gt;
&lt;p&gt;One final render without the background---just because it looks pretty, and
shows us the shape of the city:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/belfast_250000_white.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;raspberry-pi-compute-cluster&quot; tabindex=&quot;-1&quot;&gt;Raspberry Pi compute cluster&lt;/h2&gt;
&lt;p&gt;This is the Raspberry Pi compute cluster. It&#39;s taller than a man:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/full-shot.jpg&quot; alt=&quot;full body shot of cluster&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was designed and built by Richard Jelbert, the CEO and co-founder of
Inzura. Almost everything you see is 3D-printed: that includes the
faceplates, the clips and the holding rack (for the Raspis). It contains 16
Raspi 4s and 25 assorted Raspi 3B/3/2/1s. For this project I only used the
Raspi 4s.&lt;/p&gt;
&lt;p&gt;The structure of the cluster is hexagonal: there are 5 storeys and 6 segments
on each storey. One of the segments is reserved for SSDs (data storage and
database lookups), but the other 5 segments can be used for compute.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/cluster_closeup.jpg&quot; alt=&quot;close up shot of cluster&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I&#39;m sorry Dave, I&#39;m afraid I can&#39;t do that&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The front panel opens up to expose the internals:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/cluster_opened.jpg&quot; alt=&quot;shot of cluster innards&quot;&gt;&lt;/p&gt;
&lt;p&gt;Again, all of this is 3D-printed. 8 Raspberry Pi 4s sit on each rack and are
cooled by 4 mini-fans per rack (the cooling is necessary to prevent them
throttling).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/cluster_opened_closeup.jpg&quot; alt=&quot;close up shot of cluster innards&quot;&gt;&lt;/p&gt;
&lt;p&gt;The cluster has a theoretical maximum capacity of 400 Raspis (16 Raspis per
segment, 5 segments per storey, 5 storeys total); Richard said that cooling
may be tricky at that density, but 12 Raspis per segment is definitely
doable. That gives us an actual capacity of 300 Raspis in the cluster.&lt;/p&gt;
&lt;p&gt;It is also &lt;a href=&quot;https://docs.min.io/docs/deploy-minio-on-docker-swarm.html&quot;&gt;possible to cluster MinIO across up to 16
nodes&lt;/a&gt;. Minio
allows distributed object storage: it lets my code run without having a copy of
every single file on every single Raspi. Given that we need only 1 SSD per
storey, this will be sufficient for our purposes.&lt;/p&gt;
&lt;h2 id=&quot;why-use-the-cluster%3F&quot; tabindex=&quot;-1&quot;&gt;Why use the cluster?&lt;/h2&gt;
&lt;p&gt;Why go to all the trouble to set up a compute cluster? Why not run it on a
single machine?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It&#39;s the only scalable solution when the number of trips gets large&lt;/li&gt;
&lt;li&gt;We get increased performance by parallelising computation&lt;/li&gt;
&lt;li&gt;It&#39;s cool!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;scalability&quot; tabindex=&quot;-1&quot;&gt;Scalability&lt;/h3&gt;
&lt;p&gt;I had only been able to download a small sample of 50,000 anonymised trips.
But Inzura has a corpus of millions of trips and growing. It certainly
doesn&#39;t fit on a single machine&#39;s memory (it doesn&#39;t even fit on disk). So
the most naive approach of reading all the files into memory at once and
calculating the average that way won&#39;t work. Something that &lt;em&gt;does&lt;/em&gt; work is to
read the files in one by one and calculate the averages that way, but this is
of course rather slow. Which leads us to ...&lt;/p&gt;
&lt;h3 id=&quot;performance&quot; tabindex=&quot;-1&quot;&gt;Performance&lt;/h3&gt;
&lt;p&gt;The task is to calculate average road speed for every road in the database.
This is an &lt;em&gt;embarassingly parallelisable&lt;/em&gt; task: each trip is an individual JSON
file (which means we don&#39;t have to worry about shared memory), and there is
almost no work needed to combine the results of disparate parallel
computations. This means that we can get a close-to-linear speedup simply by
adding more computers --- which means that a cluster of Raspberry Pis will
outperform even a beefy (and much more expensive) computer.&lt;/p&gt;
&lt;p&gt;Even if 16 Raspis don&#39;t outperform a single computer, 300 Raspis certainly
will, and it is easy now to add more Raspis now that the groundwork has been
laid. This opens the door to all sorts of future data analysis and exploration
tasks which may be prohibitively expensive for a single computer to run (in
terms of wall-clock time).&lt;/p&gt;
&lt;h3 id=&quot;cool-factor&quot; tabindex=&quot;-1&quot;&gt;Cool factor&lt;/h3&gt;
&lt;p&gt;Why not just use Google Cloud or something?---because this is cooler and more
educational.&lt;/p&gt;
&lt;h2 id=&quot;configuring-the-cluster&quot; tabindex=&quot;-1&quot;&gt;Configuring the cluster&lt;/h2&gt;
&lt;p&gt;Configuring the cluster was by far the hardest part of this project. Any
instructions I could find for setting up a Spark cluster were either
incomplete, out of date, or incorrect. It took Richard, Chris and I three full
days to set everything up. Eventually I heavily modified &lt;a href=&quot;https://github.com/minio/cookbook/blob/master/docs/apache-spark-with-minio.md&quot;&gt;this MinIO
cookbook&lt;/a&gt;
and successfully deployed Spark on the 16 worker Raspis:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-cluster/spark-console.jpg&quot; alt=&quot;spark console with 16 slaves&quot;&gt;&lt;/p&gt;
&lt;p&gt;The cluster computer has 64 cores and 64GB of memory (45GB free)---already much better than
my laptop.&lt;/p&gt;
&lt;p&gt;I have written a bash script that should automate (but not completely) the
installation process
&lt;a href=&quot;https://gist.github.com/lieuzhenghong/c062aa2c5544d6b1a0fa5139e10441ad&quot;&gt;here&lt;/a&gt;.
The only thing one has to do apart from this is to edit the &lt;code&gt;core-site.xml&lt;/code&gt;
file to point to one&#39;s S3 bucket/MinIO server.&lt;/p&gt;
&lt;h2 id=&quot;apache-spark-code&quot; tabindex=&quot;-1&quot;&gt;Apache Spark code&lt;/h2&gt;
&lt;p&gt;I gained the necessary knowledge to do this data analysis project by working
through part of the &lt;a href=&quot;https://www.coursera.org/specializations/scala&quot;&gt;Functional Programming in Scala
Specialisation&lt;/a&gt;. I finished the
courses &lt;em&gt;Functional Programming Principles in Scala&lt;/em&gt;, &lt;em&gt;Parallel Programming&lt;/em&gt;
and &lt;em&gt;Big Data Analysis with Scala and Spark&lt;/em&gt;. The last course was the most
directly relevant to this project but I found the first course incredibly
helpful for learning Scala (and the functional programming paradigm), and the
third course for reasoning about parallel programs. Both courses helped me
appreciate why Scala is a good language for data analysis---many of the
functional abstractions of mapping over an iterable of some sort carry over
almost directly to distributed computing.&lt;/p&gt;
&lt;p&gt;I found Spark quite concise, although the documentation was quite lacking.
Nonetheless, I was able to write the program in only about 20 lines of code.&lt;/p&gt;
&lt;p&gt;The code does the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read a JSON file onto the Raspi&lt;/li&gt;
&lt;li&gt;Extract all the roads and velocities from the JSON file (Map step)&lt;/li&gt;
&lt;li&gt;Combine all the roads and find the average velocities from all the JSON
files (Reduce step)&lt;/li&gt;
&lt;li&gt;Saves it into a single CSV file (the &lt;code&gt;coalesce&lt;/code&gt; step). This step is optional
(and in fact is probably not recommended when the data set gets larger). I
did it to make it easier to visualise in QGIS.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In total there were 50,000 trips, ~85 million data points, and ~170,000 unique
road IDs.&lt;/p&gt;
&lt;pre class=&quot;language-scala&quot;&gt;&lt;code class=&quot;language-scala&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;object&lt;/span&gt; SimpleApp &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; main&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;args&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;apache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sql&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;SparkSession
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;apache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sql&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;functions&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;explode&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; spark &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SparkSession&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;builder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;appName&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;TripAnalysis&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getOrCreate&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;implicits&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;_
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; results_path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3a://results/&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; paths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s3a://trips/*&quot;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; tripDF &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;option&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;multiline&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;paths&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// &quot;Explode&quot; the data array into individual rows&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; linksDF &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tripDF&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;select&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;explode&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$&lt;span class=&quot;token string&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;as&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; linksDF2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; linksDF&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;select&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;data.dbResponse.linkID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;data.absVelocity&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// create a temporary view using the DataFrame&lt;/span&gt;
    linksDF2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createOrReplaceTempView&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;times&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;/*
      root
      |-- linkID: string (nullable = true)
      |-- absVelocity: double (nullable = true)
    */&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; tDF &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sql&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&quot;SELECT CAST&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;linkID as LONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; absVelocity from times
	WHERE linkID IS NOT NULL AND absVelocity IS NOT NULL&quot;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; groupedDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tDF&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;groupBy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;linkID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;val&lt;/span&gt; avgsDS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; groupedDS&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;agg&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;linkID&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;count&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token string&quot;&gt;&quot;absVelocity&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;avg&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sort&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;$&lt;span class=&quot;token string&quot;&gt;&quot;linkID&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;asc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    avgsDS&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;coalesce&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    option&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;header&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    csv&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results_path &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;results_49998&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    spark&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stop&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Spark code gives the road IDs, but we still have to get the coordinates
that that road ID corresponds to. So I queried the road database (which also
runs in the cluster) with a couple of lines of throwaway Python code.&lt;/p&gt;
&lt;p&gt;I had written a SQL utility function for my &lt;a href=&quot;https://lieuzhenghong.com/2019/09/16/using-thompson-sampling-to-optimise-SMS-effectiveness/&quot;&gt;previous project on optimising SMS
messages&lt;/a&gt;
which I was able to reuse here.&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; time
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; sql_utils &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; query

&lt;span class=&quot;token comment&quot;&gt;# First read csv&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; csv

rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;results-49998.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    csvreader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; csv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;reader&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;f&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    header &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;csvreader&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;header&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; csvreader&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

BATCH_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;
NUM_ROWS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

pointer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Break up the rows&lt;/span&gt;

link_ids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

all_start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; pointer &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; NUM_ROWS&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    link_ids_subset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; link_ids&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;pointer&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;BATCH_SIZE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    array_string &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;, &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;join&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; link_ids_subset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    array_string &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;(&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;array_string&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)&quot;&lt;/span&gt;&lt;/span&gt;
    query_string &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;SELECT geom from (SELECT DISTINCT(link_id), &quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;geom FROM streets WHERE link_id IN {array_string}) as f&quot;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Send out the query&lt;/span&gt;
    query_result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query_string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pointer&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;BATCH_SIZE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        rows&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;query_result&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Time taken to do &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pointer&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;pointer&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;BATCH_SIZE&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;end&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;start&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    pointer &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; BATCH_SIZE

all_end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Time taken to make all the queries: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;all_end&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;all_start&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

header&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;append&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;geom&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;results-49998-with-geom.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;w&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    f&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;join&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; header&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    f&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;\n&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;results-49998-with-geom.csv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;NUM_ROWS&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        f&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;join&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        f&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;\n&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are issues with such an approach: when the number of unique road IDs get
large, we won&#39;t be able to load all the rows into memory like I do here. But
there were only ~140,000 unique link IDs, and I think even if you were to cover
the whole of the UK the number of links would not exceed 2 million --- which
fits well within the memory of a single machine.&lt;/p&gt;
&lt;p&gt;I made two main optimisations.&lt;/p&gt;
&lt;p&gt;First of all, I batched up the queries (instead of querying &lt;code&gt;SELECT * FROM streets WHERE link_ID = linkid&lt;/code&gt;, do &lt;code&gt;WHERE link_ID IN {array_string}&lt;/code&gt;) because
I knew that latency would be the primary bottleneck. This gave a huge speedup:
making 10,000 queries (without caching) only took about 1.2 seconds. To give a
comparison, measured round-trip time was about 0.1s (100ms); if I had made
140,000 individual queries, this would have taken 14,000 seconds (4 hours!),
and I was able to do all the queries in 14 seconds.&lt;/p&gt;
&lt;p&gt;Second, I knew that the linkIDs were indexed in the database, and so I made
sure to sort the linkIDs before batching and sending them to maximise the
probability of a cache hit.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(base) lieu@bigbeast:~/dev/cluster-computing$ python3 get_road_geom.py
[&#39;linkID&#39;, &#39;count(linkID)&#39;, &#39;avg(absVelocity)&#39;]
Time taken to do 0:10000: 0.5610289573669434
Time taken to do 10000:20000: 0.48032593727111816
Time taken to do 20000:30000: 0.5004429817199707
Time taken to do 30000:40000: 0.5266928672790527
Time taken to do 40000:50000: 0.5340712070465088
Time taken to do 50000:60000: 0.6023671627044678
Time taken to do 60000:70000: 0.5589091777801514
Time taken to do 70000:80000: 0.48449015617370605
Time taken to do 80000:90000: 0.543027400970459
Time taken to do 90000:100000: 0.5296523571014404
Time taken to do 100000:110000: 0.6949601173400879
Time taken to do 110000:120000: 1.437162160873413
Time taken to do 120000:130000: 1.2379283905029297
Time taken to do 130000:140000: 1.15696120262146
Time taken to make all the queries: 9.848754644393921
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final CSV looked like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;linkID;count(linkID);avg(absVelocity);geom
17341260;3;25.53091932029027;LINESTRING (-4.17935 53.21241, -4.17968 53.21257, -4.18033 53.21294, -4.18115 53.21319, -4.18138 53.2133, -4.18184 53.21339, -4.18204 53.21346, -4.18262 53.21369, -4.18334 53.21389, -4.18394 53.21439, -4.18473 53.21465, -4.18535 53.21475, -4.18618 53.21478)
17341303;1;31.053999640650744;LINESTRING (-4.17386 53.2051, -4.17501 53.20569, -4.17523 53.2058, -4.17534 53.20584)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The LINESTRING is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry&quot;&gt;Well-Known Text (WKT) geometry
representation&lt;/a&gt;
and corresponds to the coordinates that a road occupies.&lt;/p&gt;
&lt;h2 id=&quot;future-extensions&quot; tabindex=&quot;-1&quot;&gt;Future extensions&lt;/h2&gt;
&lt;p&gt;Now that the groundwork is done, future extensions become merely an issue of
writing new code in Spark (which is, IMO, the easiest part). Some very nice and
(relatively) low-hanging fruit to pluck include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Subdividing average speeds by time of day (so we can see how traffic
conditions vary with time). We can even do a nice animation.&lt;/li&gt;
&lt;li&gt;Bringing in the full database of millions of anonymised trips in the corpus (possibly by connecting
directly to the AWS servers rather than using a local MinIO instance)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, we can use the calculated average speeds to give a more
personalised metric of driver safety. At the moment, a driver&#39;s score is
determined (in part) by whether or not he drives over the speed limit of a
road. But many roads do not fit their posted speed limits. It would be more
enlightening to compare a driver&#39;s driving patterns to a reference distribution
of other drivers on the same roads---and this data analysis helps us create
that reference distribution.&lt;/p&gt;
&lt;p&gt;Finally, we could use the ground truth of average speeds as input to a machine
learning model. Can we predict the probability of a driver getting into an
accident given the roads that he drives on, the speed he drives on those roads,
and how he drives on them? A reference distribution is surely instructive here:
it&#39;s not as dangerous to go fast when everyone else around you is going fast,
but it&#39;s very dangerous to go fast when everyone else is slow (or go slow when
everyone else is fast).&lt;/p&gt;
&lt;p&gt;From Richard:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I think big data analysis is a definite. GPUs will be faster than CPU at
certain simple tasks so worth keeping to tasks that distribute well across CPUs
(small input data, lots of complex math, small output data / results). Inference
technology is also getting cheaper and dedicated neural network hardware
could be added to each node. Like the Google fpga or Intel hardware. this may be
faster than GPU&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;you should mention that Spark was bare metal and that the next step will be
to migrate to Docker Swarm deployed Spark nodes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;what-i-learned&quot; tabindex=&quot;-1&quot;&gt;What I learned&lt;/h2&gt;
&lt;p&gt;Scala, Spark and distributed computing were completely new to me, and I had a
great time learning them. Learning about the abstractions of functional
programming expanded my mind. For instance, I had heard about monoids and
monads before but I only now understand their significance. Something that
really clicked for me was an explanation of how monoids map easily to
parallel programming, due to their associativity and identity.&lt;/p&gt;
&lt;p&gt;Spark was cool as well. There were many helpful tips in the course about
optimising one&#39;s Spark program (always try to use Pair RDDs/Datasets, avoid
shuffles whenever possible, minimise the data sent over the network, using
range partitioning...) but sadly none of them were useful for this project.&lt;/p&gt;
&lt;p&gt;It was difficult trying to get Spark working on the Raspberry Pi cluster---in
part because not many people have done it---but I&#39;m pleased to have cracked
this tough nut. In fact the project made me want to build my own Raspi
cluster...&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I am very happy to have had the opportunity to work on this project. I am very
grateful to Richard Jelbert for giving me this very cool project to work on.&lt;/p&gt;
&lt;p&gt;Richard seems to be glad too. Running data analysis on the cluster with Spark
has been on his wishlist for quite a while now, but nobody has had the
bandwidth to do it.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>The beta-Bernoulli bandit, Thompson sampling, and Bayesian inference</title>
    <link href="https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/"/>
    <updated>2019-07-12T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/</id>
    <content type="html">&lt;p&gt;I&#39;m using the work I do at my internship to run a behavioural economics
experiment. Trying to run this experiment has led me down an incredibly deep
rabbit hole, and I wanted to write down some of the things I&#39;ve learned before
I inevitably forget.&lt;/p&gt;
&lt;p&gt;I also wanted to use this blog post to defend many of the decision points I
made---there were many points where I had to make a decision to use one
approach or another, and I spent many hours thinking and reading about the best
approach.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;background&quot; tabindex=&quot;-1&quot;&gt;Background&lt;/h2&gt;
&lt;p&gt;I&#39;m trying to send SMSes to customers telling them to install an app.
Behavioural economics predicts that people are loss-averse, so I am trying to
find out if sending SMSes that have a loss-aversion framing&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;install the app
now, or you&#39;ll lose your 4500THB cashback&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;has a greater effect than sending
SMSes that have a positive framing&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;install the app now, to get 4500THB
cashback&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The question is:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How can we find out which SMS is best?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The gold standard of causal inference is to do a randomised experiment:
randomly divide my 2400 participants into groups of 800 each, then send 800 the
neutral (control), 800 the positive, and 800 the negative. Record the number of
successes (clicked SMS) and failures (did not click SMS) for each treatment.&lt;/p&gt;
&lt;p&gt;By the Central Limit Theorem all of these will be normal distributions. We can
then do the usual t-tests/chi-squared test and test that there is a
statistically significant difference between the means. (More precisely, we
reject the null hypothesis that there is no difference between the means).&lt;/p&gt;
&lt;p&gt;This is Good and Rigorous™ — but the problem is nobody is going to let you run
it because this is leaving money on the table. Only 800 customers are going to
get the optimal treatment, but that means 2/3rds of them will be getting a
suboptimal treatment.&lt;/p&gt;
&lt;p&gt;Is there a better way? Specifically, is there an optimal way to send the SMSes
so that we can &amp;quot;know&amp;quot; which treatment is best with some notion of certainty,
yet still get the most number of people receiving the optimal treatment at the
end of the day?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why this can be modelled as a multi-armed bandit problem&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It turns out that this is an incredibly-well-studied field, with a lot of applications everywhere from medical trials to (of course) marketing.&lt;/p&gt;
&lt;p&gt;The explanation of the multi-armed bandit is incredibly intuitive, and it&#39;s
something you just grok the instant you hear about it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You are walking around the casino floor where there are ten slot machines,
each with a different probability of paying out. How should one pull the slot
machines in order to maximise one&#39;s payout over the long run?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are two tradeoffs here. On the one hand, we want to &lt;em&gt;explore&lt;/em&gt; in order to
find out what the best slot machine is. The best way to be sure of what the
actual probabilities of the payouts are is to pull every arm equally.&lt;/p&gt;
&lt;p&gt;But on the other hand, do we really &lt;em&gt;care&lt;/em&gt; about what the actual probabilities
of &lt;em&gt;all&lt;/em&gt; the payouts are? Does it really matter if slot machine #4 could have
a probability of 0.01--0.03 if we are pretty sure that slot machine #5 has a
probability of 0.40-0.60? Fundamentally we want to &lt;em&gt;exploit&lt;/em&gt;: if we are already
90% sure that this slot machine is the best one, we shouldn&#39;t keep pulling the
others to &amp;quot;explore&amp;quot;, because that will in expectation reduce our earnings.
&lt;a href=&quot;https://lilianweng.github.io/lil-log/2018/01/23/the-multi-armed-bandit-problem-and-its-solutions.html#bandit-strategies&quot;&gt;This
post&lt;/a&gt;
was incredibly helpful for getting the intuitions, and I&#39;ll refer to this post
again and again.&lt;/p&gt;
&lt;p&gt;In the same way, it&#39;s suboptimal &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; to run a &amp;quot;pure exploration strategy&amp;quot; of
800/800/800 split. Once we&#39;ve made, say, 100 pulls each, we should be more or
less &amp;quot;sure enough&amp;quot; about the probability of each treatment, and therefore we
should &amp;quot;shift gears&amp;quot; and start the exploitation.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;OK, so now I&#39;ve shown that if we want to maximise our payout (also called the
&amp;quot;cumulative reward&amp;quot;), then a pure exploratory strategy is suboptimal. That
leads to a very natural follow-up question:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is the optimal strategy to maximise cumulative reward?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now that we have intuition firmly in our heads, it is useful at this point to
introduce some mathematics so that we can more formally specify the problem.&lt;/p&gt;
&lt;p&gt;I&#39;ll not focus here on the general multi-armed bandit (MAB) problem. Instead
I&#39;ll specify the Bernoulli bandit, and I&#39;ll modify slightly the description
from &lt;a href=&quot;https://web.stanford.edu/~bvr/pubs/TS_Tutorial.pdf&quot;&gt;this paper&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;(Bernoulli Bandit)&lt;/em&gt; Suppose there are &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; actions and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; time-steps,
and when an action is played, it yields either a success or a failure. Action
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;∈&lt;/mo&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k \in {1, ..., K}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7335em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; produces a success with probability &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;∈&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta_k \in
[0,1]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∈&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. If there is a success, then &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;r_t = 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, else &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;r_t = 0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The
success probabilities are unknown to the agent, but are fixed over time. The
objective is to maximise the cumulative reward &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msubsup&gt;&lt;mo&gt;∑&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msubsup&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sum^T_{t=1} r_t&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.2809em;vertical-align:-0.2997em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;&lt;span class=&quot;mop op-symbol small-op&quot; style=&quot;position:relative;top:0em;&quot;&gt;∑&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9812em;&quot;&gt;&lt;span style=&quot;top:-2.4003em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mrel mtight&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2997em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; over
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; periods, where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is relatively large compared to the number of arms
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&#39;s first think about a few simple strategies. Let&#39;s start with the worst:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Random -- choose an arm at random every period.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;First of all, the random strategy is exactly that---random---and the expected
cumulative reward for this strategy is simply&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;munderover&gt;&lt;mo&gt;∑&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/munderover&gt;&lt;mfrac&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/mfrac&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sum^K_{k=1} \frac{T}{3} \theta_k.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:3.1304em;vertical-align:-1.3021em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop op-limits&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.8283em;&quot;&gt;&lt;span style=&quot;top:-1.8479em;margin-left:0em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.05em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;mrel mtight&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.05em;&quot;&gt;&lt;/span&gt;&lt;span&gt;&lt;span class=&quot;mop op-symbol large-op&quot;&gt;∑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-4.3em;margin-left:0em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3.05em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3021em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For instance, if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;{&lt;/mo&gt;&lt;mn&gt;0.3&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;0.4&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;0.5&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;}&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta = \{0.3, 0.4, 0.5\}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.3&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;300&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;T=300&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;300&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, then the random
strategy would give &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi mathvariant=&quot;double-struck&quot;&gt;E&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;30&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;40&lt;/mn&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;50&lt;/mn&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;120&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\mathbb{E}[r] = 30 + 40 + 50 = 120&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathbb&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;120&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Notice that the Random strategy is exactly the &amp;quot;random assignment&amp;quot; algorithm of
assigning 800/800/800.&lt;/p&gt;
&lt;p&gt;Can we do better? Let&#39;s try the following:&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&amp;quot;Dumb&amp;quot; Greedy(N) -- pull each arm N times. Pick the arm with the highest sampled
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;; call it arm &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Then always pull arm &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;K^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; henceforth.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note the two degenerate cases: if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N=0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, Dumb Greedy picks an arm at random
and pulls it all the way. If &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;K&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N=T/K&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;K&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, the greedy approach reduces to the
random strategy. For intermediate values of N, we &lt;em&gt;first&lt;/em&gt; pull all arms N
times, to get a better idea of the distribution, then checks the best arm and
pulls that. Greedy(N) dominates random choice, because it
gets &lt;em&gt;some&lt;/em&gt; information about which arm is best, and uses that information to
inform its choice.&lt;/p&gt;
&lt;p&gt;This strategy&#39;s effectiveness follows a U-shaped curve: it&#39;s no better than
random choice if you just pick a random arm at t=0 and pull it forever, or
forever pick a random arm. By the law of large numbers, the more you pull, the
more certain you are about the true means of the arms, but the less time you
have to pull the best arm. This captures our intuition of exploring and
exploiting: the knowledge you gain from exploring is good, but only if you
manage to exploit that knowledge.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;TODO (questions for author): How much better is Greedy(N) than random? What is the optimal N?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It would be good if we had some measure of not just the mean, but also how
&lt;em&gt;certain&lt;/em&gt; we were of our estimate of the mean. If I flip a coin 10 times and get
1 head and 9 tails, I am much less certain of its fairness as if I were to flip
that coin 500 times and get 50 heads and 450 tails.&lt;/p&gt;
&lt;p&gt;It turns out that measure does exist, and it&#39;s called ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The beta distribution&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The beta distribution can best be thought of as &amp;quot;a distribution of probabilities
--- that is, it represents all the possible values of a probability when we
don&#39;t know what that probability is.&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stats.stackexchange.com/questions/47771/what-is-the-intuition-behind-beta-distribution&quot;&gt;This Stats.SE thread entitled &amp;quot;What is the intuition behind beta
distribution&amp;quot;&lt;/a&gt;
has loads of fantastic answers, and it&#39;s where I got that explanation from. I
would certainly recommend reading through David Robinson&#39;s answer.&lt;/p&gt;
&lt;p&gt;Here&#39;s how I would explain it:&lt;/p&gt;
&lt;p&gt;We know that the treatments are Bernoulli with parameter &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Then in &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;N&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
repeated trials the treatments must follow a binomial distribution with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;N&lt;/mi&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B(N,
p)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Suppose we conduct N trials and observe &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; successes and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
failures. Then the beta distribution &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Beta(\alpha+1, \beta+1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; gives us the
&lt;em&gt;range&lt;/em&gt; of &amp;quot;reasonable estimates&amp;quot; of the binomial distribution parameter &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/thompson-sampling/beta_distribution_1.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This image by Raffael Vogler very nicely shows why a beta distribution gives us
what we want. We wanted a measure of the mean but also a measure of our
certainty that the mean is what we think it is. Here we can see that while the
orange curve has a higher mean (0.9), our &amp;quot;best estimate&amp;quot; of its true value is
quite diffuse. On the other hand, we&#39;re quite sure that true value of the
second curve (in yellow) lies close to 0.8.&lt;/p&gt;
&lt;p&gt;Furthermore, the beta distribution has a lovely property in that we can
&amp;quot;update&amp;quot; the beta distribution very easily as we get more data. Suppose we have
2 heads and 8 tails: the beta distribution is &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;9&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Beta(3, 9)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. We flip the coin
again. It comes up heads. Then the beta distribution easily updates to
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;4&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;10&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Beta(4,10)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Armed with this knowledge of beta-distributions, we can try the following strategy.&lt;/p&gt;
&lt;p&gt;Can we do better? Let&#39;s try the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&amp;quot;Smart&amp;quot; beta-Greedy: At every time step, calculate &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.1667em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; of every arm,
then pull the arm with the highest &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.1667em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and update the
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.1667em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; according to the result.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How &amp;quot;Smart&amp;quot; beta-Greedy works: Initialise each arm with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;double-struck&quot;&gt;E&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mn&gt;0.5&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta} =
\mathbb{E}[Beta(1, 1)] = 0.5&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.1667em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathbb&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)]&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Beta(1,1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; distribution is a uniform
distribution over [0,1], and is what&#39;s known as an &lt;em&gt;uninformative prior&lt;/em&gt;: we
assume that all rewards are equally likely.&lt;/p&gt;
&lt;p&gt;At the start, seeing that all thetas are equal, we pull an arm at random;
call this arm &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;k&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. We update &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta_k}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1079em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.25em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; appropriately.&lt;/p&gt;
&lt;p&gt;We update as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If we do get a reward: &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(\alpha_k, \beta_k) = (\alpha_k+1, \beta)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0037em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0037em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;If we do not get a reward: &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(\alpha_k, \beta_k) = (\alpha_k, \beta+1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0037em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0037em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, pick the best &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.1667em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, which is given by
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{\alpha_k}{(\alpha_k + \beta_k}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.2373em;vertical-align:-0.52em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7173em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen mtight&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3488em;margin-left:-0.0037em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1512em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3488em;margin-left:-0.0528em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1512em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4159em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3488em;margin-left:-0.0037em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1512em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.52em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Repeat this process.&lt;/p&gt;
&lt;p&gt;This greedy algorithm is smarter than &amp;quot;dumb&amp;quot; greedy, because it constantly
reevaluates what the best arm is with our new beta updating rule. This is
pretty good, right?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Can we do better?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Take a look at this image from &lt;em&gt;A Tutorial on Thompson Sampling&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/thompson-sampling/beta_distribution_2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are three possible arms. The greedy algorithm would always choose action
1, because action 1 has the maximal expected mean reward. &amp;quot;Since the
uncertainty around this expected mean reward is small, observations are
unlikely to change the expectation substantially, and therefore, action 1 is
likely to be selected &lt;em&gt;ad ininitum&lt;/em&gt;.&amp;quot;&lt;/p&gt;
&lt;p&gt;It seems reasonable to avoid action 2, since it is extremely unlikely that
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta_2 &amp;gt; \theta_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, but the algorithm should try out &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mn&gt;3&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta_3&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, because
if you take a look at that distribution in red it&#39;s quite plausible that its
mean reward exceeds 0.6. &amp;quot;The algorithm fails to account for uncertainty in the
mean reward of action 3, which should entice the agent to explore and learn
about that action.&amp;quot; (p. 10-11)&lt;/p&gt;
&lt;p&gt;Let&#39;s try and capture some intuition here. The problem with &amp;quot;Smart&amp;quot; Greedy is
that it can be misled by an initial lucky or unlucky streak, and get stuck in a
suboptimal maxima of exploitation. We could modify &amp;quot;Smart&amp;quot; Greedy to pull every
arm N times first, just like &amp;quot;Dumb&amp;quot; Greedy(N), but here&#39;s another way to do it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;ε-Greedy -- like &amp;quot;Smart&amp;quot; Greedy, but with probability &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ϵ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\epsilon&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ϵ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; pull an
arm at random.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The ε-greedy algorithm takes the best action most of the time, but does random
exploration occasionally. This will prevent the algorithm from getting &amp;quot;stuck&amp;quot;
on a local optima: 5% of the time it will try action 3, for instance, and learn
more about it. Eventually the ε-greedy algorithm will converge onto the best
action.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;TODO (questions for author): How good is ε-Greedy compared to Smart Greedy?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But again ε-greedy is not optimal for two reasons. First, if we&#39;re already dead
certain about the best lever, we don&#39;t want it to pull a random bad lever ε of
the time! Second of all, it wastes pulls exploring arms we&#39;re already certain
about. In this case we want to explore action 3, and we don&#39;t want to explore
action 1 at all. Yet the ε-greedy algorithm will select action 1 and 3 with
equal probability.&lt;/p&gt;
&lt;p&gt;This is suboptimal. We need something that intelligently allocates exploratory
effort: go where your estimates are the most uncertain. Can we do better?
Enter...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thompson sampling&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Thompson sampling is a very subtle modification of the &amp;quot;smart&amp;quot; greedy
algorithm: so subtle, in fact, that I missed it the first time! Here&#39;s the
difference: instead of choosing the highest expected theta value, &lt;em&gt;sample&lt;/em&gt; the
theta values from the beta distributions.&lt;/p&gt;
&lt;p&gt;Take a look at the image again:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/thompson-sampling/beta_distribution_2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The expected rewards are &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mn&gt;0.6&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;0.4&lt;/mn&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mn&gt;0.4&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\theta = [0.6, 0.4, 0.4]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The greedy algorithm
selects the action with the highest expected reward: that is, action 1.
Thompson sampling &lt;em&gt;samples&lt;/em&gt; from the beta distributions: in other words,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;msub&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;mo&gt;∼&lt;/mo&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{\theta_k} \sim Beta(\alpha_k, \beta_k)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1079em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.25em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∼&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0037em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0528em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. It then pulls the arm with the
maximum sampled reward.&lt;/p&gt;
&lt;p&gt;This is genius! Why? Consider a typical sample. Sampling action 1 will give us
a value very close to 0.6. Sampling action 2 will give us a value very close to
0.4. Sampling action 3, on the other hand, will give us a wide range of values,
&lt;em&gt;including&lt;/em&gt; values greater than 0.6. This means that action 2 will pretty much
never be chosen, but there&#39;s a good chance of action 3 being chosen! In other
words --- Thompson sampling nicely directs exploration effort towards the
unknown.&lt;/p&gt;
&lt;p&gt;I ran 10,000 simulations, and here are the results...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bayesian inference vs frequentist inference&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Once I have the results ....&lt;/p&gt;
&lt;p&gt;I can use &lt;a href=&quot;https://en.wikipedia.org/wiki/Fisher&#39;s_exact_test&quot;&gt;Fisher&#39;s exact
test&lt;/a&gt; or the normal approximation to the binomial distribution.&lt;/p&gt;
&lt;p&gt;By the CLT, we know that all three treatments must be normally distributed.&lt;/p&gt;
&lt;p&gt;Bayesian inference: there is a closed form, but I can use simulation to compare
the three beta distributions:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mathoverflow.net/q/90361&quot;&gt;Given several beta distributions, what is the probability that one is the
highest?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A paper from NIPS 2011 (&amp;quot;An empirical evaluation of Thompson Sampling&amp;quot;) shows, in experiments, that Thompson Sampling beats UCB. UCB is based on choosing the lever that promises the highest reward under optimistic assumptions (i.e. the variance of your estimate of the expected reward is high, therefore you pull levers that you don&#39;t know that well). Instead, Thompson Sampling is fully Bayesian: it generates a bandit configuration (i.e. a vector of expected rewards) from a posterior distribution, and then acts as if this was the true configuration (i.e. it pulls the lever with the highest expected reward). &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Call the different SMS treatments A, B, and C, and the probability of someone
installing the app $$r$$ can be conditional on either one of these treatments.
The &lt;em&gt;value&lt;/em&gt; of each treatment &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Q&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mo&gt;⋅&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Q(\cdot)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;⋅&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the expected reward given that
treatment, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Q&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi mathvariant=&quot;double-struck&quot;&gt;E&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∣&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Q(A) = \mathbb{E}[r|A]&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathbb&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∣&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A little wrinkle&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.evanmiller.org/bayesian-ab-testing.html#notes&quot;&gt;Formulas for Bayesian A/B Testing&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Why do I use Bayesian methods?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Frequentist approaches require me to set sample size for adequate power, and
this sample size depends on effect size. But I have no good prior for effect
size&lt;/li&gt;
&lt;li&gt;Sample size large&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Contextual bandits&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Agarwal 2013 &lt;a href=&quot;http://proceedings.mlr.press/v28/agrawal13.pdf&quot;&gt;Thompson Sampling for Contextual Bandits with Linear
Payoffs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Top-two Thompson Sampling for Best-Arm Identification&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://arxiv.org/pdf/1602.08448.pdf&quot;&gt;Simple Bayesian Algorithms for Best-Arm Identification&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now suppose we have&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Here I should clarify --- suboptimal &lt;em&gt;for what&lt;/em&gt;? For a scientific experiment where the goal is to discover a fact about the world, then we shouldn&#39;t care about exploitation at all. We want the highest possible statistical power, and that means maximising exploration. But of course in this case where money is on the line, some balance of exploration and exploitation must be struck. &lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Pedro A. Ortega (https://stats.stackexchange.com/users/9572/pedro-a-ortega), Best bandit algorithm?, URL (version: 2017-03-24): https://stats.stackexchange.com/q/24027 &lt;a href=&quot;https://lieuzhenghong.com/2019/07/12/bayesian-inference-thompson-sampling-and-the-mab/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>A gentle introduction to the IS-PC-MR model</title>
    <link href="https://lieuzhenghong.com/2019/04/21/A-gentle-introduction-to-the-IS-PC-MR-model/"/>
    <updated>2019-04-21T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/04/21/A-gentle-introduction-to-the-IS-PC-MR-model/</id>
    <content type="html">&lt;style&gt;
	.question-box {
		display:flex;
		justify-content: center;
		flex-wrap: wrap;
		background-color: yellow;
		padding: 10px;
	}
	.question-box p {
	}

	table {
		border: 1px solid black;
		border-collapse: collapse;
	}
	table td {
		text-align: center;
		border: 1px dashed black;
		padding: 5px;
	}

	.fig-compare {
		display: flex;
		flex-wrap: wrap;
	}
&lt;/style&gt;
&lt;p&gt;&lt;strong&gt;TODO: work-in-progress.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction-and-topics-covered&quot; tabindex=&quot;-1&quot;&gt;Introduction and topics covered&lt;/h2&gt;
&lt;p&gt;Here I go through the IS-PC-MR model we learned in the first two lessons of Core Macro.&lt;/p&gt;
&lt;p&gt;I want to be very explicit on the microfoundations: no handwaving here. For instance, I go into detail about how the PC derives from the relative steepness of the WS and PS curves.&lt;/p&gt;
&lt;p&gt;Finally, we look at how the model works in practice.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is the IS curve?&lt;/li&gt;
&lt;li&gt;What is the ES, WS, MPL, PS?&lt;/li&gt;
&lt;li&gt;What is the PC?&lt;/li&gt;
&lt;li&gt;What is the central bank&#39;s loss function?&lt;/li&gt;
&lt;li&gt;What is the MR and how is it derived from the central bank loss function?&lt;/li&gt;
&lt;li&gt;a, &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;What is a supply shock?&lt;/li&gt;
&lt;li&gt;What is a demand shock?&lt;/li&gt;
&lt;li&gt;How the central bank responds to a supply shock&lt;/li&gt;
&lt;li&gt;How the central bank responds to a demand shock&lt;/li&gt;
&lt;li&gt;How the central bank can do better if it expects the shock&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;assumptions-of-the-model&quot; tabindex=&quot;-1&quot;&gt;Assumptions of the model&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;We have an economy with diminishing returns. (MPL, ES)&lt;/li&gt;
&lt;li&gt;The economy is made up purely of labourers and companies. Companies pay labourers wages, then produce goods, which labourers consume.&lt;/li&gt;
&lt;li&gt;We have some market power in both the labour supply and labour
demand markets. (WS, PS)&lt;/li&gt;
&lt;li&gt;Changing interest rates affects consumption decisions and thus
affects future output. (IS)&lt;/li&gt;
&lt;li&gt;Output gap affects inflation due to WS/PS curves (PC)&lt;/li&gt;
&lt;li&gt;Central bank operates with a loss function (MR)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-is-curve&quot; tabindex=&quot;-1&quot;&gt;The IS curve&lt;/h2&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;IS: y*t - y_e = a(r*{t-1} - r_e)
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6597em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6984em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;microfoundations&quot; tabindex=&quot;-1&quot;&gt;Microfoundations&lt;/h3&gt;
&lt;p&gt;We begin with the IS curve. The IS curve says that output deviates from long-run output &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;y_e&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; depending on the deviation of &lt;em&gt;last period&#39;s&lt;/em&gt; interest rate.&lt;/p&gt;
&lt;p&gt;A change in interest rates affect the output of the economy. Specifically, they affect consumption and investment decisions. (assumption 4). How does this work?&lt;/p&gt;
&lt;p&gt;Consider this: you&#39;re a consumer, and you want to consume. &lt;em&gt;Ceteris paribus&lt;/em&gt;, if interest rates are low (or even negative), then you would want to consume as much as you can. On the other hand, if interest is high, you&#39;d want to reduce consumption and save more now to spend more in the future.&lt;/p&gt;
&lt;p&gt;Higher interest rates also affect investment decisions. if you were a company wanting to build a new plant, you&#39;d have to borrow money to do it. If the interest rate was high, it&#39;s very &lt;em&gt;bohua&lt;/em&gt;; you&#39;d rather keep the money.&lt;/p&gt;
&lt;p&gt;And because &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Y = (C+I+G)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7667em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, both investment and consumption affect output.&lt;/p&gt;
&lt;p&gt;Note the &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t-1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6984em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; subscript on the interest rate: this is because central banks&#39;
interest rates only affect the economy with a lag. This is because investment
decisions today have been made some time in the past, and aren&#39;t affected by
current interest rates. Current interest rates only factor into deciding
&lt;em&gt;future&lt;/em&gt; investment/output.&lt;/p&gt;
&lt;h2 id=&quot;the-es%2C-ws%2C-ps-and-mpl-curves&quot; tabindex=&quot;-1&quot;&gt;The ES, WS, PS and MPL curves&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;ES: upward-sloping
WS: upward-sloping, higher than ES
MPL: downward-sloping due to diminishing returns
PS: downward-sloping, lower than MPL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ES, WS, PS and MPL pin down the level of real wages at a certain level of output.&lt;/p&gt;
&lt;p&gt;In a competitive labour market, the demand for labourers is given
by the MPL. The supply is given by individuals&#39; utility functions, but we shan&#39;t go into that here.&lt;/p&gt;
&lt;p&gt;The intersection of &lt;em&gt;employment supply&lt;/em&gt; (ES) and &lt;em&gt;employment demand&lt;/em&gt; (MPL)
is the equilibrium level of employment in a competitive market. Note that
employment demand is downward sloping due to diminshing returns (see
assumption 1).&lt;/p&gt;
&lt;p&gt;However, in this model, participants have market power (assumption 3).
Labour unions can sign labour contracts that give them wages above the
competitive wage. This is called the &lt;em&gt;wage-setting curve&lt;/em&gt; (WS) that lies above the ES curve.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/ws_curve.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Similarly, there is a &lt;em&gt;price-setting curve&lt;/em&gt; (PS) that lies below the MPL
curve. The intersection of these two curves is the equilibrium level of employment&lt;/p&gt;
&lt;h3 id=&quot;involuntary-and-voluntary-employment&quot; tabindex=&quot;-1&quot;&gt;Involuntary and voluntary employment&lt;/h3&gt;
&lt;p&gt;Voluntary unemployment: people who are not willing to work at the prevailing market wage
Involuntary unemployment: people who are willing to work at the prevailing market wage, but cannot due to the fact that the labour unions have priced them above that.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No involuntary unemployment if workers have no market power&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/voluntary_and_involuntary_unemployment.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;effect-on-wages-ambiguous&quot; tabindex=&quot;-1&quot;&gt;Effect on wages ambiguous&lt;/h3&gt;
&lt;p&gt;The effect on wages is ambiguous. It depends on the relative slopes of the WS and PS curves.&lt;/p&gt;
&lt;p&gt;Compare these two images.&lt;/p&gt;
&lt;div class = &quot;fig-compare&quot;&gt;
	&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/ws_ps_curve.png&quot;&gt;
	&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/ws_ps_curve_2.png&quot;&gt;
&lt;/div&gt;
&lt;p&gt;In the figure on the left, the competitive equilibrium&#39;s wage w* lies above the wage that was gotten in the noncompetitive equilibrium. In the figure on the right, the reverse is true.&lt;/p&gt;
&lt;h2 id=&quot;the-pc-curve&quot; tabindex=&quot;-1&quot;&gt;The PC curve&lt;/h2&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;E&lt;/mi&gt;&lt;/msubsup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PC: \pi_t = \pi_t^E + \alpha(y_t - y_e)
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1383em;vertical-align:-0.247em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8913em;&quot;&gt;&lt;span style=&quot;top:-2.453em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0576em;&quot;&gt;E&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.247em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the case of adaptive expectations,&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mo&gt;:&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PC: \pi*t = \pi*{t-1} + \alpha(y_t - y_e)
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6151em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 id=&quot;microfoundations-1&quot; tabindex=&quot;-1&quot;&gt;Microfoundations&lt;/h3&gt;
&lt;p&gt;The Phillips curve is gotten by the interaction of the WS and PS curves. The Phillips curve states that inflation in this period equals &lt;em&gt;expected&lt;/em&gt; inflation this period, plus a shock from the output gap. But why would the output gap affect inflation? We use the WS and PS curves to explain.&lt;/p&gt;
&lt;p&gt;With the WS and PS curves in place, we can begin to understand the Phillips curve.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/deriving_the_pc_curve.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The figure illustrates. Suppose we want to raise output from Y* to Y&#39;. Well, two things will happen:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Labourers will demand higher wages to work more&lt;/li&gt;
&lt;li&gt;Due to diminishing returns, MPL will fall: companies are willing to pay less.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Labourers will demand more to work. They&#39;ll want a real wage increase of $$\theta$$ (in &lt;span style=&quot;color:red&quot;&gt;red&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;The companies pay that wage. But they have the last laugh---they simply set the price of their goods higher, so that they make the same profit! Specifically prices will go up such that labourers&#39; real wages are eroded like so.&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;msup&gt;&lt;mrow&gt;&lt;/mrow&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;γ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^{&amp;#x27;} = w^* = \theta - \gamma 
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9925em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9925em;&quot;&gt;&lt;span style=&quot;top:-2.9925em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5795em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8278em;&quot;&gt;&lt;span style=&quot;top:-2.931em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7387em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7387em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mbin mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0556em;&quot;&gt;γ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;(remember from assumption 2 the economy is made up completely of
companies and labourers, and labourers buy the goods the companies
produce)&lt;/p&gt;
&lt;p&gt;Therefore, prices go up == inflation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The coefficient $$\alpha$$ in the PC depends on the &lt;em&gt;relative steepness&lt;/em&gt; of the WS and PS curves.&lt;/strong&gt; The steeper both of them are, the larger the gap between the two curves, the larger the coefficient, and the steeper the PC will be.&lt;/p&gt;
&lt;h2 id=&quot;the-mr-curve&quot; tabindex=&quot;-1&quot;&gt;The MR curve&lt;/h2&gt;
&lt;p&gt;Central bank&#39;s loss function:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;L = (y - y_T)^2 + (\pi - \pi_T)^2
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The MR is the central bank&#39;s best response to the Phillips curve. That is to say, it solves the optimisation problem&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msub&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;&lt;mi&gt;s&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mrow&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;L = (y - y_T)^2 + (\pi - \pi_T)^2 s.t. \pi*t = \pi*{t-1} + (y_t - y_e)
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6151em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4653em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7278em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So we substitute the PC into the loss function, differentiate, and
rearrange to obtain&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mi&gt;T&lt;/mi&gt;&lt;/msup&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pi = \pi^T - \frac{y_t-y_e}{\alpha \beta}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9747em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8913em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.1389em;&quot;&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.1408em;vertical-align:-0.8804em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.2603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2806em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1514em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8804em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;a%2C-alpha-and-beta&quot; tabindex=&quot;-1&quot;&gt;a, alpha and beta&lt;/h2&gt;
&lt;p&gt;a : Found in the IS curve. Measures how responsive the economy is to interest rate changes. - For instance, economies credit-constrained consumers will have higher a.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Found in the Phillips curve. It measures the relative steepness of the WS and PS curves. - Stronger labour unions or firms with more market power increase &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Found in the central bank&#39;s loss function. Measures how inflation-averse a bank is (how much output it&#39;s willing to give up in order to decrease inflation). - A more inflation-averse central bank will increase &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-effect-of-these-coefficients-on-mr&quot; tabindex=&quot;-1&quot;&gt;The effect of these coefficients on MR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Makes MR less steep. A highly inflation-averse CB (high &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) is going to be willing to cut a lot of output to decrease a little bit of inflation. At the limit, where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;β&lt;/mi&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;∞&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\beta \to \infty&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0528em;&quot;&gt;β&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∞&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, the MR is a straight line: the CB will literally do anything to prevent any deviation of inflation from target.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: Makes MR less steep. A greater &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; means that a small change in output gives a huge change in inflation (remember that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;mo&gt;∝&lt;/mo&gt;&lt;mi&gt;θ&lt;/mi&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mi&gt;γ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha \propto \theta + \gamma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;∝&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7778em;vertical-align:-0.0833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;θ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0556em;&quot;&gt;γ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. So the CB gets more &amp;quot;bang for your buck&amp;quot;: it&#39;s thus very willing to adjust output in order to reduce inflation, because it can do it relatively cheaply.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But note that the effect of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;α&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\alpha&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0037em;&quot;&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; on policy path is ambiguous&lt;/p&gt;
&lt;h2 id=&quot;supply-shocks&quot; tabindex=&quot;-1&quot;&gt;Supply shocks&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;p&gt;Supply shocks are cost-push shocks. They affect the PC curve.&lt;/p&gt;
&lt;p&gt;Let&#39;s examine the case of a temporary positive supply shock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/supply_shock.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7651em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The economy is at steady-state with &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;mtext&gt;and &lt;/mtext&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Y = Y^{*}, \pi = \pi^{*}, \text{and } r = r^{*}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8831em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt;and &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. A supply shock causes prices of goods to increase unexpectedly. The PC moves up from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PC_0 \to PC_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Immediately, the central bank raises rates from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;r^{*} \to r_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0278em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; in order to cut output to Y_1. But as monetary policy operates with a lag, this change doesn&#39;t take effect until the next period.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7651em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The PC remains elevated at &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PC_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. But the interest rate now takes effect and causes output to fall from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Y^{*} \to Y_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.2222em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mtext&gt; onwards&lt;/mtext&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_2 \text{ onwards}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt; onwards&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The PC falls from PC_1 to PC_2. The central bank lowers rates slightly. There is a protracted adjustment of interest rates and output back to their equilibrium values.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;demand-shocks&quot; tabindex=&quot;-1&quot;&gt;Demand shocks&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;p&gt;Demand shocks affect the IS curve.&lt;/p&gt;
&lt;p&gt;Let&#39;s examine the case of a temporary positive demand shock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/is-pc-mr_explained/demand-shock.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_0&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7651em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The economy is in eqm. A positive temporary demand shock hits, causing the IS to shift from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;msup&gt;&lt;mi&gt;S&lt;/mi&gt;&lt;msup&gt;&lt;mrow&gt;&lt;/mrow&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;IS \rightarrow IS^{&amp;#x27;}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9425em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0785em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0576em;&quot;&gt;S&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9425em;&quot;&gt;&lt;span style=&quot;top:-2.9425em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5795em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8278em;&quot;&gt;&lt;span style=&quot;top:-2.931em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Inflation rises to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pi_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The central bank immediately hikes rates to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;msup&gt;&lt;mrow&gt;&lt;/mrow&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;r^{&amp;#x27;}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9425em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0278em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9425em;&quot;&gt;&lt;span style=&quot;top:-2.9425em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5795em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8278em;&quot;&gt;&lt;span style=&quot;top:-2.931em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, but as monetary policy operates with a lag, this change doesn&#39;t take effect until the next period.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7651em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. The IS curve goes back to normal, but due to higher inflation expectations the PC shifts upwards to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;C&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;PC_1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0715em;&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0715em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Due to the central bank&#39;s hiked rates, however, inflation decreases from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/msub&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;π&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\pi_1 \rightarrow \pi_2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5806em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;π&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0359em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msub&gt;&lt;mtext&gt; onwards&lt;/mtext&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;t_2 \text{ onwards}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8444em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3011em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord text&quot;&gt;&lt;span class=&quot;mord&quot;&gt; onwards&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. There is a protracted adjustment of interest rates and output back to their equilibrium values.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;how-the-central-bank-can-do-better-if-it-expects-the-shock&quot; tabindex=&quot;-1&quot;&gt;How the central bank can do better if it expects the shock&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;p&gt;If the central bank expects the shock, it can cut/hike rates one period before the shock. The moment the shock hits, output is already stabilised --- as though the shock never existed.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Explaining Acemoglu&#39;s model of directed technical change: a primer</title>
    <link href="https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/"/>
    <updated>2019-04-20T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/</id>
    <content type="html">&lt;style&gt;
	.question-box {
		display:flex;
		justify-content: center;
		flex-wrap: wrap;
		background-color: yellow;
		padding: 10px;
	}
	.question-box p {
	}

	table {
		border: 1px solid black;
		border-collapse: collapse;
	}
	table td {
		text-align: center;
		border: 1px dashed black;
		padding: 5px;
	}
&lt;/style&gt;
&lt;h2 id=&quot;table-of-contents&quot; tabindex=&quot;-1&quot;&gt;Table of contents&lt;/h2&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Introduction and nontechnical explanation of the paradox&lt;/li&gt;
&lt;li&gt;We can solve the paradox by directed technical change&lt;/li&gt;
&lt;li&gt;But why would technical change be directed? Market effects&lt;/li&gt;
&lt;li&gt;Implications of the model, and comparisons to other models:
&lt;ul&gt;
&lt;li&gt;Schumpeterian-Solow model&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;introduction-and-nontechnical-explanation&quot; tabindex=&quot;-1&quot;&gt;Introduction and nontechnical explanation&lt;/h2&gt;
&lt;p&gt;I first want to begin with a seeming paradox. Call this &lt;strong&gt;The Paradox&lt;/strong&gt;.
Consider these two facts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The number of highly-skilled workers has increased greatly over the past few
decades.&lt;/li&gt;
&lt;li&gt;The skill premium&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; has increased despite a huge increase in high-skilled
workers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This seems counterintuitive. We know the labour market is determined by supply
and demand. Therefore, it seems like the skill premium should decrease. We
must conclude that something is making the skill premium go up despite the
large influx of high-skilled workers.&lt;/p&gt;
&lt;p&gt;What could it be? The answer is &lt;strong&gt;directed technical change&lt;/strong&gt;: despite the fact
that there are much more high-skilled workers nowadays, high-skilled workers
have become much more productive than low-skilled ones, and therefore they
command a higher wage.&lt;/p&gt;
&lt;p&gt;But why have high-skilled workers become much more productive than low-skilled
ones? Here&#39;s one possibility.&lt;/p&gt;
&lt;h3 id=&quot;the-nature-of-technological-progress-this-few-decades-(e.g.-computer%2C-microchips)-has-been-more-suited-for-high-skilled-workers.&quot; tabindex=&quot;-1&quot;&gt;The nature of technological progress this few decades (e.g. computer, microchips) has been more suited for high-skilled workers.&lt;/h3&gt;
&lt;p&gt;At first glance, this explanation seems plausible. But if you think about it,
it falls apart. See Acemoglu:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;At the expense of oversimplifying, we can say that the microchip could have
been used to develop advanced scanners that would increase the productivity of unskilled workers, or advanced computer-assisted machines that would be used by skilled workers to replace unskilled workers. (p.31)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, technology itself does not confer disproportionate benefits on
either group: what matters are the innovations that build upon that
technological breakthrough.&lt;/p&gt;
&lt;h3 id=&quot;the-large-increase-in-the-number-of-high-skilled-workers-has-made-it-more-profitable-for-innovators-to-develop-technologies-that-boost-their-productivity.&quot; tabindex=&quot;-1&quot;&gt;The large increase in the number of high-skilled workers has made it more profitable for innovators to develop technologies that boost their productivity.&lt;/h3&gt;
&lt;p&gt;The real reason for directed technical change is actually a &lt;strong&gt;market size
effect&lt;/strong&gt;. Innovators focus their efforts on developing technologies that
maximise their profit, and how much they can sell their R&amp;amp;D for depends on how
many people use their technology. The more high-skilled workers there are, the
more innovators develop for them, and the larger their productivity grows. This
nicely turns the supply-and-demand story on its head, and gives us our answer
to the paradox.&lt;/p&gt;
&lt;p&gt;Here, I present Acemoglu&#39;s model of directed technical change, that formalises
all we&#39;ve just talked about. Why Acemoglu&#39;s model specifically?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It is the only model in Oxford&#39;s macroeconomics course that talks about
directed technical change/ high- vs low-skilled workers.&lt;/li&gt;
&lt;li&gt;It nicely explains &lt;strong&gt;The Paradox&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#39;question-box&#39;&gt;
&lt;p&gt;&lt;b&gt; Review questions &lt;/b&gt;&lt;/p&gt;
&lt;p&gt; What was the empirical motivation for Acemoglu&#39;s model of directed technological change? &lt;/p&gt;
&lt;p&gt; How can the skill premium go up even as the relative supply of high-skilled workers goes up?&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;formalising-the-paradox&quot; tabindex=&quot;-1&quot;&gt;Formalising the paradox&lt;/h2&gt;
&lt;p&gt;The production function, as well as our utility function, is given by&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Y = [(A_H H)^\rho + (A_L L)^\rho]^{1-\rho}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7144em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7144em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;There are high-skilled goods produced by high-skilled labour, and low-skilled
goods produced by low-skill labour. We will ignore capital. Note here that this
is a CRS production function.&lt;/p&gt;
&lt;p&gt;We shall first disregard the technology growth function (how &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_L&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; change over time).&lt;/p&gt;
&lt;p&gt;Because this is a competitive market, workers are paid their marginal productivities:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;[&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;mo fence=&quot;true&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w_L \equiv MPL = A^\rho_L \left[A^\rho_L + A^\rho_H\left(\frac{H}{L}\right)^\rho\right]^\frac{1-\rho}{\rho}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6138em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.8531em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.5043em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.9031em;&quot;&gt;&lt;span style=&quot;top:-4.2572em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9227em;&quot;&gt;&lt;span style=&quot;top:-2.656em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2255em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line mtight&quot; style=&quot;border-bottom-width:0.049em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4624em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4829em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;[&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;msubsup&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msubsup&gt;&lt;mo fence=&quot;true&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w_H \equiv MPH = A^\rho_H \left[A^\rho_L \left(\frac{H}{L}\right)^{-\rho} + A^\rho_H\right]^\frac{1-\rho}{\rho}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6138em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:3.3988em;vertical-align:-1.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size4&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.6112em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7823em;&quot;&gt;&lt;span style=&quot;top:-2.4065em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.1809em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.2935em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size4&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:2.1488em;&quot;&gt;&lt;span style=&quot;top:-4.5029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9227em;&quot;&gt;&lt;span style=&quot;top:-2.656em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2255em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line mtight&quot; style=&quot;border-bottom-width:0.049em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4624em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4829em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Combining these two equations we get the &lt;em&gt;skill premium&lt;/em&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \equiv \frac{w_H}{w_L} = \left(\frac{A_H}{A_L}\right)^\rho \left(\frac{H}{L}\right)^{-(1-\rho)}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4637em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.9436em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.1076em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.6779em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.5043em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.7279em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mopen mtight&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;span class=&quot;mclose mtight&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;= \left(\frac{A_H}{A_L}\right)^{(\sigma-1)/\sigma} \left(\frac{H}{L}\right)^{-(\frac{1}{\sigma})}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.744em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.7279em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen mtight&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mclose mtight&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.7939em;&quot;&gt;&lt;span style=&quot;top:-4.2029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mopen mtight&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8443em;&quot;&gt;&lt;span style=&quot;top:-2.656em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2255em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line mtight&quot; style=&quot;border-bottom-width:0.049em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.384em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.344em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose mtight&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;where &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is the elasticity of substitution&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma \equiv \frac{1}{1-\rho}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4637em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.2019em;vertical-align:-0.8804em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8804em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Taking logs on both sides gives&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ln&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mfrac&gt;&lt;mi&gt;ln&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mfrac&gt;&lt;mi&gt;ln&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\ln \omega = \frac{\sigma-1}{\sigma} \ln(\frac{A_h}{A_l}) - \frac{1}{\sigma}\ln(\frac{H}{L})
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;ln&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.1963em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;ln&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.0463em;vertical-align:-0.686em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;ln&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s take a look at this last equation, and plot it in a graph with x-axis
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{H}{L}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.2173em;vertical-align:-0.345em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8723em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.345em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. We can see that as the number of skilled workers increases
(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;), the lower the wage premium.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/acemoglu_explained/wage_premium.png&quot; alt=&quot;An increase in skilled workers causes a decrease in the wage
premium&quot;&gt;&lt;/p&gt;
&lt;p&gt;An increase in skilled workers (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;msup&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo mathvariant=&quot;normal&quot; lspace=&quot;0em&quot; rspace=&quot;0em&quot;&gt;′&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;H^{*} \rightarrow H&amp;#x27;&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7519em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) leads
to a decrease in wage premium (movement from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mo&gt;→&lt;/mo&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A \rightarrow B&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;→&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;).&lt;/p&gt;
&lt;div class=&#39;question-box&#39;&gt;
	&lt;p&gt;&lt;b&gt; Review questions &lt;/b&gt;&lt;/p&gt;
	&lt;p&gt; What is the production function stated by Acemoglu?&lt;/p&gt;
	&lt;p&gt; What is the skill premium?&lt;/p&gt;
	&lt;p&gt; What is the elasticity of substitution? How does it relate to \(\rho\)? &lt;/p&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id=&quot;solving-the-paradox-by-directed-technical-change&quot; tabindex=&quot;-1&quot;&gt;Solving the paradox by directed technical change&lt;/h2&gt;
&lt;p&gt;We have just formalised the result that as the relative ratio of high-skilled
workers increases, the wage premium decreases. This is great, but how then can
we explain the empirical finding that the skill premium &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; has
increased over the decades? The answer is a combination of both elasticity of
substitution &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and a &lt;em&gt;skill-biased technical change&lt;/em&gt;. Looking once
again at the previous equation, we see that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; can increase if the term&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mfrac&gt;&lt;mi&gt;ln&lt;/mi&gt;&lt;mo&gt;⁡&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{\sigma-1}{\sigma} \ln(\frac{A_h}{A_l})
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.1963em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3214em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mop&quot;&gt;ln&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;increases.&lt;/p&gt;
&lt;p&gt;Under what circumstances will this term increase? Well, one way is to increase
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_h&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. But an increase in &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_h&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; will only increase this term if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt;
1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. If workers are not very substitutable (&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;lt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;), an improvement in
the productivity of skilled workers &lt;em&gt;reduces&lt;/em&gt; the skill premium. This case
appears paradoxical at first but is in fact quite intuitive. As Acemoglu says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider, for example, a Leontieff (fixed proportions) production function.
In this case, when &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_h&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; increases and skilled workers become more
productive, the demand for unskilled workers, who are necessary to produce
more output by working with the more productive skilled workers, increases by
more than the demand for skilled workers. In some sense, in this case, the
increase in &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_h&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is creating an “excess supply” of skilled workers given the
number of unskilled workers. This excess supply increases the unskilled wage
relative to the skilled wage.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay. So suppose &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. Then, an increase in &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_h&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; will indeed increase the wage premium by shifting the line upwards.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/acemoglu_explained/wage_premium_2.png&quot; alt=&quot;Skill-biased technology change can offset an increase in skilled labour,
causing the wage labour to increase&quot;&gt;&lt;/p&gt;
&lt;p&gt;Figure 2 illustrates. Despite the increase in H/L, skill-biased technology change causes
the wage premium to increase from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^*&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mbin mtight&quot;&gt;∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; to &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msup&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mrow&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;w^{**}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.6887em;&quot;&gt;&lt;span style=&quot;top:-3.063em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;∗∗&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Great---we have solved the paradox by introducing skill-biased technical
change. More explicitly, the relative productivity of skilled workers,&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mfrac&gt;&lt;/msup&gt;&lt;mo separator=&quot;true&quot;&gt;,&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;(A_h/A_l)^\frac{\sigma-1}{\sigma},
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.254em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.004em;&quot;&gt;&lt;span style=&quot;top:-3.413em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mopen nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8443em;&quot;&gt;&lt;span style=&quot;top:-2.656em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2255em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line mtight&quot; style=&quot;border-bottom-width:0.049em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.384em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.344em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter sizing reset-size3 size6&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mpunct&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;must have increased.&lt;/p&gt;
&lt;h2 id=&quot;acemoglu&#39;s-model-with-endogenous-directed-technical-change.&quot; tabindex=&quot;-1&quot;&gt;Acemoglu&#39;s model with endogenous directed technical change.&lt;/h2&gt;
&lt;p&gt;I&#39;ve just shown that one can have an increase in the ratio of high- to low-
skilled workers IF the coefficient of substitution &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; AND technical
change is directed towards high-skilled workers.&lt;/p&gt;
&lt;p&gt;But that begs the questions: why &lt;em&gt;was&lt;/em&gt; technical change directed towards
high-skilled workers? Now we attempt to &lt;em&gt;endogenise&lt;/em&gt; technical change (i.e.
try and find a reason &lt;em&gt;within&lt;/em&gt; the model why technical change was directed).&lt;/p&gt;
&lt;p&gt;We have our utility/production function once again:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;Y&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;[&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;mo&gt;+&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;msup&gt;&lt;mo stretchy=&quot;false&quot;&gt;]&lt;/mo&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;Y = [(A_H H)^\rho + (A_L L)^\rho]^{1-\rho}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.2222em;&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7144em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.1141em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mopen&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7144em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose&quot;&gt;&lt;span class=&quot;mclose&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8641em;&quot;&gt;&lt;span style=&quot;top:-3.113em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here, let&#39;s introduce some innovators. Innovators can produce innovations,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; or &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_L&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, that increase the productivity of all high- or low-skill
workers. Let the fixed cost of producing an innovation be B and let the
marginal cost of producing the new technology be 0. Then the marginal benefit
of providing a new technology is simply the marginal increase in productivity
(&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; or &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;L&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;) multiplied by the price of that good; this gives &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p_H H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; and
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p_L L&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; respectively.&lt;/p&gt;
&lt;p&gt;We can see that innovators will only choose to produce an innovation if they
stand to make a profit: in other words only when &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;B&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;B &amp;lt; p_H H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.7224em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0502em;&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Here, there are two factors that affect innovation: price and market size.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Price effect&lt;/strong&gt;: the larger the price of the good &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p_H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.625em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, the more profit
innovators stand to make.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Market size effect&lt;/strong&gt;: The more high- or low- skilled workers &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;H&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, the more
profit innovators stand to make.&lt;/p&gt;
&lt;p&gt;There is a further equilibrium condition. At equilibrium, the marginal benefit
of providing both high- and low- skilled technologies must be equal. Otherwise,
people would start developing more technologies of the other one to make more
profit.&lt;/p&gt;
&lt;p&gt;This gives us the following condition:&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;p_h H = p_l L
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8778em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;By consumer optimisation,&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{p_H}{p_L} = \frac{MU_H}{MU_L}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.988em;vertical-align:-0.8804em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.1076em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8804em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.1963em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;After all, consider the case where LHS &amp;gt; RHS. Then, it would be a Pareto improvement to
substitute 1 unit of H for 1 unit of L.&lt;/p&gt;
&lt;p&gt;But we know here that the production and utility functions are the same! Thus,&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;MU_H == MPH
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;msub&gt;&lt;mi&gt;U&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;mi&gt;M&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;.&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;MU_L = MPL.
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8333em;vertical-align:-0.15em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;U&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.109em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6833em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.109em;&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.1389em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Therefore, we can reuse the previous result&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;p&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;[&lt;/mo&gt;&lt;mfrac&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;]&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{p_H}{p_L} = \left [ \frac{A_H H}{A_L L} \right ] ^{\rho-1}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.988em;vertical-align:-0.8804em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.1076em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8804em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.604em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.654em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Substituting in the equilibrium condition, and replacing $$\sigma = 1/(1- \rho)$$
gives us&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{A_h}{A_l} = \left(\frac{H}{L}\right)^ {\sigma - 1}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.1963em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3361em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.604em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.654em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This gives the result that when &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, more technology will be
produced for the higher-skilled worker if H/L increases (i.e. the market size
effect dominates). In other words --- &lt;strong&gt;directed technical progress&lt;/strong&gt;! This is
something we previously assumed in the exogenous case, but now we have shown
how directed technical progress is in fact caused by a large supply of
high-skilled workers.&lt;/p&gt;
&lt;p&gt;Okay, we&#39;ve shown that if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, when &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{A_H}{A_L} \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3339em;vertical-align:-0.4453em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8886em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3567em;margin-left:0em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1433em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4103em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3567em;margin-left:0em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1433em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4453em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. But what about the skill premium?&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/msup&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mo stretchy=&quot;false&quot;&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;mo stretchy=&quot;false&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \equiv \frac{w_H}{w_L} = \left(\frac{A_H}{A_L}\right)^\rho \left(\frac{H}{L}\right)^{-(1-\rho)}
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4637em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.9436em;vertical-align:-0.836em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.1076em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:-0.0269em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.6779em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.836em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.5043em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.1667em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.7279em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mopen mtight&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;span class=&quot;mclose mtight&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Substituting the result we got for &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;h&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{A_h}{A_l}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3451em;vertical-align:-0.4509em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8942em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3488em;margin-left:0em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0197em;&quot;&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1512em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4159em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3488em;margin-left:0em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1512em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4509em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; into the equation, as well as the fact that &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;≡&lt;/mo&gt;&lt;mfrac&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;ρ&lt;/mi&gt;&lt;/mrow&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma \equiv \frac{1}{1-\rho}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4637em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;≡&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.3262em;vertical-align:-0.4811em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.8451em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;ρ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.394em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4811em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, we obtain&lt;/p&gt;
&lt;p class=&#39;katex-block&#39;&gt;&lt;span class=&quot;katex-display&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot; display=&quot;block&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mo&gt;=&lt;/mo&gt;&lt;msup&gt;&lt;mrow&gt;&lt;mo fence=&quot;true&quot;&gt;(&lt;/mo&gt;&lt;mfrac&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/mfrac&gt;&lt;mo fence=&quot;true&quot;&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;−&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;/msup&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;= \left(\frac{H}{L}\right)^{\sigma-2} 
&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.3669em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:2.604em;vertical-align:-0.95em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;minner&quot;&gt;&lt;span class=&quot;mopen delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.3603em;&quot;&gt;&lt;span style=&quot;top:-2.314em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.677em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.686em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose delimcenter&quot; style=&quot;top:0em;&quot;&gt;&lt;span class=&quot;delimsizing size3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:1.654em;&quot;&gt;&lt;span style=&quot;top:-3.9029em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mbin mtight&quot;&gt;−&lt;/span&gt;&lt;span class=&quot;mord mtight&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This result tells us that if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, then an increase in relative
supply of high-skilled workers increases the skill premium. Note that this is
different from the exogenous model. In the exogenous model, as long as $$\sigma &amp;gt; 1$$
both the level of skill-biased technology and the skill premium increase.
In the endogenous model, if &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1 &amp;lt; \sigma &amp;lt; 2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6835em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; the level of technology does
increase, but the skill premium actually decreases (the increase in supply
outweighs the increase in technology).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/acemoglu_explained/acemoglu_endogenous_sigma_1_2.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/acemoglu_explained/acemoglu_endogenous_sigma_2.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level of &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/th&gt;
&lt;th&gt;Exogenous model&lt;/th&gt;
&lt;th&gt;Endogenous model&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;0&lt;/mn&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;0 &amp;lt; \sigma &amp;lt; 1&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6835em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↓&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \downarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↓&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_L \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↓&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \downarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↓&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_L \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;lt;&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;1 &amp;lt; \sigma &amp;lt; 2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6835em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↓&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \downarrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↓&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;σ&lt;/mi&gt;&lt;mo&gt;&amp;gt;&lt;/mo&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\sigma &amp;gt; 2&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.5782em;vertical-align:-0.0391em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;σ&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.6444em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;msub&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;mo&gt;↑&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;A_H \uparrow&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3283em;&quot;&gt;&lt;span style=&quot;top:-2.55em;margin-left:0em;margin-right:0.05em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.7em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.15em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2778em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mrel&quot;&gt;↑&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;comparison-to-other-models&quot; tabindex=&quot;-1&quot;&gt;Comparison to other models&lt;/h2&gt;
&lt;p&gt;In the Schumpeter-Solow case, demand for innovation is gotten from &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{k}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.25em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,
level of capital per effective labour unit. The greater &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mover accent=&quot;true&quot;&gt;&lt;mi&gt;k&lt;/mi&gt;&lt;mo&gt;^&lt;/mo&gt;&lt;/mover&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\hat{k}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord accent&quot;&gt;&lt;span class=&quot;vlist-t&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.9579em;&quot;&gt;&lt;span style=&quot;top:-3em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0315em;&quot;&gt;k&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.2634em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;accent-body&quot; style=&quot;left:-0.25em;&quot;&gt;&lt;span class=&quot;mord&quot;&gt;^&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; is, the
more profit innovators stand to make.&lt;/p&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;TODO&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;The wage premium &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;ω&lt;/mi&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\omega&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.4306em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.0359em;&quot;&gt;ω&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, is defined as &lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mfrac&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;H&lt;/mi&gt;&lt;/msub&gt;&lt;msub&gt;&lt;mi&gt;w&lt;/mi&gt;&lt;mi&gt;L&lt;/mi&gt;&lt;/msub&gt;&lt;/mfrac&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;\frac{w_H}{w_L}&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1.157em;vertical-align:-0.4453em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;&lt;span class=&quot;mopen nulldelimiter&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mfrac&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.7117em;&quot;&gt;&lt;span style=&quot;top:-2.655em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3567em;margin-left:-0.0269em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot;&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1433em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.23em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;frac-line&quot; style=&quot;border-bottom-width:0.04em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;top:-3.4103em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:3em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size6 size3 mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0269em;&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;msupsub&quot;&gt;&lt;span class=&quot;vlist-t vlist-t2&quot;&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.3448em;&quot;&gt;&lt;span style=&quot;top:-2.3567em;margin-left:-0.0269em;margin-right:0.0714em;&quot;&gt;&lt;span class=&quot;pstrut&quot; style=&quot;height:2.5em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;sizing reset-size3 size1 mtight&quot;&gt;&lt;span class=&quot;mord mathnormal mtight&quot; style=&quot;margin-right:0.0813em;&quot;&gt;H&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.1433em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-s&quot;&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;vlist-r&quot;&gt;&lt;span class=&quot;vlist&quot; style=&quot;height:0.4453em;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;mclose nulldelimiter&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;. &lt;a href=&quot;https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;How do we get the elasticity of substitution?? How is it defined? TODO &lt;a href=&quot;https://lieuzhenghong.com/2019/04/20/Acemoglu-explained/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Building an automated, blockchain-connected model train diorama</title>
    <link href="https://lieuzhenghong.com/2019/01/31/building-a-blocktrain/"/>
    <updated>2019-01-31T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2019/01/31/building-a-blocktrain/</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;WIP&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/final_product.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Over the summer of 2018 (June-Aug 2018), I built an automated, blockchain-connected model train diorama and an accompanying visualisation. The diorama shows how changes in the locations of goods can be added in real-time to the blockchain, ensuring an immutable and unforgeable chain of provenance. This exhibit is also &lt;em&gt;interactive&lt;/em&gt;: members of the public can scan QR codes pasted on several shipping containers, and they&#39;ll see that good&#39;s location and history on their phones update in real time.&lt;/p&gt;
&lt;h1 id=&quot;why-a-blocktrain%3F&quot; tabindex=&quot;-1&quot;&gt;Why a blocktrain?&lt;/h1&gt;
&lt;p&gt;My boss was part of the group promoting industry adoption of blockchain. He wanted me to find some way to i) explain how the blockchain works, and ii) show how blockchain can be used in industry.&lt;/p&gt;
&lt;p&gt;I chose to showcase the supply chain, because this application is already being promoted by &lt;a href=&quot;https://www.ibm.com/blockchain/industries/supply-chain&quot;&gt;IBM&lt;/a&gt; and it would have more relevance to the industry experts my boss talks to.&lt;/p&gt;
&lt;p&gt;My boss was enamoured with the idea of a moving train, having seen a model train set at the Accenture HQ. So I had the task of finding out how to use a model train set to showcase the supply chain. After several iterations, I decided on the current diorama + blockchain visualisation.&lt;/p&gt;
&lt;h1 id=&quot;architecture&quot; tabindex=&quot;-1&quot;&gt;Architecture&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_1.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_2.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_3.png&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/final_product_annotated.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are four main components of this diorama:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hyperledger Blockchain and REST API (running on a DigitalOcean instance)&lt;/li&gt;
&lt;li&gt;Train diorama (controlled by a Raspberry Pi)&lt;/li&gt;
&lt;li&gt;Blockchain visualisation (running on the Raspberry Pi)&lt;/li&gt;
&lt;li&gt;Asset tracker (served by a DigitalOcean instance)&lt;/li&gt;
&lt;/ol&gt;
&lt;video width = &quot;100%&quot; controls&gt;
&lt;source src=&quot;https://files.lieu.gg/img/blockchain_project/in_action.MOV&quot;&gt;
&lt;/video&gt;
&lt;h1 id=&quot;blockchain-on-the-cloud&quot; tabindex=&quot;-1&quot;&gt;Blockchain on the cloud&lt;/h1&gt;
&lt;p&gt;I spun up a DigitalOcean instance to run the blockchain.&lt;/p&gt;
&lt;p&gt;Hyperledger Composer comes with its own REST API.&lt;/p&gt;
&lt;h2 id=&quot;blockchain-visualisation&quot; tabindex=&quot;-1&quot;&gt;Blockchain visualisation&lt;/h2&gt;
&lt;p&gt;The blockchain visualisation is written from scratch in HTML5 Canvas, and runs on the Raspberry Pi. It polls the Hyperledger REST API to check for updates.&lt;/p&gt;
&lt;p&gt;I made a nice animation whereupon new blocks slide in, giving the diorama a sense of dynamism.&lt;/p&gt;
&lt;h2 id=&quot;asset-tracker&quot; tabindex=&quot;-1&quot;&gt;Asset tracker&lt;/h2&gt;
&lt;p&gt;I wanted to make the diorama interactive so I created a&lt;/p&gt;
&lt;p&gt;People viewing the diorama can use their phones to scan the QR codes attached to several goods containers.&lt;/p&gt;
&lt;h1 id=&quot;building-the-diorama&quot; tabindex=&quot;-1&quot;&gt;Building the diorama&lt;/h1&gt;
&lt;h2 id=&quot;ideation&quot; tabindex=&quot;-1&quot;&gt;Ideation&lt;/h2&gt;
&lt;p&gt;I bought a $20 &lt;em&gt;Thomas the Train&lt;/em&gt; model train set just to figure out how the diorama would work. You can see the video of it here:&lt;/p&gt;
&lt;video width = &quot;100%&quot; controls&gt;
&lt;source src=&quot;https://files.lieu.gg/img/blockchain_project/thomas_the_train.mp4&quot;&gt;
&lt;/video&gt;
&lt;h2 id=&quot;starting-and-stopping-the-train&quot; tabindex=&quot;-1&quot;&gt;Starting and stopping the train&lt;/h2&gt;
&lt;p&gt;This was the hardest part of the project.&lt;/p&gt;
&lt;p&gt;I first tried to use a weird German device called an &lt;em&gt;Aufenthaltsschalter&lt;/em&gt; to stop and start the train automatically.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/german_device.jpg&quot; alt=&quot;&quot;&gt;
The Aufenthaltsschalter*&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/jain_puzzled.jpg&quot; alt=&quot;&quot;&gt;
&lt;em&gt;Jain trying to figure out the device&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/crazy_german_manual.jpg&quot; alt=&quot;&quot;&gt;
&lt;em&gt;Complicated schematic&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;Eureka moment&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The program running on the Raspberry Pi is very simple. It constantly listens for a voltage change on any of the reed switches, and if there is, it toggles the reed switch, which stops the train (to simulate goods unloading/loading).&lt;/p&gt;
&lt;p&gt;It then makes a HTTP request to the Hyperledger blockchain REST API to update the locations of the goods on the train.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/how_it_works.png&quot; alt=&quot;Schematic of how the Raspberry Pi controls the train&quot;&gt;&lt;/p&gt;
&lt;p&gt;There were many possible approaches I considered: ultrasonic sensor, light sensor, etc&lt;/p&gt;
&lt;p&gt;Here&#39;s a video of the train starting and stopping when toggling the reed switch.&lt;/p&gt;
&lt;video width = &quot;100%&quot; controls&gt;
&lt;source src=&quot;https://files.lieu.gg/img/blockchain_project/reed_switch.mp4&quot;&gt;
&lt;/video&gt;
&lt;h2 id=&quot;construction&quot; tabindex=&quot;-1&quot;&gt;Construction&lt;/h2&gt;
&lt;p&gt;I knew I wanted water in my diorama, as i) water looks very aesthetic, ii) I wanted to put a shipping container on the ship which people could scan, iii) Singapore is an island.&lt;/p&gt;
&lt;p&gt;To get a nice water effect, I used this thing called &amp;quot;Realistic Water&amp;quot;. We painted the styrofoam base a deep blue to get a &amp;quot;deep sea&amp;quot; effect, taped the sides to prevent water egress, then slowly poured the &amp;quot;Realistic Water&amp;quot; in, pressed in some rocks and finally left it to set overnight.&lt;/p&gt;
&lt;p&gt;It worked quite well, I think: see for yourself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/water_closeup.jpg&quot; alt=&quot;Closeup of realistic water, before ship was added&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;glamour-shots&quot; tabindex=&quot;-1&quot;&gt;Glamour shots&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/final_product.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_2.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_3.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_6.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_4.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I greatly enjoyed this project.&lt;/p&gt;
&lt;p&gt;It was super fun to play with model trains and fix up the diorama.&lt;/p&gt;
&lt;p&gt;Learned a lot of new things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hyperledger&lt;/li&gt;
&lt;li&gt;Reed switch, relay switch&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>Blocktrain</title>
    <link href="https://lieuzhenghong.com/projects/blocktrain/"/>
    <updated>2018-08-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/blocktrain/</id>
    <content type="html">&lt;h2 id=&quot;blockchain-train-diorama-(blocktrain)&quot; tabindex=&quot;-1&quot;&gt;Blockchain train diorama (Blocktrain)&lt;/h2&gt;
&lt;p&gt;June 2018 -- Aug 2018&lt;/p&gt;
&lt;p&gt;Tech stack: Hyperledger Fabric/Composer, Node.js, JavaScript&lt;/p&gt;
&lt;p&gt;After obtaining buy-in from senior management,
I conceptualised and led a project that persuades industry leaders
to adopt blockchain in their companies.&lt;/p&gt;
&lt;p&gt;The project is a fully-automated blockchain demonstrator for supply chain management.
It showcases how blockchain technology can be adopted in the supply chain.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/final_product.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_2.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_3.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_4.jpg&quot; alt=&quot;&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/detail_5.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;To this end, I&#39;ve built an automated train diorama, and three other components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Model train diorama with IoT sensors (to showcase the system in action)&lt;/li&gt;
&lt;li&gt;Blockchain (powered by Hyperledger)&lt;/li&gt;
&lt;li&gt;Real-time blockchain visualisation&lt;/li&gt;
&lt;li&gt;Asset tracker (good viewer) that works on any mobile device&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&#39;s how it works. On the train are shipping containers with QR codes pasted
on them. Scanning each QR code will pull up the asset tracker, a webpage that
gives the real-time location and previous provenance of the good --- all stored
immutably on the blockchain. As the train pulls up to a station, the goods are
unloaded and sent to a different location (absent a robotic arm, I&#39;m afraid one
has to use his imagination for this).&lt;/p&gt;
&lt;p&gt;When this happens, each shipping container will update its location automatically.
This is stored on the blockchain. I also built a blockchain visualisation
so we can see new blocks being added in real-time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_3.png&quot; alt=&quot;screenshot of blockchain slides&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_1.png&quot; alt=&quot;screenshot of blockchain slides&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/blockchain_project/blockchain_2.png&quot; alt=&quot;screenshot of blockchain slides&quot;&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ve written a more extensive writeup about the project
&lt;a href=&quot;https://lieuzhenghong.com/2019/01/31/building-a-blocktrain/&quot;&gt;here&lt;/a&gt;,
where I go into further detail.&lt;/p&gt;
&lt;p&gt;Built with Hyperledger, Node.js, and HTML Canvas.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Phonics Game</title>
    <link href="https://lieuzhenghong.com/projects/phonics-game/"/>
    <updated>2018-07-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/phonics-game/</id>
    <content type="html">&lt;h2 id=&quot;phonics-game&quot; tabindex=&quot;-1&quot;&gt;Phonics Game&lt;/h2&gt;
&lt;p&gt;July 2018&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/phonics_game/phonics_game.png&quot; alt=&quot;screenshot of phonics game&quot;&gt;&lt;/p&gt;
&lt;p&gt;An educational game for kids aged 7-8 to learn &amp;quot;vowel teams&amp;quot;, made for the
Ministry of Education. I didn&#39;t know what a vowel team was
until I started this project.&lt;/p&gt;
&lt;p&gt;Built with HTML Canvas and JavaScript, with art from the (extremely) talented
Shan Wei. Available to play &lt;a href=&quot;https://lieuzhenghong.com/projects/phonics-game/lieuzhenghong.com/phonics-game-poc&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Q-Step Essay</title>
    <link href="https://lieuzhenghong.com/ppe_qstep_essay/"/>
    <updated>2018-05-06T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/ppe_qstep_essay/</id>
    <content type="html">&lt;p&gt;In Hilary Term 2018, we were asked to read Lijphart, learn R, and write an empirical politics essay critiquing Lijphart. The essay is&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;expected to provide an empirical answer to one of the three questions listed below that deal with Lijphart’s regime type classification and its consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Does consensus democracy reduce social inequality?&lt;/li&gt;
&lt;li&gt;Does consensus democracy improve economic outcomes?&lt;/li&gt;
&lt;li&gt;Does consensus democracy improve the quality of government?&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;I chose the first question, &amp;quot;Does consensus democracy reduce social inequality?&amp;quot; I used an R notebook to do my scratch work and preliminary data exploration, then wrote the essay in Markdown and used pandoc to compile it.&lt;/p&gt;
&lt;p&gt;I was pleased that this essay won the 2018 prize. Professors David Kirk and Andrew Eggers were the markers. Andy later became my thesis advisor.&lt;/p&gt;
&lt;p&gt;The GitHub repo is available at &lt;a href=&quot;https://github.com/lieuzhenghong/qstep-essay&quot;&gt;https://github.com/lieuzhenghong/qstep-essay&lt;/a&gt; and the essay can be found &lt;a href=&quot;https://github.com/lieuzhenghong/qstep-essay/blob/master/qstep_essay_final.pdf&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Dropship Chess</title>
    <link href="https://lieuzhenghong.com/projects/dropship-chess/"/>
    <updated>2017-09-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/dropship-chess/</id>
    <content type="html">&lt;h2 id=&quot;dropship-chess&quot; tabindex=&quot;-1&quot;&gt;Dropship Chess&lt;/h2&gt;
&lt;p&gt;September 2017&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/chess/dropship-chess.jpg&quot; alt=&quot;screenshot of dropship chess&quot;&gt;&lt;/p&gt;
&lt;p&gt;A game built for the the Jack computer, a computer we build ourselves from
scratch (NAND gates) as part of the (excellent) course &lt;a href=&quot;https://www.nand2tetris.org/course&quot;&gt;From NAND to
Tetris&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s chess played on a 6x6 board where captured enemy pieces can be
&amp;quot;airdropped&amp;quot; anywhere on the board in lieu of moving a piece, kind of like
Shogi/Bughouse. White starts with two knights and Black with two bishops—so you
have to capture the opponent&#39;s knights/bishops to get your own.&lt;/p&gt;
&lt;p&gt;NAND To Tetris is an excellent overview of computer architecture. You start
with a NAND gate and build full adders and mutliplexers from it. You then build
basic processing and storage devices (ALU, RAM , CPU, display). Then you build an
assembler, then a VM, then an interpreter, then a full-fledged parser/lexer and
compiler for a high level language called Jack, and finally you write the OS
for the computer in Jack! At the end of the course you&#39;ve built a computer
which supports a high-level language and can run a highly nontrivial
program (Tetris) starting only from NAND gates. Awesome!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lieuzhenghong/nand2tetris-dropship-chess&quot;&gt;Dropship Chess&lt;/a&gt;,
&lt;a href=&quot;https://github.com/lieuzhenghong/nand2tetris/&quot;&gt;NAND 2 Tetris&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Inspector&#39;s Gadget</title>
    <link href="https://lieuzhenghong.com/projects/inspectors-gadget/"/>
    <updated>2017-08-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/inspectors-gadget/</id>
    <content type="html">&lt;h2 id=&quot;inspector&#39;s-gadget&quot; tabindex=&quot;-1&quot;&gt;Inspector&#39;s Gadget&lt;/h2&gt;
&lt;p&gt;August 2017&lt;/p&gt;
&lt;img src=&quot;https://files.lieu.gg/img/inspectors_gadget/inspectors_gadget_gif.gif&quot; width=&quot;600px&quot;&gt;
&lt;p&gt;Inspector&#39;s Gadget is a bespoke desktop application written in ElectronJS
that was custom-built for a civil engineering consulting firm. It streamlines
the process of writing building inspection reports. Real-world usage reports
show that it decreases the time taken to write a report by up to 85%.&lt;/p&gt;
&lt;p&gt;A building inspection report involves three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Photos taken of the building&lt;/li&gt;
&lt;li&gt;Floor plan of the building&lt;/li&gt;
&lt;li&gt;PDF report of all building defects and recommended actions taken (if any)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A building inspection report is done as follows: An engineer walks around
the building and takes photos of all structural features and defects (if
any). The engineer will then &amp;quot;tag&amp;quot; the floor plan---put labels on the floor
plan to show where each photo was taken. Finally, the engineer will produce
a PDF report which includes all the photos taken, a description of each photo,
and a classification of the defect type.&lt;/p&gt;
&lt;p&gt;Before I created this application for the firm, creating a report was a very
time-consuming process. First, every photo taken was renamed in File Explorer.
Then, the floor plan was tagged in Microsoft Word by manually creating Text
Boxes and moving them to the desired spot. Finally, to generate the report, the
engineers would paste the images one by one into the Word document. God forbid
the engineer missed out one photo in the middle, as to insert the new photo
&lt;em&gt;all&lt;/em&gt; subsequent photos had to be cut-and-pasted one box down. (You can see an
example in the image: the image A2-30 has been left out. That means all the
images and text from A2-31 onwards have to be cut and pasted one box down to
make space for the new image.)&lt;/p&gt;
&lt;p&gt;This application streamlines every part of the process, from uploading images
to quick-tagging floor plans to the final report generation. Just click an area
of the floor plan to tag it. The report is generated automatically, and if you
missed out a photo, that&#39;s fine---the report will reflow seamlessly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/inspectors_gadget/report.png&quot; alt=&quot;Inspector Gadget&#39;s UI to create a report&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lieuzhenghong/inspectors-gadget/&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building a Raspberry Pi console</title>
    <link href="https://lieuzhenghong.com/2017/05/30/building-a-raspberry-pi-console/"/>
    <updated>2017-05-30T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2017/05/30/building-a-raspberry-pi-console/</id>
    <content type="html">&lt;p&gt;Yesterday, Bailin and I finished the build of the Raspberry Pi console.&lt;/p&gt;
&lt;p&gt;This Raspberry Pi console project is the culmination of more than half a year of
effort. For the last eight months, I have been teaching the kids at Ulu Pandan
Stars Python (specifically Python Turtle). After much hand-holding and patient
instruction the kids were able to write the code for a Pong clone (mostly) all
by themselves. (We wrote the code that read from the GPIO pins).&lt;/p&gt;
&lt;p&gt;The kids don&#39;t understand all the concepts, however, which makes me think that
the project is a little too ambitious. For example, they have no idea what the
ADC does, how the wiring in the Raspberry Pi works and/or how the Raspi reads
the hardware inputs. I don&#39;t see this as &lt;em&gt;too&lt;/em&gt; big a deal, though, because even
if they don&#39;t understand it, at least they know about it.&lt;/p&gt;
&lt;p&gt;Nonetheless, the kids definitely &lt;em&gt;do&lt;/em&gt; understand a lot of things: basic
programming concepts (functions, loops, conditionals), Cartesian coordinates,
event-based programming, and so on. We have also been training them to talk
about what they have done (the girls lack the confidence to speak in a formal
setting) but there&#39;s still a lot of work that still needs to be done.&lt;/p&gt;
&lt;h2 id=&quot;parts-used&quot; tabindex=&quot;-1&quot;&gt;Parts used&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;7-inch touchscreen LCD: 118 SGD&lt;/li&gt;
&lt;li&gt;Raspberry Pi 3: ~65 SGD&lt;/li&gt;
&lt;li&gt;Rheostats, 2: ~2 SGD each&lt;/li&gt;
&lt;li&gt;60mm buttons, 2: 4.50 SGD each&lt;/li&gt;
&lt;li&gt;45mm buttons, 2: 3.50 SGD each&lt;/li&gt;
&lt;li&gt;ADC, 3 (but we used only 1): ~7 SGD each&lt;/li&gt;
&lt;li&gt;Box file from Popular: ~5 SGD&lt;/li&gt;
&lt;li&gt;X-acto knife: 13 SGD&lt;/li&gt;
&lt;li&gt;Solder iron: given to me by Snoopy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Total cost: ~250 SGD&lt;/p&gt;
&lt;h2 id=&quot;first-draft&quot; tabindex=&quot;-1&quot;&gt;First draft&lt;/h2&gt;
&lt;p&gt;The project started as a &#39;shoebox console&#39; but we found that a shoebox was way
too flimsy. Here&#39;s what that looked like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/old_console_closeup.jpg&quot; alt=&quot;image-title-here&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/old_console_closeup2.jpg&quot; alt=&quot;image-title-here&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/old_console_students.jpg&quot; alt=&quot;image-title-here&quot;&gt;
Zhengyang with the students
&lt;video width=&#39;100%&#39; src=&#39;https://files.lieu.gg/img/raspi-console/old_console_video&#39; controls&gt;&lt;/video&gt;
Video of me pressing the buttons&lt;/p&gt;
&lt;p&gt;We used an X-acto knife to cut the holes in the box and had to solder wires
onto the rheostats and the push buttons.&lt;/p&gt;
&lt;h2 id=&quot;improved-version&quot; tabindex=&quot;-1&quot;&gt;Improved version&lt;/h2&gt;
&lt;p&gt;Bailin was able to buy a box file from Popular for $5 so we used that instead.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_wip_soldering.jpg&quot; alt=&quot;Soldering the buttons&quot;&gt;
Bailin soldering the buttons. His hands were shaky so I took over for the more
delicate parts.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_wip.jpg&quot; alt=&quot;Work-in-progress console&quot;&gt;
The box before we put all the stuff inside it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_wip_closeup.jpg&quot; alt=&quot;Closeup of the work-in-progress console&quot;&gt;
Closeup of the WIP console; power bank not pictured&lt;/p&gt;
&lt;p&gt;&lt;video width=&#39;100%&#39; src=&#39;https://files.lieu.gg/img/raspi-console/console_video.mp4&#39; controls&gt;&lt;/video&gt;
Video tour of the console&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_side.jpg&quot; alt=&quot;Console from the side&quot;&gt;
Side view&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_closeup.jpg&quot; alt=&quot;Closeup of the console&quot;&gt;
Closeup of the console&lt;/p&gt;
&lt;p&gt;&lt;video width=&#39;100%&#39; src=&#39;https://files.lieu.gg/img/raspi-console/console_gaming_video.mp4&#39; controls&gt;&lt;/video&gt;
My mom and my cousin playing with it: the game is buggy and I will get
Audrey and Gillian to fix it.&lt;/p&gt;
&lt;h2 id=&quot;finishing-up&quot; tabindex=&quot;-1&quot;&gt;Finishing up&lt;/h2&gt;
&lt;p&gt;Today I called for an extra lesson where I got the kids to mount the final two
buttons so they could claim to have done at least some of it themselves (instead
of having the tutors do all the work). Here&#39;s what the final version looks like
now:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_v2_front.jpg&quot; alt=&quot;Console from the front&quot;&gt;
Front view&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_v2_34.jpg&quot; alt=&quot;Console from the side&quot;&gt;
3/4-view. I think it &lt;a href=&quot;https://en.wikipedia.org/wiki/Pareidolia&quot;&gt;kind of looks like a
face!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/raspi-console/console_v2_closeup.jpg&quot; alt=&quot;Closeup of the console&quot;&gt;
Closeup of the console&lt;/p&gt;
&lt;p&gt;Actually I still don&#39;t know how the thing is wired because Zheng Yang did the
lion&#39;s share of the work in wiring. I&#39;ll have to learn from Bailin how
everything is wired.&lt;/p&gt;
&lt;p&gt;This was my first time working with a Raspberry Pi as well as hardware
components like rheostats and buttons: my previous projects were all
software-only. I&#39;m very grateful to Zheng Yang and Bailin for helping so much
(it literally could not have been done without Zheng Yang).&lt;/p&gt;
&lt;p&gt;The kids will finish their DSA exercise in August. Whether or not they get into
DSA is out of my control but I hope that they will have the confidence and
motivation to pursue similar projects in the future. STEM is the future, after
all...&lt;/p&gt;
&lt;h2 id=&quot;what&#39;s-next&quot; tabindex=&quot;-1&quot;&gt;What&#39;s next&lt;/h2&gt;
&lt;p&gt;The kids should patch their games and do some bug-fixing.&lt;/p&gt;
&lt;p&gt;I&#39;d like to build a few &#39;demonstration games&#39; on the console that make
good use of the two rheostats (an interesting input medium).&lt;/p&gt;
&lt;p&gt;It&#39;s my hope that this console can be used as a springboard for future
programming lessons.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Building my first Telegram bot</title>
    <link href="https://lieuzhenghong.com/2016/09/20/building-my-first-telegram-bot/"/>
    <updated>2016-09-20T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/2016/09/20/building-my-first-telegram-bot/</id>
    <content type="html">&lt;p&gt;I built my first Telegram bot, Charge Bot. The first commit was 3 days ago (18th
September) but I first started working on it on 27th August. Then I took a three-week
break and resumed working on it on 17th September.&lt;/p&gt;
&lt;p&gt;You can check the bot out on Telegram &lt;a href=&quot;https://telegram.me/charge_game_bot&quot;&gt;here.&lt;/a&gt;
The Github repo is &lt;a href=&quot;https://github.com/lieuzhenghong/charge-bot/&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This checked a couple of technical firsts for me:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First Telegram bot&lt;/li&gt;
&lt;li&gt;First time I used Python to write anything substantial&lt;/li&gt;
&lt;li&gt;First deploy on Heroku&lt;/li&gt;
&lt;li&gt;First time using non-ASCII characters and working with UTF-8 encoding&lt;/li&gt;
&lt;li&gt;First time using a linter (pylint)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are also a couple of non-technical firsts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First time building a multiplayer &amp;quot;game&amp;quot;&lt;/li&gt;
&lt;li&gt;First time building anything my friends can use&lt;/li&gt;
&lt;li&gt;First time building something for public consumption (apart from a blog)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It was also the first time I wrote anything for public consumption.&lt;/p&gt;
&lt;p&gt;Overall, I am quite happy with this project. The scope was manageable and it did
not balloon (probably because it was a game and, being a game, the scope is rather
clearly defined; what also helped was the limitations of the Telegram medium).
At the same time, I was able to incorporate user feedback and suggestions.&lt;/p&gt;
&lt;h2 id=&quot;how-it-works&quot; tabindex=&quot;-1&quot;&gt;How it works&lt;/h2&gt;
&lt;p&gt;The Python code to write a Telegram bot is extremely trivial.
It is just a while loop that sends HTTP requests with a long timeout (long
polling). Upon receiving a response, it sends the next request.&lt;/p&gt;
&lt;p&gt;There is another way which is push instead of pull (doesn&#39;t send requests: waits for
Telegram to send updates to you) but it is far more involved and wasn&#39;t suitable for a
first-time project.&lt;/p&gt;
&lt;p&gt;Anyway, here&#39;s the code:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_updates&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        string &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; URL &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;getUpdates?offset={0}&amp;amp;timeout={1}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            read_offset&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        req &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        handle_updates&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&#39;s it. But there was a gotcha: As my background is in Javascript where all responses
are asynchronous, the line &lt;code&gt;req = requests.get(string)&lt;/code&gt; tripped me up. If you were to write
that in Javascript you would get &lt;code&gt;req == undefined&lt;/code&gt; or something like that and thus
&lt;code&gt;handle_updates(req)&lt;/code&gt; would throw an error.&lt;/p&gt;
&lt;p&gt;For Python, the synchronous nature of the code means that the assignment operator will
actually stop the evaluation until it returns a proper result. That means no callback is
needed and the code becomes very simple.&lt;/p&gt;
&lt;h2 id=&quot;snafus&quot; tabindex=&quot;-1&quot;&gt;Snafus&lt;/h2&gt;
&lt;h3 id=&quot;modularisation&quot; tabindex=&quot;-1&quot;&gt;Modularisation&lt;/h3&gt;
&lt;p&gt;This was something that I had a lot of trouble with, despite Mark&#39;s best efforts to help me.&lt;/p&gt;
&lt;p&gt;My code is divvied up as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* index.py (should be main.py): is the main file, imports everything
* network.py: sends requests and handles responses
* lobby.py: code that allows players to create and join a game
* game.py: game code
* charge_keyboard.py: the inline keyboard needed for the game
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I was unable to understand the idea of a function that called another function (also known
as... a callback function LOL). Here&#39;s what I had trouble with:&lt;/p&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# network.py&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setPushDataTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;func&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;global&lt;/span&gt; callback
    callback &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; func

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pushDataToDispatcher&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;global&lt;/span&gt; callback
    callback&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# index.py&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; network

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Initialises the app and sets up all callbacks&quot;&quot;&quot;&lt;/span&gt;
    network&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;setPushDataTo&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dispatcher&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dispatcher&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically, this pattern allows a function in one file to call a function in another file,
&lt;em&gt;without importing&lt;/em&gt;. The reason why we cannot import is because we don&#39;t want a two-way
import (index imports network, not the other way round).&lt;/p&gt;
&lt;p&gt;But we still need some way for the &amp;quot;child&amp;quot; to communicate with the &amp;quot;parent&amp;quot; and the way
to do it is by setting the callback function in the &amp;quot;child&amp;quot; to the parent&#39;s function.&lt;/p&gt;
&lt;p&gt;I am not sure I am explaining it clearly...I&#39;ll come back in a few days to this post
and see.&lt;/p&gt;
&lt;h3 id=&quot;deploying-on-heroku&quot; tabindex=&quot;-1&quot;&gt;Deploying on Heroku&lt;/h3&gt;
&lt;p&gt;Heroku was a real pain to set up...the documentation was lacking and I spent two nights&#39;
worth just trying to figure it out.&lt;/p&gt;
&lt;p&gt;The gist of it is that you have to have a &lt;code&gt;requirements.txt&lt;/code&gt; file, a &lt;code&gt;Procfile&lt;/code&gt; and a
&lt;code&gt;runtime.txt&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;The &amp;quot;Getting Started with Heroku&amp;quot; tutorial mentioned the first two but not the last one!!&lt;/p&gt;
&lt;p&gt;Basically, &lt;code&gt;requirements.txt&lt;/code&gt; is just a list of dependencies... that&#39;s quite straightforward
I still don&#39;t know what &lt;code&gt;runtime.txt&lt;/code&gt; does but I had to put in the line &lt;code&gt;python-3.5.2&lt;/code&gt; in
order for Heroku to deploy my app with Python 3. I needed Python 3 because of it&#39;s native
Unicode handling.&lt;/p&gt;
&lt;p&gt;What I mean by that is: when Python2 receives a response as a string, it doesn&#39;t actually
use Unicode encoding. In order to get it as Unicode you have to put a &lt;code&gt;u&#39;&lt;/code&gt; in front of it.
Python 3 does this all by itself.&lt;/p&gt;
&lt;p&gt;The Procfile is also not straightforward. Basically the Procfile tells Heroku what kind of
dyno your app is (web, worker, something else), what file to run with what program. So
like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;worker: python index.py --loglevel=info&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;(Weirdly, typing python3 index.py throws some weird error and I don&#39;t know why and haven&#39;t
been able to Google)&lt;/p&gt;
&lt;h2 id=&quot;bad-code&quot; tabindex=&quot;-1&quot;&gt;Bad code&lt;/h2&gt;
&lt;p&gt;This app was developed very haphazardly, and it shows. I used tons of global variables
because I&#39;m very bad. Coming from a Javascript background I don&#39;t know how to use classes,
like, &lt;em&gt;at all&lt;/em&gt;. So it&#39;s good that I&#39;m learning Python.&lt;/p&gt;
&lt;p&gt;I tried refactoring but it was truly a huge pain and I actually had to rollback to the
previous commit because I fucked everything up. 😭&lt;/p&gt;
&lt;h2 id=&quot;learning-points-and-future-plans&quot; tabindex=&quot;-1&quot;&gt;Learning points and future plans&lt;/h2&gt;
&lt;p&gt;I want to make as many bots as I can in the future, because Telegram is by far the most-used
app on my phone. It was extremely smart of the Telegram team to expose this API to developers--
this has allowed it to eclipse Whatsapp even further.&lt;/p&gt;
&lt;p&gt;For my next app, I will definitely try and use the webhooks push method.&lt;/p&gt;
&lt;p&gt;Heroku has a free dyno tier so I have &lt;strong&gt;no idea&lt;/strong&gt; why I&#39;m paying 8 dollars a month to DigitalOcean.
I think that I will move my automated transaction tracker over to Heroku as well.&lt;/p&gt;
&lt;p&gt;I mentioned the bad code: for my next app I am going to try and write it &lt;strong&gt;right&lt;/strong&gt; and I
know everyone says that but I mean it, I&#39;m going to aim for 0 warnings on pylint!!!&lt;/p&gt;
&lt;p&gt;Overall, this was a good learning experience, I had fun. Am pretty psyched to build my
next Telegram bot!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Automated Transaction Tracker</title>
    <link href="https://lieuzhenghong.com/projects/automated-transaction-tracker/"/>
    <updated>2016-08-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/automated-transaction-tracker/</id>
    <content type="html">&lt;h2 id=&quot;automated-transaction-tracker&quot; tabindex=&quot;-1&quot;&gt;Automated Transaction Tracker&lt;/h2&gt;
&lt;p&gt;August 2016&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/automated_transaction_tracker/automated_transaction_tracker.gif&quot; alt=&quot;screencap of automated transaction tracker&quot;&gt;&lt;/p&gt;
&lt;p&gt;I built the Army&#39;s first item tracker and automatic SMS reminder system
(that I know of),
for use in the Army&#39;s logistics branch.&lt;/p&gt;
&lt;p&gt;It&#39;s written in React and Node.js, and uses MongoDB on the back end.&lt;/p&gt;
&lt;p&gt;The system decreases administrative overhead
by automatically keeping count of all items in the store (item tracker),
and sending SMSes to remind borrowers who have borrowed items from the store
but have not returned them in time.
The system will also automatically notify the supervisor of the store
so that appropriate disciplinary action can be taken.&lt;/p&gt;
&lt;p&gt;This system won second prize in the Army&#39;s Annual Innovation Contest.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lieuzhenghong/automated-transaction-tracker/&quot;&gt;GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Form Emailer and Form Letterer</title>
    <link href="https://lieuzhenghong.com/projects/form-letterer/"/>
    <updated>2016-04-01T00:00:00Z</updated>
    <id>https://lieuzhenghong.com/projects/form-letterer/</id>
    <content type="html">&lt;h2 id=&quot;form-emailer-and-form-letterer&quot; tabindex=&quot;-1&quot;&gt;Form Emailer and Form Letterer&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://files.lieu.gg/img/form_suite/form_emailer.png&quot; alt=&quot;screenshot of form emailer&quot;&gt;
&lt;img src=&quot;https://files.lieu.gg/img/form_suite/form_letterer.png&quot; alt=&quot;screenshot of form letterer&quot;&gt;&lt;/p&gt;
&lt;p&gt;April 2016&lt;/p&gt;
&lt;p&gt;A mini &amp;quot;software suite&amp;quot; that makes sending mass, personalised emails very
simple. I created it because I was too lazy to send emails manually when I was
an intern. It was written in Python with the help of
&lt;a href=&quot;https://python-docx.readthedocs.io/en/latest/&quot;&gt;python-docx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Form Letterer allows you to quickly generate Word documents from a template,
(e.g. documents with different names/dates/amounts), while Form Emailer lets
you send personalised emails with different files attached. They synergise as
you can use Form Letterer to generate unique documents and then send those
documents in personalised emails with Form Emailer.&lt;/p&gt;
&lt;p&gt;One of the &amp;quot;killer features&amp;quot; this software suite has is the ability to send
unique attachments (a different attachment to each recipient), which Outlook
Mail Merge lacked. Another cool feature is it supports arbitrary Python code in
substitutions, which allows for amazing substitutions Mail Merge just can&#39;t support
like conditional execution.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/lieuzhenghong/form-letterer/&quot;&gt;Form Letterer GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;https://github.com/lieuzhenghong/form-emailer/&quot;&gt;Form Emailer GitHub&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
</feed>
