{"@attributes":{"version":"2.0"},"channel":{"title":"TomAF","link":"https:\/\/afiodorov.github.io","description":"Laugh with me, smile with me, disagree with me","language":"en-us","pubDate":"Thu, 17 Apr 2025 10:34:47 +0000","lastBuildDate":"Thu, 17 Apr 2025 10:34:47 +0000","item":[{"title":"The Age of Personalized Software: How LLMs Are Changing Programming","link":"https:\/\/afiodorov.github.io\/2025\/04\/17\/personalized-software\/","pubDate":"Thu, 17 Apr 2025 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>Today, I want to talk about the role of LLMs in the software industry.<\/p>\n\n<p>First, let me start by saying that the magic of LLMs is real; they really do help with writing all kinds of software and with software-related tasks.<\/p>\n\n<p>But I\u2019m not here to predict the end of programming. The other day, I thought about using generative AI to write some music for me. See, as a child, I wrote a couple of songs whose lyrics I quite liked, but I was never an advanced or diligent enough musician to turn them into professional-sounding pieces. The songs are still around, featuring my voice and a guitar, but they feel more like drafts \u2013 something you\u2019d show a fellow musician before considering it done.<\/p>\n\n<p>So, the other day, I found this guy on YouTube who was showing how to use various pieces of software to turn lyrics into music, complete with AI singing voices and musical instruments. I was amazed, but once I started paying closer attention to what he was doing, it became increasingly obvious that he\u2019s very knowledgeable about music production. In other words, he knows how to do all of it without AI. Sure, I could probably create something too, but that \u2018something\u2019 would either be far below today\u2019s musical standards or take me an incredible amount of time to produce.<\/p>\n\n<p>Where was I\u2026 ah yes, software. So, sure, now anyone can feel like a programmer, just like YouTube tutorials make us all feel like electricians, car mechanics, or doctors. And now, with LLMs, we\u2019re all lawyers and accountants too\u2026 right?<\/p>\n\n<p>Okay, I can fix a plug, tighten a screw, and change the oil in my car. And now, anyone can make a simple snake game using AI. But have you seen the state of professional software? Making money from apps requires hiring graphic designers, UX experts, and who knows what else.<\/p>\n\n<p>Because people, on average, aren\u2019t going to part with their cash just to use a basic app made by one developer.<\/p>\n\n<p>But where does this leave us programmers? Well, I still love LLMs because I get to write personalized apps. And I think that\u2019s where things are heading. It\u2019s not just your grandmother getting a custom app from her grandchildren; it\u2019s also your company\u2019s accountant getting a personal app or a plug-in to make their spreadsheet work easier.<\/p>\n\n<p>The value of each individual app made by this kind of \u201cvibe coding\u201d might be low, but collectively, they add up. Think of the scale \u2013 maybe it aggregates to something significant, perhaps illustrating the kind of value we see in OpenAI\u2019s valuation, just through sheer volume.<\/p>\n\n<p>So, to conclude, is this the end of programming or the start of something new? I\u2019d say neither.<\/p>\n"},{"title":"Vibe-blogging: Why I Prefer Bottom-Up Programming","link":"https:\/\/afiodorov.github.io\/2025\/04\/15\/vibe-blogging\/","pubDate":"Tue, 15 Apr 2025 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>I\u2019ve been wanting to get back into technical writing, and something has been bouncing around in my head lately: the perennial discussion of top-down versus bottom-up programming approaches.<\/p>\n\n<p>Let me define my terms, at least for this discussion. I see the top-down approach as emphasizing upfront planning, designing systems based on anticipated user needs and abstract structures. Conversely, I view the bottom-up approach as more discovery-driven \u2013 figuring out the requirements and the best way to implement them during the process, often starting with concrete pieces and building upwards.<\/p>\n\n<p>I want to be clear: I firmly believe both approaches have their place and are often needed in tandem for large, successful projects. However, personally? I find myself consistently drawn to, and simply enjoying, the bottom-up process much more.<\/p>\n\n<p>My journey with this preference started early. When I began coding, the landscape felt dominated by a choice: dive into compiled languages or embrace dynamic ones like Python (or JavaScript, pre-TypeScript). Apps were taking off, but jobs often fell into distinct \u201cbackend\u201d or \u201cfrontend\u201d buckets. This meant choices like Java\/C#\/C++ on one side, and PHP or JavaScript on the other. Python felt like something else entirely back then \u2013 often described as \u201cglue code,\u201d useful for scripting, but not quite a heavyweight contender in either the pure backend or frontend space.<\/p>\n\n<p>Frankly, I disliked Java intensely. To me, it felt like the epitome of the top-down philosophy. While the approach itself isn\u2019t inherently flawed, my perception was that the Java ecosystem often went overboard with abstractions, boilerplate, and scaffolding. It felt heavy and prescriptive. Python, for me, always represented the opposite end of that spectrum \u2013 lean, flexible, and immediate.<\/p>\n\n<p>Looking back, what kept pulling me towards Python? Time and again, it was its power in specific, practical contexts.<\/p>\n\n<p>My first real Python \u201caha!\u201d moment came during mathematical research involving computer simulations. I initially started with C++, chasing raw performance \u2013 a common choice when speed is paramount and you think you know exactly what needs to be computed. But I wasn\u2019t experienced enough to make C++ truly sing quickly. Slowly, I discovered NumPy. The revelation wasn\u2019t just about avoiding C++ compilation times; it was about the speed of experimentation. NumPy allowed me to rapidly test different hypotheses, tweak algorithms, and visualize results. The feedback loop was drastically shorter. Eventually, most of the simulation logic migrated to Python\/NumPy, and I rarely needed to touch the C++ code again. This was bottom-up discovery in action \u2013 finding the path through iteration.<\/p>\n\n<p>The second Python \u201ctrap\u201d I happily fell into was Pandas. It\u2019s worth appreciating Pandas\u2019 origin: Wes McKinney, working in finance, needed better tools for data analysis than Excel or existing libraries offered. He wasn\u2019t necessarily setting out to build a grand, perfectly designed system; he was solving a real, pressing problem for himself. And boy, did that library take off. For me, Pandas is a quintessential example of bottom-up success. It became, and largely remains, the lingua franca of data analysis.<\/p>\n\n<p>Now, the \u201ctop-down\u201d perspective often criticizes Pandas for its sometimes inconsistent API or its historical quirks (like the way it handled missing values via np.nan, a legacy of being built on top of NumPy). These criticisms have merit. Reading complex, heavily overloaded Pandas code can be challenging. And newer libraries like Polars have emerged, learning from Pandas\u2019 history to offer a cleaner, potentially more consistent API designed from the ground up. I understand the appeal, though habit keeps me reaching for Pandas often.<\/p>\n\n<p>But this slight digression highlights the core point. Pandas exploded in popularity because it solved immediate, tangible problems effectively, even if its initial form wasn\u2019t perfectly architected. Its \u201cmessiness\u201d is arguably a side effect of its organic, bottom-up growth. The succinctness, despite the quirks, was a massive advantage when you were still discovering what analysis needed to be done.<\/p>\n\n<p>This leads me to think about programming more broadly. For me, programming is fundamentally an engineering discipline. A programmer is a tool-wielder. If the best way to solve the problem is writing clean, well-structured code following a grand design, great. If it involves wrestling with a library\u2019s API or finding clever workarounds to get the job done now, that\u2019s also part of the game. The focus is on solving the problem.<\/p>\n\n<p>Think about other foundational pieces of software. Linus Torvalds wrote Git initially to solve his specific, pressing problem of managing the Linux kernel\u2019s source code. Satoshi Nakamoto created Bitcoin to address a specific set of ideas about decentralization and currency (whatever the exact motivation, it wasn\u2019t purely an exercise in abstract system design).<\/p>\n\n<p>These weren\u2019t born from committees planning abstract interfaces; they were born from individuals or small groups tackling concrete challenges. A programmer takes a problem and solves it using the tools available, including writing code. The bottom-up approach, the journey of discovery, feels incredibly aligned with this pragmatic, problem-solving core of engineering. While top-down planning provides necessary structure, especially at scale, the initial spark often comes from that bottom-up need.<\/p>\n"},{"title":"Releasing LiveTranslate - automatic simultaneous translation","link":"https:\/\/afiodorov.github.io\/2023\/11\/26\/announcing-livetranslate\/","pubDate":"Sun, 26 Nov 2023 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>I am tired of Americanism: consuming in the Anglosphere sometimes makes me feel\nlike all movies are the same. America is a great country for allowing a massive\nquantity of various productions to flourish however due to commercialisation\npressures some creativity is stiffled.<\/p>\n\n<p>Growing up I enjoyed some Soviet cinema. Most of it was boring however some\nfilms I loved and kept rewatching. However these days I can\u2019t find Russian\nstuff with dubs\/subtitles - so I am forced to watch this stuff alone. And\nsometimes I want to share the experience. This led me to consider the\npossibilities of leveraging large language models (LLMs) to facilitate\ntranslation for such content.<\/p>\n\n<p>Current transcription technologies like DeepGram offer decent performance, but\nthere\u2019s an evident bias towards Western languages. When it comes to Russian and\nPolish, for instance, inaccuracies are more common. Those inaccuracies could\neasily be fixed by an LLM post-processing the result: I experimented with using\nan LLM to improve the quality of these transcriptions, but real-time processing\nis still beyond our reach due to the response times of models like\nGPT-3.5-turbo (let alone GPT-4).<\/p>\n\n<p>When it comes to the translation, again LLMs are just not fast enough to\ntranslate real-time, so I am sticking with Google Translate. And surely enough\nI can just preprocessing most content and translate thing myself - but that\u2019s\nmuch more effort than just putting something on.<\/p>\n\n<p>In the meantime, I\u2019ve found that automatic translation can be quite useful for\nthose who have a basic grasp of the source language. It serves as a helpful\ntool for understanding and learning, similar to how one might pick up slang\nfrom context within a movie. This has proven especially true for me with Polish\ncontent - all of a sudden I found it understandable (a Russian speaker\ntypically doesn\u2019t understand Polish but can read a lot of it without any\nlearning).<\/p>\n\n<p>Given the current limitations of real-time translation, I\u2019ve decided to release\nmy project, <a href=\"https:\/\/github.com\/afiodorov\/livetranslate\">LiveTranslate<\/a>, on GitHub. It\u2019s a practical solution for now,\nparticularly for programmers who might be interested in contributing to its\ndevelopment. The project has potential for further enhancements, especially in\nthe areas of user interface and increased accuracy.<\/p>\n\n<p>The repository is now available for access and contribution. This release is\nfor those who share an interest in making non-English content more accessible\nand are looking for a way to integrate programming skills with language\ntranslation. The hope is that as LLMs improve in latency, so too will the\ncapabilities of LiveTranslate.<\/p>\n\n<h2 id=\"demo\">Demo<\/h2>\n\n<p><img src=\"https:\/\/github.com\/afiodorov\/livetranslate\/raw\/main\/demo.gif\" alt=\"Demo of the livetranslate\" \/><\/p>\n\n"},{"title":"Announcing Thoughtful3","link":"https:\/\/afiodorov.github.io\/2022\/12\/29\/announcing-thoughtful3\/","pubDate":"Thu, 29 Dec 2022 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>I spent last 6 days creating <a href=\"https:\/\/thoughtful3.eth.limo\/\">Thoughtful3<\/a>.\nIt\u2019s basically Twitter but it is hosted on Ethereum blockchain and thus is very\nexpensive. Like $8 per Tweet that you have to pay the crypto miners to embed\nyour thoughts into the blockchain. I think it\u2019s a feature actually: with such\nhigh prices no problem with spam accounts.<\/p>\n\n<p>Why? I like the idea of embedding your thoughts into Ethereum forever. Whatever\nI post there is likely to outlive me. Also this is truly censorship resistant.\nSo if you need to complain about evil governments: go ahead (but it\u2019ll cost\nyou $8 per 300 characters). Anyway I\u2019ve always wanted to make a Web3 app, i.e.\na decentralised app. This is my first (Web3 and Thoughtful is the reason for the\nname). Underneath I am using <a href=\"https:\/\/thegraph.com\/\">thegraph<\/a>. I used vyper for the\nsmartcontract &amp; pure typescript (no libraries like React) for the front end.\nCode of the project can be found <a href=\"https:\/\/github.com\/afiodorov\/thoughtful3\">here<\/a>.<\/p>\n\n<p>I didn\u2019t know much about Metamask (extension that allows you to interact with\nEthereum network) nor modern JavaScript 6 days ago and heavily used ChatGPT3 to\ngenerate boilerplate code for me &amp; used DALL-E to generate a logo.<\/p>\n\n"},{"title":"I am in Lisbon","link":"https:\/\/afiodorov.github.io\/2022\/07\/26\/i-am-in-lisbon\/","pubDate":"Tue, 26 Jul 2022 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>I am on my summer break and it didn\u2019t take me long to get to Lisbon, Portugal.\nI flew from Canary Islands and did not know what to expect. I\u2019ve only been here\n3.5 days but slowly I am forming a picture.<\/p>\n\n<p>Approaching Lisbon I saw red-bricked roofs of the houses and many hills and it\ninstantly reminded me of Vilnius, Lithuania. However right at the airport\nwaiting for the taxi pick-up I noticed multi ethnic groups waiting and so my\nimpression changed towards either a) yet another Western European city b)\npost-colonial capital. Of course it is a bit of both, but I am currently\nthinking it\u2019s more b) than a).<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0292.HEIC.jpg\" alt=\"roofs\" \/><\/p>\n\n<p>Greeted by the transit person who was responsible for getting me to the hotel\n(most hotel bookings here include a taxi transfer), I found out she\u2019s Brazilian\nand so is the taxi driver. Took her a few minutes of knowing me to complain about\nthe Portuguese: she said she moved from Porto to Lisbon because Portuguese\nthere \u201cdon\u2019t like Brazilians much\u201d. Woaaa. Felt like getting to know a group of\ngood friends who instantly started gossiping about one another.<\/p>\n\n<p>Checking in at the hotel the receptionist spoke some Spanish to me for about 1\nminute and then he just switched to English without an explanation. The other\nstaff stood by timidly and didn\u2019t say much after the initial \u201chola\u201d. From\nfuture interactions with the locals I am getting the impression that Portuguese\nare much more reserved and timid compared to southern Spanish. Why am I comparing\nthem to Spanish anyway?<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0289.HEIC.jpg\" alt=\"bridge\" \/><\/p>\n\n<p>Before coming here I used to think of Portugal as some kind of Spanish little\nbrother. And it is not - as simple as that. The easiest way to offend everyone\nin this country is to say \u2018gracias\u2019 instead of \u2018obligado\u2019. Portugal has a\ndistinct national identity. Apart from a brief period of the union with\nCastilla they remained largely independent. Even the union was never a conquest\nby the Spanish - it happened because of some blood ties of the royal families.<\/p>\n\n<p>The similarities I see are more to do with the climate: dinners are very\nlate, people never seem to be in a rush. Some ingredients and dishes are in\ncommon: like the octopus. Although that\u2019s probably because of the shared\ncuisine with their Northern neighbour: Galicia. The languages don\u2019t sound the\nsame at all. In fact many people say the Portuguese phonetically resemble some\nkind of Slavic language. And to my ear this is completely true. The first day I\nkept wondering why everyone is speaking Polish around here. Reasons for the\nsimilarity are coincidental: Slavic &amp; Portuguese are stress-timed languages and\nfeature many sounds like sh\/zh and other constant clusters that make them\nsounds somewhat similar especially if are not paying much attention.<\/p>\n\n<p>However, there is one similarity in (slang) Spanish and Portuguese languages:\nthe frequency of the AO diphthong. I always wondered why Maluma sings \u2018ya que\nestoy tomA\u2019O\u2019 even though he\u2019s Colombian. I currently suspect this A\u2019O thing is\na Brazilian influence on the Latin Spanish to make it sound cool. Coincidently\nsame A\u2019O diphthong can be heard in the Galician accent, language most similar\nto Portuguese. Satisfying when all pieces fit.<\/p>\n\n<p>I digressed. Lisbon itself turned out be smaller in the population size than I\nthought it would be. Hosting just 500 thousand inhabitants - it is only 30%\nbigger than the city where I reside, Las Palmas. Yet Las Palmas feels like a\nprovince whilst Lisbon, or should I say Lisboa, is definitely a capital. The\ndensity of beautiful buildings in the city shows that it has a wealthy history;\nit also has a metro system. I guess 500,000 figure is deceptive, as their\nmetropolitan population is much much bigger than Las Palmas. Whilst I enjoy the\nbeautiful buildings that make up the city center, due to the hot climate at the\nmoment my sight-seeing abilities are limited. What I absolutely love about the\ncity is the abundance of various parks and squares for people to hide from the\nscorching sun. Here, in the shade, I spend a lot of time these days reading my\ne-reader and thinking about what to write.<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0290.HEIC.jpg\" alt=\"belem\" \/><\/p>\n\n<p>I am staying here at a very modest hotel, especially given its price. There\u2019s\nno swimming pool, my room is tiny, nor do I agree with their liberal use\nof the word gym. Sure, a room with a few kettlebells is a gym. The city centre\nis full of hotels. So what brings all the people then? For me it\u2019s a\ncombination of factors. Lisbon has become popular with remote workers,\nespecially crypto-bros because of the taxation. It\u2019s a lively city with a good\nclimate and prices still lower than other European capitals. I see the appeal.\nSo far I found myself much more fascinated with the history of the place and\nthe affinity with Brazil. As I keep exploring the city more I see them tourists\nidly wondering around downtown, drinking cocktails straight from the pineapple.\nDoesn\u2019t feel that different to other popular destinations. But as a motorized\nrickshaw pass by I hear the girls cheerfully singing<\/p>\n<blockquote>\n  <p>Nossa, nossa<br \/>\nAssim voc\u00ea me mata<br \/>\nAi, se eu te pego<\/p>\n<\/blockquote>\n\n<p>a very catchy Brazilian song I picked up from hanging out with Latin musicians.<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0283.HEIC.jpg\" alt=\"pineapple drink\" \/><\/p>\n\n<p>I keep finding it incredible that all the way back in 1500\u2019s Portuguese sailors\ncolonised Brazil. Later they colonised other places in Africa and Asia. No\nwonder it took them a long time to swallow their pride and give up their\nterritories. They lost thousands of people too in 1961-1974 still trying to hold\nonto their last colonies. Ultimately they suffered a defeat. Now that the\nnation is cured of its pride and they have become a modern modest democracy\nthey\u2019ve discovered the problem of declining population. Rich westerners have\nbetter things to do than to have kids. Appears current solution to the problem\nis to import people from the ex colonies. And so there are Angolian, Mozambican\nand, of course, Brazilian restaurants here. So far I\u2019ve only tried one\nBrazilian dish (moqueca de peixe), and it was a very rich explosion of exotic,\nspicy flavours. After having the incredible dish and being exposed to the\ncatchy music I must admit it is tempting to pick up some basic Portuguese\nand travel through Brazil as my next journey.<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0284.HEIC.jpg\" alt=\"tower\" \/><\/p>\n\n<p>And so where am I, in the end? I am in a modern Western capital with a distinct\nculture and a flavour of colonial past. Welcome to Lisboa, welcome to not-Spain!<\/p>\n\n<p><img src=\"\/assets\/lisboa_IMG_0280.HEIC.jpg\" alt=\"staircase\" \/><\/p>\n"},{"title":"Computing rolling median in Go","link":"https:\/\/afiodorov.github.io\/2020\/02\/04\/rolling-median\/","pubDate":"Tue, 04 Feb 2020 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>Back in the day when I was teaching myself how to <del>program<\/del> land a programming\njob, I\u2019d spend quite some time learning basic data structures such as queues,\nstacks, heaps, linked lists, etc. To my disappointment though, now that I am\nemployed in tech I almost never get a chance to implement these anymore.\nReasons are: I can often use a library or I simply don\u2019t need these ingredients\nas they are too \u201clow-level\u201d.<\/p>\n\n<p>Recently though I have had a chance to brush up on my Computer Science 101\nknowledge, and weeks go by but I am still excited. Thus I bring the\nexcitement to you, my dear reader!<\/p>\n\n<p>The story begins in me having to make the following computation in go:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">ser<\/span><span class=\"p\">.<\/span><span class=\"n\">rolling<\/span><span class=\"p\">(<\/span><span class=\"n\">period<\/span><span class=\"o\">=<\/span><span class=\"mi\">30<\/span><span class=\"p\">).<\/span><span class=\"n\">median<\/span><span class=\"p\">()<\/span> <span class=\"c1\"># this is python's Pandas library, N=30<\/span><\/code><\/pre><\/figure>\n\n<p>i.e. computing <a href=\"https:\/\/en.wikipedia.org\/wiki\/Moving_average\">rolling\/moving median<\/a> of a series of timestamped numbers.\nOne of the reasons I like coding in Go sometimes is because it forces you to\nimplement things like that from scratch, rather than rely on someone else\u2019s\ncode. It\u2019s problems like these that got me enthusiastic about entering this\nprofession (as opposed to having to peruse <a href=\"https:\/\/www.djangoproject.com\/\">Django<\/a> documentation: a read that\ndoesn\u2019t have a great ending).<\/p>\n\n<hr \/>\n\n<p>Without further ado, let\u2019s begin our rolling median implementation. Start with\nan underlying data structure that holds our timestamped numbers:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-go\" data-lang=\"go\"><span class=\"k\">package<\/span> <span class=\"n\">main<\/span>\n\n<span class=\"k\">import<\/span> <span class=\"p\">(<\/span>\n\t<span class=\"s\">\"math\"<\/span>\n\t<span class=\"s\">\"sort\"<\/span>\n\t<span class=\"s\">\"time\"<\/span>\n<span class=\"p\">)<\/span>\n\n<span class=\"c\">\/\/ Data holds Value &amp; Time when value was observed<\/span>\n<span class=\"k\">type<\/span> <span class=\"n\">Data<\/span> <span class=\"k\">struct<\/span> <span class=\"p\">{<\/span>\n\t<span class=\"n\">Value<\/span> <span class=\"kt\">float64<\/span>\n\t<span class=\"n\">Time<\/span>  <span class=\"n\">time<\/span><span class=\"o\">.<\/span><span class=\"n\">Time<\/span>\n<span class=\"p\">}<\/span><\/code><\/pre><\/figure>\n\n<p>When computing rolling median, we will need to remember last N (where N is the\nsize of the window) entries in a sorted order. The fact that elements are\nsorted allows us to quickly find the median by picking the element in the\nmiddle. Go provides a handy <code class=\"language-plaintext highlighter-rouge\">sort<\/code> library that allows one to use <a href=\"https:\/\/en.wikipedia.org\/wiki\/Binary_search_algorithm\">binary search<\/a>\nto insert &amp; delete elements from a slice that\u2019s already sorted:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-go\" data-lang=\"go\"><span class=\"c\">\/\/ SortedFloatSlice assumes elements are sorted<\/span>\n<span class=\"k\">type<\/span> <span class=\"n\">SortedFloatSlice<\/span> <span class=\"p\">[]<\/span><span class=\"kt\">float64<\/span>\n\n<span class=\"c\">\/\/ Insert into slice maintaing the sort order<\/span>\n<span class=\"k\">func<\/span> <span class=\"p\">(<\/span><span class=\"n\">f<\/span> <span class=\"n\">SortedFloatSlice<\/span><span class=\"p\">)<\/span> <span class=\"n\">Insert<\/span><span class=\"p\">(<\/span><span class=\"n\">value<\/span> <span class=\"kt\">float64<\/span><span class=\"p\">)<\/span> <span class=\"n\">SortedFloatSlice<\/span> <span class=\"p\">{<\/span>\n\t<span class=\"n\">i<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sort<\/span><span class=\"o\">.<\/span><span class=\"n\">SearchFloat64s<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">)<\/span>\n\t<span class=\"n\">n<\/span> <span class=\"o\">:=<\/span> <span class=\"nb\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">)<\/span>\n\t<span class=\"nb\">copy<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"o\">+<\/span><span class=\"m\">1<\/span><span class=\"o\">:<\/span><span class=\"p\">],<\/span> <span class=\"n\">n<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"o\">:<\/span><span class=\"p\">])<\/span>\n\t<span class=\"n\">n<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">value<\/span>\n\t<span class=\"k\">return<\/span> <span class=\"n\">n<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c\">\/\/ Delete from slice maintaing the sort order<\/span>\n<span class=\"k\">func<\/span> <span class=\"p\">(<\/span><span class=\"n\">f<\/span> <span class=\"n\">SortedFloatSlice<\/span><span class=\"p\">)<\/span> <span class=\"n\">Delete<\/span><span class=\"p\">(<\/span><span class=\"n\">value<\/span> <span class=\"kt\">float64<\/span><span class=\"p\">)<\/span> <span class=\"n\">SortedFloatSlice<\/span> <span class=\"p\">{<\/span>\n\t<span class=\"n\">i<\/span> <span class=\"o\">:=<\/span> <span class=\"n\">sort<\/span><span class=\"o\">.<\/span><span class=\"n\">SearchFloat64s<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">,<\/span> <span class=\"n\">value<\/span><span class=\"p\">)<\/span>\n\t<span class=\"n\">n<\/span> <span class=\"o\">:=<\/span> <span class=\"nb\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">[<\/span><span class=\"o\">:<\/span><span class=\"n\">i<\/span><span class=\"p\">],<\/span> <span class=\"n\">f<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"o\">+<\/span><span class=\"m\">1<\/span><span class=\"o\">:<\/span><span class=\"p\">]<\/span><span class=\"o\">...<\/span><span class=\"p\">)<\/span>\n\t<span class=\"k\">return<\/span> <span class=\"n\">n<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c\">\/\/ Median of the slice<\/span>\n<span class=\"k\">func<\/span> <span class=\"p\">(<\/span><span class=\"n\">f<\/span> <span class=\"n\">SortedFloatSlice<\/span><span class=\"p\">)<\/span> <span class=\"n\">Median<\/span><span class=\"p\">()<\/span> <span class=\"kt\">float64<\/span> <span class=\"p\">{<\/span>\n\t<span class=\"k\">if<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span><span class=\"o\">%<\/span><span class=\"m\">2<\/span> <span class=\"o\">==<\/span> <span class=\"m\">1<\/span> <span class=\"p\">{<\/span>\n\t\t<span class=\"k\">return<\/span> <span class=\"n\">f<\/span><span class=\"p\">[<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span><span class=\"o\">\/<\/span><span class=\"m\">2<\/span><span class=\"p\">]<\/span>\n\t<span class=\"p\">}<\/span>\n\t<span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">[<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span><span class=\"o\">\/<\/span><span class=\"m\">2<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span> <span class=\"n\">f<\/span><span class=\"p\">[<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">f<\/span><span class=\"p\">)<\/span><span class=\"o\">\/<\/span><span class=\"m\">2<\/span><span class=\"o\">-<\/span><span class=\"m\">1<\/span><span class=\"p\">])<\/span> <span class=\"o\">\/<\/span> <span class=\"m\">2<\/span>\n<span class=\"p\">}<\/span><\/code><\/pre><\/figure>\n\n<p>We have all the components to make the computation possible. Just like pandas\nwe pre-fill the result with <code class=\"language-plaintext highlighter-rouge\">NaN<\/code>\u2019s where computation is impossible. We\ninitialise the sliding window at the start of the series, and keep advancing\nthe window one element at a time, whilst keeping the window sorted<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-go\" data-lang=\"go\"><span class=\"k\">func<\/span> <span class=\"n\">movingMedian<\/span><span class=\"p\">(<\/span><span class=\"n\">series<\/span> <span class=\"p\">[]<\/span><span class=\"n\">Data<\/span><span class=\"p\">,<\/span> <span class=\"n\">period<\/span> <span class=\"kt\">int<\/span><span class=\"p\">)<\/span> <span class=\"p\">[]<\/span><span class=\"n\">Data<\/span> <span class=\"p\">{<\/span>\n\t<span class=\"n\">res<\/span> <span class=\"o\">:=<\/span> <span class=\"nb\">make<\/span><span class=\"p\">([]<\/span><span class=\"n\">Data<\/span><span class=\"p\">,<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">series<\/span><span class=\"p\">))<\/span>\n\n\t<span class=\"n\">window<\/span> <span class=\"o\">:=<\/span> <span class=\"nb\">make<\/span><span class=\"p\">(<\/span><span class=\"n\">SortedFloatSlice<\/span><span class=\"p\">,<\/span> <span class=\"m\">0<\/span><span class=\"p\">,<\/span> <span class=\"n\">period<\/span><span class=\"o\">-<\/span><span class=\"m\">1<\/span><span class=\"p\">)<\/span>\n\t<span class=\"k\">for<\/span> <span class=\"n\">_<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span> <span class=\"o\">:=<\/span> <span class=\"k\">range<\/span> <span class=\"n\">series<\/span><span class=\"p\">[<\/span><span class=\"o\">:<\/span><span class=\"p\">(<\/span><span class=\"n\">period<\/span> <span class=\"o\">-<\/span> <span class=\"m\">1<\/span><span class=\"p\">)]<\/span> <span class=\"p\">{<\/span>\n\t\t<span class=\"n\">window<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">window<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">Value<\/span><span class=\"p\">)<\/span>\n\t<span class=\"p\">}<\/span>\n\t<span class=\"n\">sort<\/span><span class=\"o\">.<\/span><span class=\"n\">Float64s<\/span><span class=\"p\">(<\/span><span class=\"n\">window<\/span><span class=\"p\">)<\/span>\n\n\t<span class=\"n\">median<\/span> <span class=\"o\">:=<\/span> <span class=\"kt\">float64<\/span><span class=\"p\">(<\/span><span class=\"m\">0<\/span><span class=\"p\">)<\/span>\n\t<span class=\"k\">for<\/span> <span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"n\">v<\/span> <span class=\"o\">:=<\/span> <span class=\"k\">range<\/span> <span class=\"n\">series<\/span> <span class=\"p\">{<\/span>\n\t\t<span class=\"k\">if<\/span> <span class=\"n\">i<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">period<\/span><span class=\"o\">-<\/span><span class=\"m\">1<\/span> <span class=\"p\">{<\/span>\n\t\t\t<span class=\"n\">median<\/span> <span class=\"o\">=<\/span> <span class=\"n\">math<\/span><span class=\"o\">.<\/span><span class=\"n\">NaN<\/span><span class=\"p\">()<\/span>\n\t\t<span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"p\">{<\/span>\n\t\t\t<span class=\"k\">if<\/span> <span class=\"n\">i<\/span><span class=\"o\">-<\/span><span class=\"n\">period<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"m\">0<\/span> <span class=\"p\">{<\/span>\n\t\t\t\t<span class=\"n\">window<\/span> <span class=\"o\">=<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">Delete<\/span><span class=\"p\">(<\/span><span class=\"n\">series<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"o\">-<\/span><span class=\"n\">period<\/span><span class=\"p\">]<\/span><span class=\"o\">.<\/span><span class=\"n\">Value<\/span><span class=\"p\">)<\/span>\n\t\t\t<span class=\"p\">}<\/span>\n\t\t\t<span class=\"n\">window<\/span> <span class=\"o\">=<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">Insert<\/span><span class=\"p\">(<\/span><span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">Value<\/span><span class=\"p\">)<\/span>\n\t\t\t<span class=\"n\">median<\/span> <span class=\"o\">=<\/span> <span class=\"n\">window<\/span><span class=\"o\">.<\/span><span class=\"n\">Median<\/span><span class=\"p\">()<\/span>\n\t\t<span class=\"p\">}<\/span>\n\n\t\t<span class=\"n\">res<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Data<\/span><span class=\"p\">{<\/span>\n\t\t\t<span class=\"n\">Time<\/span><span class=\"o\">:<\/span>  <span class=\"n\">v<\/span><span class=\"o\">.<\/span><span class=\"n\">Time<\/span><span class=\"p\">,<\/span>\n\t\t\t<span class=\"n\">Value<\/span><span class=\"o\">:<\/span> <span class=\"n\">median<\/span><span class=\"p\">,<\/span>\n\t\t<span class=\"p\">}<\/span>\n\t<span class=\"p\">}<\/span>\n\n\t<span class=\"k\">return<\/span> <span class=\"n\">res<\/span>\n<span class=\"p\">}<\/span><\/code><\/pre><\/figure>\n\n<hr \/>\n\n<p>Complexity analysis: we have to do insert\/delete from a sorted array at each\nstep, which is O(window). Since we have N steps the resulting complexity is\nO(N*window). Can we do better? Turns out the canonical algorithm for computing\na rolling median is to keep window elements in a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Skip_list\">skip list<\/a> instead.\nSkip list allows one to insert, delete and random access sorted elements in\nlogN times, thus the complexity of the canonical algorithm is lower:\nO(N*log(window)). However for windows of small sizes, I feel like the advantage\nof skip lists is not worth the cost of much more complex implementation.<\/p>\n\n<hr \/>\n\n<p>This concludes the code &amp; the blog post. Hurray!<\/p>\n\n<p>TL;DR I used a sorted array to make the computation.<\/p>\n\n<p>TL;DR;TL;DR I am (still) a massive nerd.<\/p>\n\n"},{"title":"Getting a musical note from audio","link":"https:\/\/afiodorov.github.io\/2019\/12\/06\/note\/","pubDate":"Fri, 06 Dec 2019 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>Lately I have been <s>learning music<\/s> playing around with computers &amp; maths\nunder the pretence of learning music. I am particularly interested in breaking\ndown melodies into individual notes. However since actually training my\nmusical ear is hard work, I am going to use basic signal processing in order to\nachieve my goal.<\/p>\n\n<figure>\n    <figcaption>Let's start with this 1 second music audio:<\/figcaption>\n    <audio controls=\"\" src=\"\/assets\/note.wav\">\n            Your browser does not support the\n            <code>audio<\/code> element.\n    <\/audio>\n<\/figure>\n\n<p>Can you identify the note? Well I can\u2019t. So I am going to use a computer to do\nthis for me.<\/p>\n\n<hr \/>\n\n<p>First, I am going to discover some basics of digital music audio by loading\nthe above audio file &amp; plotting it. I get something like this:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">librosa<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">pandas<\/span> <span class=\"k\">as<\/span> <span class=\"n\">pd<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">plotly.express<\/span> <span class=\"k\">as<\/span> <span class=\"n\">px<\/span>\n\n<span class=\"n\">note_filepath<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"\/home\/tom\/afiodorov.github.io\/assets\/note.wav\"<\/span>\n<span class=\"n\">y<\/span><span class=\"p\">,<\/span> <span class=\"n\">sample_rate<\/span> <span class=\"o\">=<\/span> <span class=\"n\">librosa<\/span><span class=\"p\">.<\/span><span class=\"n\">load<\/span><span class=\"p\">(<\/span><span class=\"n\">note_filepath<\/span><span class=\"p\">,<\/span> <span class=\"n\">sr<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">({<\/span><span class=\"s\">'time (s)'<\/span><span class=\"p\">:<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">y<\/span><span class=\"p\">))<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">sample_rate<\/span><span class=\"p\">,<\/span> <span class=\"s\">'wave'<\/span><span class=\"p\">:<\/span> <span class=\"n\">y<\/span><span class=\"p\">})<\/span>\n<span class=\"n\">fig<\/span> <span class=\"o\">=<\/span> <span class=\"n\">px<\/span><span class=\"p\">.<\/span><span class=\"n\">line<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"o\">=<\/span><span class=\"s\">\"time (s)\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"o\">=<\/span><span class=\"s\">\"wave\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"s\">'Raw Waveform'<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">show<\/span><span class=\"p\">()<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<div id=\"waveform\"><\/div>\n\n<p>Turns out digital audio is represented by a series of real numbers, i.e. it is\na one-dimensional array. When we plot our series, we get extremely wiggly\nline. Such plot is referred to as (raw) waveform. If you zoom in enough in the\nabove chart, you will see that it\u2019s just a line. I found it surprising how easy\nit is to represent music. The greatest, most complex compositions you have ever\nlistened to are just a bunch of real numbers. Let\u2019s print first 10 numbers of the\nabove file just for illustrative purpose:<\/p>\n\n<p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">y<\/span><span class=\"p\">[:<\/span><span class=\"mi\">10<\/span><span class=\"p\">]<\/span>\n<span class=\"o\">&gt;<\/span> <span class=\"n\">array<\/span><span class=\"p\">([<\/span><span class=\"o\">-<\/span><span class=\"mf\">0.03649902<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.04107666<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.05935669<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.09130859<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.1232605<\/span> <span class=\"p\">,<\/span>\n<span class=\"o\">&gt;<\/span>        <span class=\"o\">-<\/span><span class=\"mf\">0.13696289<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.15524292<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.17349243<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.18261719<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"mf\">0.20089722<\/span><span class=\"p\">],<\/span>\n<span class=\"o\">&gt;<\/span>              <span class=\"n\">dtype<\/span><span class=\"o\">=<\/span><span class=\"n\">float32<\/span><span class=\"p\">)]<\/span><\/code><\/pre><\/figure>\n\n<\/p>\n\n<p>Do these 10 numbers sound like a note to you :)? Just kidding. Even if you\ndiscovered a way to enjoy music by reading a long list of numbers, these 10\nwould actually be inaudible: they represent a miniscule part of the 1 second\ninterval above. In the plot above 44 100 points are used to represent 1 second\nworth of audio. This is the same as saying that the sampling rate of our\nrecording is 44 100 Hz. To put it in elementary terms, we record the audio wave\nvalue 44 100 times per second at equally spaced intervals. Why 44 100? This\nnumber is linked to human hearing. People can hear sounds from 20 to 20 000 Hz,\nwhere the higher the number of Hz, the higher the sound sounds to you. It turns\nout in order to record audio in such range, we need to sample twice as often,\nthus the sampling rate of 44 100<sup id=\"fnref:1\" role=\"doc-noteref\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup> has been used often in digital records.<\/p>\n\n<hr \/>\n\n<p>Basic musical theory: we have 7 notes: do, re, mi, fa, sol, la, si, do,\nalternatively known as C, D, E, F, G, A, B, C. The latter do is an octave above\nthe first do. What\u2019s an octave from a physical point of view? Turns out if a\nnote has frequency twice as high as another note than those two notes are\nthe same but one octave apart. Often subscript is used to denote octaves,\ne.g. C\u2082 and C\u2083 are one octave apart whereas F\u2084 and F\u2087 are 3 octaves apart. At\nsome point in the 20th century musicians all around the world agreed that A\u2084\n(la) is 440 Hz. Now let\u2019s look at notes on a piano:<\/p>\n\n<p><img src=\"\/assets\/piano.jpg\" alt=\"piano\" \/><\/p>\n\n<p>There are actually 12 keys between the two C\u2019s when we count the black keys.\nThese 12 keys are equally separated musically. Curiously there\u2019s no black key\nbetween mi (E) &amp; fa (F). The distance between F and G is a tone and the\ndistance between E &amp; F is a semitone. What do I mean by equally separated? The\nratio of frequencies matter when we compare notes, as opposed to their absolute\nfrequency. Thus for adjacent notes to have the same ratio I can apply a factor of\n\\( \\sqrt[12]{2} \\approx 1.06 \\) every time I go up by a semitone. This way\nafter I apply it 12 times, I double the frequency and thus complete the octave.\nUsing this knowledge it\u2019s a trivial exercise in computer science to generate\nfrequencies of all notes. I presented to you a cropped table of some of them\nfrom octave 0 to 6:<\/p>\n\n<table>\n  <thead>\n    <tr>\n      <th>octave<\/th>\n      <th>F#<\/th>\n      <th>G<\/th>\n      <th>G#<\/th>\n      <th>A<\/th>\n      <th>A#<\/th>\n      <th>B<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>0<\/td>\n      <td>23.1247<\/td>\n      <td>24.4997<\/td>\n      <td>25.9565<\/td>\n      <td>27.5<\/td>\n      <td>29.1352<\/td>\n      <td>30.8677<\/td>\n    <\/tr>\n    <tr>\n      <td>1<\/td>\n      <td>46.2493<\/td>\n      <td>48.9994<\/td>\n      <td>51.9131<\/td>\n      <td>55<\/td>\n      <td>58.2705<\/td>\n      <td>61.7354<\/td>\n    <\/tr>\n    <tr>\n      <td>2<\/td>\n      <td>92.4986<\/td>\n      <td>97.9989<\/td>\n      <td>103.826<\/td>\n      <td>110<\/td>\n      <td>116.541<\/td>\n      <td>123.471<\/td>\n    <\/tr>\n    <tr>\n      <td>3<\/td>\n      <td>184.997<\/td>\n      <td>195.998<\/td>\n      <td>207.652<\/td>\n      <td>220<\/td>\n      <td>233.082<\/td>\n      <td>246.942<\/td>\n    <\/tr>\n    <tr>\n      <td>4<\/td>\n      <td>369.994<\/td>\n      <td>391.995<\/td>\n      <td>415.305<\/td>\n      <td>440<\/td>\n      <td>466.164<\/td>\n      <td>493.883<\/td>\n    <\/tr>\n    <tr>\n      <td>5<\/td>\n      <td>739.989<\/td>\n      <td>783.991<\/td>\n      <td>830.609<\/td>\n      <td>880<\/td>\n      <td>932.328<\/td>\n      <td>987.767<\/td>\n    <\/tr>\n    <tr>\n      <td>6<\/td>\n      <td>1479.98<\/td>\n      <td>1567.98<\/td>\n      <td>1661.22<\/td>\n      <td>1760<\/td>\n      <td>1864.66<\/td>\n      <td>1975.53<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<details><summary>rest of the notes<\/summary><p>\n<table>\n<thead>\n<tr><th style=\"text-align: right;\">  octave<\/th><th style=\"text-align: right;\">        C<\/th><th style=\"text-align: right;\">       C#<\/th><th style=\"text-align: right;\">        D<\/th><th style=\"text-align: right;\">       D#<\/th><th style=\"text-align: right;\">        E<\/th><th style=\"text-align: right;\">        F<\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td style=\"text-align: right;\">       0<\/td><td style=\"text-align: right;\">  16.3516<\/td><td style=\"text-align: right;\">  17.3239<\/td><td style=\"text-align: right;\">  18.354 <\/td><td style=\"text-align: right;\">  19.4454<\/td><td style=\"text-align: right;\">  20.6017<\/td><td style=\"text-align: right;\">  21.8268<\/td><\/tr>\n<tr><td style=\"text-align: right;\">       1<\/td><td style=\"text-align: right;\">  32.7032<\/td><td style=\"text-align: right;\">  34.6478<\/td><td style=\"text-align: right;\">  36.7081<\/td><td style=\"text-align: right;\">  38.8909<\/td><td style=\"text-align: right;\">  41.2034<\/td><td style=\"text-align: right;\">  43.6535<\/td><\/tr>\n<tr><td style=\"text-align: right;\">       2<\/td><td style=\"text-align: right;\">  65.4064<\/td><td style=\"text-align: right;\">  69.2957<\/td><td style=\"text-align: right;\">  73.4162<\/td><td style=\"text-align: right;\">  77.7817<\/td><td style=\"text-align: right;\">  82.4069<\/td><td style=\"text-align: right;\">  87.3071<\/td><\/tr>\n<tr><td style=\"text-align: right;\">       3<\/td><td style=\"text-align: right;\"> 130.813 <\/td><td style=\"text-align: right;\"> 138.591 <\/td><td style=\"text-align: right;\"> 146.832 <\/td><td style=\"text-align: right;\"> 155.563 <\/td><td style=\"text-align: right;\"> 164.814 <\/td><td style=\"text-align: right;\"> 174.614 <\/td><\/tr>\n<tr><td style=\"text-align: right;\">       4<\/td><td style=\"text-align: right;\"> 261.626 <\/td><td style=\"text-align: right;\"> 277.183 <\/td><td style=\"text-align: right;\"> 293.665 <\/td><td style=\"text-align: right;\"> 311.127 <\/td><td style=\"text-align: right;\"> 329.628 <\/td><td style=\"text-align: right;\"> 349.228 <\/td><\/tr>\n<tr><td style=\"text-align: right;\">       5<\/td><td style=\"text-align: right;\"> 523.251 <\/td><td style=\"text-align: right;\"> 554.365 <\/td><td style=\"text-align: right;\"> 587.33  <\/td><td style=\"text-align: right;\"> 622.254 <\/td><td style=\"text-align: right;\"> 659.255 <\/td><td style=\"text-align: right;\"> 698.456 <\/td><\/tr>\n<tr><td style=\"text-align: right;\">       6<\/td><td style=\"text-align: right;\">1046.5   <\/td><td style=\"text-align: right;\">1108.73  <\/td><td style=\"text-align: right;\">1174.66  <\/td><td style=\"text-align: right;\">1244.51  <\/td><td style=\"text-align: right;\">1318.51  <\/td><td style=\"text-align: right;\">1396.91  <\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/p><\/details>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">def<\/span> <span class=\"nf\">num_semitones_between<\/span><span class=\"p\">(<\/span><span class=\"n\">note1<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">note2<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s\">'C'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'C#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'D'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'D#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'E'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'F'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'F#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'G'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'G#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'A'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'A#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'B'<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">notes<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span><span class=\"p\">(<\/span><span class=\"n\">note1<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">notes<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span><span class=\"p\">(<\/span><span class=\"n\">note2<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">note_frequency<\/span><span class=\"p\">(<\/span><span class=\"n\">note<\/span><span class=\"p\">:<\/span> <span class=\"nb\">str<\/span><span class=\"p\">,<\/span> <span class=\"n\">octave<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">4<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">float<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">a_4<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">440<\/span> <span class=\"c1\">#  standard pitch\n<\/span>    <span class=\"n\">a_frequency<\/span> <span class=\"o\">=<\/span> <span class=\"n\">a_4<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">**<\/span> <span class=\"p\">(<\/span><span class=\"n\">octave<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">4<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">adjustment<\/span> <span class=\"o\">=<\/span> <span class=\"n\">num_semitones_between<\/span><span class=\"p\">(<\/span><span class=\"n\">note<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"A\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">a_frequency<\/span> <span class=\"o\">*<\/span> <span class=\"mi\">2<\/span> <span class=\"o\">**<\/span> <span class=\"p\">(<\/span><span class=\"n\">adjustment<\/span> <span class=\"o\">\/<\/span> <span class=\"mi\">12<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">gen_notes_table<\/span><span class=\"p\">()<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">l<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n    <span class=\"n\">notes<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s\">'C'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'C#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'D'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'D#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'E'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'F'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'F#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'G'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'G#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'A'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'A#'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'B'<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">octave<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">7<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">l<\/span><span class=\"p\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">([<\/span><span class=\"n\">note_frequency<\/span><span class=\"p\">(<\/span><span class=\"n\">note<\/span><span class=\"p\">,<\/span> <span class=\"n\">octave<\/span><span class=\"o\">=<\/span><span class=\"n\">octave<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">note<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">notes<\/span><span class=\"p\">])<\/span>\n    <span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span><span class=\"n\">l<\/span><span class=\"p\">,<\/span> <span class=\"n\">columns<\/span><span class=\"o\">=<\/span><span class=\"n\">notes<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span><span class=\"p\">.<\/span><span class=\"n\">name<\/span> <span class=\"o\">=<\/span> <span class=\"s\">'octave'<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">df<\/span>\n\n<span class=\"kn\">import<\/span> <span class=\"nn\">tabulate<\/span>\n<span class=\"n\">tabulate<\/span><span class=\"p\">.<\/span><span class=\"n\">tabulate<\/span><span class=\"p\">(<\/span><span class=\"n\">gen_notes_table<\/span><span class=\"p\">(),<\/span> <span class=\"n\">tablefmt<\/span><span class=\"o\">=<\/span><span class=\"s\">\"github\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"s\">\"keys\"<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<hr \/>\n\n<p>Note: in the above table the ratio between A# and A is roughly 1.06 (466 \/\n440), just like advertised.<\/p>\n\n<p>OK, but how do we get the goddamn note from the audio snippet? We need some\nsort of transformation of the waveform into frequencies. <a href=\"https:\/\/en.wikipedia.org\/wiki\/Fourier_transform\">Fourier transform<\/a>, an\ninteresting piece of mathematics discovered by Joseph Fourier in 1822, allows\nus to \u201cpluck out\u201d specific frequencies from the sound and see how much each of\nthem contribute. Graphically it means that we are going to take the waveform\nshown above, and try to approximate it by adding functions cosine and sine\nuntil the result looks almost exactly like our waveform. A process illustrated\nbelow for a simple waveform that is of quadratic shape:<\/p>\n\n<p><img src=\"\/assets\/fourier.svg\" alt=\"fourier\" \/><\/p>\n\n<p>The more cosine &amp; sine functions we add, the more precise the approximation becomes.\nWhat we are interested in is which exactly cosine &amp; sine contribute the most to\nthe recorded waveform, i.e. which notes are present in the audio? Let\u2019s perform\nthe transform and plot it:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">numpy<\/span> <span class=\"k\">as<\/span> <span class=\"n\">np<\/span>\n\n<span class=\"n\">ft<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">fft<\/span><span class=\"p\">.<\/span><span class=\"n\">rfft<\/span><span class=\"p\">(<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">absolute<\/span><span class=\"p\">(<\/span><span class=\"n\">ft<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">:]),<\/span> <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">ft<\/span><span class=\"p\">)))<\/span>\n<span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span><span class=\"p\">.<\/span><span class=\"n\">name<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"Frequency (Hz)\"<\/span>\n<span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">columns<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"s\">'Amplitude'<\/span><span class=\"p\">]<\/span>\n<span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">reset_index<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">fig<\/span> <span class=\"o\">=<\/span> <span class=\"n\">px<\/span><span class=\"p\">.<\/span><span class=\"n\">line<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">2000<\/span><span class=\"p\">],<\/span> <span class=\"n\">x<\/span><span class=\"o\">=<\/span><span class=\"s\">\"Frequency (Hz)\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"o\">=<\/span><span class=\"s\">\"Amplitude\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"s\">'Fourier transform'<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">show<\/span><span class=\"p\">()<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<div id=\"fourier\"><\/div>\n\n<p>From the above graph we see that the frequency that is the most present is 370\nHz, meaning the note recorded is F#\u2084 (fi). Interestingly enough F#\u2085 (740 Hz)\nand F#\u2086 (\u2248 1486 Hz) are also present. These are so-called overtones that make\nthe sound sound more pleasant. Whew, so much maths to identify the note, but we\nfinally got here! Finally, I am including two more audio samples, for\neducational purposes.<\/p>\n\n<figure>\n    <figcaption>This is how the snippet would sound without the overtones:<\/figcaption>\n    <audio controls=\"\" src=\"\/assets\/noovertones.wav\">\n            Your browser does not support the\n            <code>audio<\/code> element.\n    <\/audio>\n<\/figure>\n\n<figure>\n    <figcaption>And this is everything but the 370 Hz removed:<\/figcaption>\n    <audio controls=\"\" src=\"\/assets\/370.wav\">\n            Your browser does not support the\n            <code>audio<\/code> element.\n    <\/audio>\n<\/figure>\n\n<script>\nfunction embed(divName) {\n  let url = '\/assets\/' + divName + '.json';\n  let req = new XMLHttpRequest();\n  req.open(\"GET\", url, true);\n  req.onload  = function() {\n     let jsonResponse = JSON.parse(req.responseText);\n     let waveform = document.getElementById(divName);\n     Plotly.plot(waveform, jsonResponse, {margin: { t: 10 }});\n  };\n  req.send(null);\n}\n\nembed('waveform');\nembed('fourier');\n<\/script>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\" role=\"doc-endnote\">\n      <p>Why 44 100 as opposed to 40 000? I don\u2019t know!\u00a0<a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n"},{"title":"Generating Ethereum address from scratch","link":"https:\/\/afiodorov.github.io\/2019\/06\/18\/elliptic\/","pubDate":"Tue, 18 Jun 2019 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>In this blog post I would like to introduce readers into Elliptic Curve\nCryptography and use this knowledge to construct an Ethereum address.<\/p>\n\n<h1 id=\"part-1-elliptic-curves\">Part 1: Elliptic Curves<\/h1>\n\n<p>An Elliptic Curve is a curve define by the equation<\/p>\n\n\\[y^2 = x^3 + ax +b,\\]\n\n<p>The curve has a number of nice properties, and one of them is that if take two\npoints on the curve and draw a line through them, the line will intersect the\ncurve at exactly one point. You can play around with this property using the\n<a href=\"https:\/\/bokeh.pydata.org\/en\/latest\/\">Bokeh<\/a> application below:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">numpy<\/span> <span class=\"k\">as<\/span> <span class=\"n\">np<\/span>\n\n<span class=\"kn\">from<\/span> <span class=\"nn\">bokeh.layouts<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">column<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">bokeh.models<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">CustomJS<\/span><span class=\"p\">,<\/span> <span class=\"n\">Slider<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">bokeh.plotting<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">ColumnDataSource<\/span><span class=\"p\">,<\/span> <span class=\"n\">figure<\/span><span class=\"p\">,<\/span> <span class=\"n\">show<\/span>\n\n\n<span class=\"k\">def<\/span> <span class=\"nf\">create_layout<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">start_xs<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">6<\/span><span class=\"p\">],<\/span> <span class=\"n\">x_max<\/span><span class=\"o\">=<\/span><span class=\"mi\">15<\/span><span class=\"p\">,<\/span> <span class=\"n\">flip<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">roots<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">roots<\/span><span class=\"p\">([<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">])<\/span>\n    <span class=\"n\">min_<\/span> <span class=\"o\">=<\/span> <span class=\"n\">roots<\/span><span class=\"p\">[<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">isreal<\/span><span class=\"p\">(<\/span><span class=\"n\">roots<\/span><span class=\"p\">)][<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"n\">real<\/span>\n    <span class=\"k\">while<\/span> <span class=\"n\">min_<\/span><span class=\"o\">**<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span> <span class=\"n\">min_<\/span> <span class=\"o\">*<\/span> <span class=\"n\">a<\/span> <span class=\"o\">+<\/span> <span class=\"n\">b<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">min_<\/span> <span class=\"o\">+=<\/span> <span class=\"mf\">0.0001<\/span>\n\n    <span class=\"n\">step<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">0.01<\/span>\n    <span class=\"n\">x_vals<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">arange<\/span><span class=\"p\">(<\/span><span class=\"n\">min_<\/span><span class=\"p\">,<\/span> <span class=\"n\">x_max<\/span><span class=\"p\">,<\/span> <span class=\"n\">step<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">y_vals<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">sqrt<\/span><span class=\"p\">(<\/span><span class=\"n\">x_vals<\/span><span class=\"o\">**<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span> <span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">x_vals<\/span> <span class=\"o\">+<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">start_xs<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">array<\/span><span class=\"p\">(<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">start_ys<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">sqrt<\/span><span class=\"p\">(<\/span><span class=\"n\">start_xs<\/span><span class=\"o\">**<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span> <span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">start_xs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">flip<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"o\">-<\/span><span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">source<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ColumnDataSource<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"o\">=<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"o\">=<\/span><span class=\"n\">start_ys<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"n\">line_xs<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">()]<\/span> <span class=\"o\">+<\/span> <span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"p\">[<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">()]<\/span>\n    <span class=\"n\">slope<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span>\n    <span class=\"n\">y_line_min<\/span> <span class=\"o\">=<\/span> <span class=\"n\">slope<\/span> <span class=\"o\">*<\/span> <span class=\"p\">(<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">()<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span> <span class=\"o\">+<\/span> <span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">y_line_max<\/span> <span class=\"o\">=<\/span> <span class=\"n\">slope<\/span> <span class=\"o\">*<\/span> <span class=\"p\">(<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">()<\/span> <span class=\"o\">-<\/span> <span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">])<\/span> <span class=\"o\">+<\/span> <span class=\"n\">start_ys<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">line_ys<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">y_line_min<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span> <span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"n\">start_ys<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"p\">[<\/span><span class=\"n\">y_line_max<\/span><span class=\"p\">]<\/span>\n\n    <span class=\"n\">source_line<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ColumnDataSource<\/span><span class=\"p\">(<\/span><span class=\"n\">data<\/span><span class=\"o\">=<\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"o\">=<\/span><span class=\"n\">line_xs<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"o\">=<\/span><span class=\"n\">line_ys<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"n\">p1_slider<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Slider<\/span><span class=\"p\">(<\/span><span class=\"n\">start<\/span><span class=\"o\">=<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">(),<\/span> <span class=\"n\">end<\/span><span class=\"o\">=<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">(),<\/span> <span class=\"n\">value<\/span><span class=\"o\">=<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">],<\/span>\n                       <span class=\"n\">step<\/span><span class=\"o\">=<\/span><span class=\"n\">step<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"s\">\"Point1\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">p2_slider<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Slider<\/span><span class=\"p\">(<\/span><span class=\"n\">start<\/span><span class=\"o\">=<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">(),<\/span> <span class=\"n\">end<\/span><span class=\"o\">=<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">(),<\/span> <span class=\"n\">value<\/span><span class=\"o\">=<\/span><span class=\"n\">start_xs<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">],<\/span>\n                       <span class=\"n\">step<\/span><span class=\"o\">=<\/span><span class=\"n\">step<\/span><span class=\"p\">,<\/span> <span class=\"n\">title<\/span><span class=\"o\">=<\/span><span class=\"s\">\"Point2\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">plot<\/span> <span class=\"o\">=<\/span> <span class=\"n\">figure<\/span><span class=\"p\">(<\/span><span class=\"n\">plot_width<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">,<\/span> <span class=\"n\">plot_height<\/span><span class=\"o\">=<\/span><span class=\"mi\">400<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plot<\/span><span class=\"p\">.<\/span><span class=\"n\">line<\/span><span class=\"p\">(<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">,<\/span> <span class=\"n\">y_vals<\/span><span class=\"p\">,<\/span> <span class=\"n\">line_width<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plot<\/span><span class=\"p\">.<\/span><span class=\"n\">line<\/span><span class=\"p\">(<\/span><span class=\"n\">x_vals<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"n\">y_vals<\/span><span class=\"p\">,<\/span> <span class=\"n\">line_width<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">plot<\/span><span class=\"p\">.<\/span><span class=\"n\">circle<\/span><span class=\"p\">(<\/span><span class=\"s\">'x'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'y'<\/span><span class=\"p\">,<\/span> <span class=\"n\">source<\/span><span class=\"o\">=<\/span><span class=\"n\">source<\/span><span class=\"p\">,<\/span> <span class=\"n\">size<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">color<\/span><span class=\"o\">=<\/span><span class=\"s\">\"navy\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">alpha<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.5<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">plot<\/span><span class=\"p\">.<\/span><span class=\"n\">line<\/span><span class=\"p\">(<\/span><span class=\"s\">'x'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'y'<\/span><span class=\"p\">,<\/span> <span class=\"n\">source<\/span><span class=\"o\">=<\/span><span class=\"n\">source_line<\/span><span class=\"p\">,<\/span> <span class=\"n\">line_width<\/span><span class=\"o\">=<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">color<\/span><span class=\"o\">=<\/span><span class=\"s\">\"black\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">minus<\/span> <span class=\"o\">=<\/span> <span class=\"s\">\"-\"<\/span> <span class=\"k\">if<\/span> <span class=\"n\">flip<\/span> <span class=\"k\">else<\/span> <span class=\"s\">\"\"<\/span>\n    <span class=\"n\">callback<\/span> <span class=\"o\">=<\/span> <span class=\"n\">CustomJS<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"o\">=<\/span><span class=\"nb\">dict<\/span><span class=\"p\">(<\/span><span class=\"n\">source_dots<\/span><span class=\"o\">=<\/span><span class=\"n\">source<\/span><span class=\"p\">,<\/span>\n                                  <span class=\"n\">source_line<\/span><span class=\"o\">=<\/span><span class=\"n\">source_line<\/span><span class=\"p\">,<\/span>\n                                  <span class=\"n\">p1<\/span><span class=\"o\">=<\/span><span class=\"n\">p1_slider<\/span><span class=\"p\">,<\/span> <span class=\"n\">p2<\/span><span class=\"o\">=<\/span><span class=\"n\">p2_slider<\/span><span class=\"p\">),<\/span>\n                        <span class=\"n\">code<\/span><span class=\"o\">=<\/span><span class=\"sa\">f<\/span><span class=\"s\">\"\"\"\n        const data = source_dots.data;\n        const x1 = p1.value;\n        const x2 = p2.value;\n        const x = data['x'];\n        const y = data['y'];\n        x[0] = x1;\n        x[1] = x2;\n        const y1 = <\/span><span class=\"si\">{<\/span><span class=\"n\">minus<\/span><span class=\"si\">}<\/span><span class=\"s\">Math.sqrt(Math.pow(x1, 3) + <\/span><span class=\"si\">{<\/span><span class=\"n\">a<\/span><span class=\"si\">}<\/span><span class=\"s\"> * x1 + <\/span><span class=\"si\">{<\/span><span class=\"n\">b<\/span><span class=\"si\">}<\/span><span class=\"s\">);\n        const y2 = Math.sqrt(Math.pow(x2, 3) + <\/span><span class=\"si\">{<\/span><span class=\"n\">a<\/span><span class=\"si\">}<\/span><span class=\"s\"> * x2 + <\/span><span class=\"si\">{<\/span><span class=\"n\">b<\/span><span class=\"si\">}<\/span><span class=\"s\">);\n        y[0] = y1;\n        y[1] = y2;\n        source_line.data['x'][1] = x1;\n        source_line.data['x'][2] = x2;\n        source_line.data['y'][1] = y1;\n        source_line.data['y'][2] = y2;\n        const slope = (y2 - y1) \/ (x2 - x1);\n        source_line.data['y'][0] = slope * (source_line.data['x'][0] - x1) + y1;\n        source_line.data['y'][3] = slope * (source_line.data['x'][3] - x1) + y1;\n        source_dots.change.emit();\n        source_line.change.emit();\n    \"\"\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">p1_slider<\/span><span class=\"p\">.<\/span><span class=\"n\">js_on_change<\/span><span class=\"p\">(<\/span><span class=\"s\">'value'<\/span><span class=\"p\">,<\/span> <span class=\"n\">callback<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">p2_slider<\/span><span class=\"p\">.<\/span><span class=\"n\">js_on_change<\/span><span class=\"p\">(<\/span><span class=\"s\">'value'<\/span><span class=\"p\">,<\/span> <span class=\"n\">callback<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">layout<\/span> <span class=\"o\">=<\/span> <span class=\"n\">column<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">plot<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">column<\/span><span class=\"p\">(<\/span><span class=\"n\">p1_slider<\/span><span class=\"p\">,<\/span> <span class=\"n\">p2_slider<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">layout<\/span>\n\n\n<span class=\"n\">l1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">create_layout<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">29<\/span><span class=\"p\">,<\/span> <span class=\"n\">flip<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">l2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">create_layout<\/span><span class=\"p\">(<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span> <span class=\"mi\">29<\/span><span class=\"p\">,<\/span> <span class=\"n\">flip<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">show<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">(<\/span><span class=\"n\">l1<\/span><span class=\"p\">,<\/span> <span class=\"n\">l2<\/span><span class=\"p\">))<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<p><div id=\"elliptic\" class=\"bk-root\"><\/div><\/p>\n\n<p>This property allows us to map 2 points on a curve to a 3 point, an operation\nthat we will refer to as an addition (with respect to the curve). The reason we\ncall this an addition, because it shares certain similarities with an\narithmetic addition. However, we refine our addition to result in the reflected\npoint, see illustration below:<\/p>\n\n<p><img src=\"\/assets\/elliptic_add.jpeg\" alt=\"\" class=\"center-image\" \/><\/p>\n\n<p>Algebraically, this means that<\/p>\n\n\\[\\begin{align}\n\\begin{split}\n x_R &amp;= s^2 - x_P - x_Q,\n \\\\\n y_R &amp;= y_P + s(x_R - x_P) .\n\\end{split}\n\\tag{1}\\label{eqn:point_r}\n\\end{align}\\]\n\n<p>where slope, \\(s\\), defined as<\/p>\n\n\\[\\frac{y_P - y_Q}{x_P - x_Q},\\]\n\n<p>when \\(P \\neq Q\\), and<\/p>\n\n\\[\\frac{3x_P^2 + a}{2y_P},\\]\n\n<p>when \\(P = Q\\). Note that in this case the slope is just a tangent and is\neasy to derive:<\/p>\n\n\\[\\frac{\\partial (y^2)}{\\partial x} = \\frac{\\partial (x^3 + ax +b)}{\\partial x} \\implies \\\\\n2y \\frac{\\partial y}{\\partial x} = 3x^2 + a.\\]\n\n<p>We can verify algebraically that \\(y_R^2 = x_R^3 + ax_R + b\\), meaning\n\\(R\\) is on our curve. Finally, for our addition to be valid, we need to\ndefine a point that would serve the role of \\(0\\). So, by definition,\n\\(P + O = P\\), and \\(-P + P = O\\). My vague intuition is that I can think\nof \\(O\\) as the entire <code class=\"language-plaintext highlighter-rouge\">x<\/code>-axis.<\/p>\n\n<h1 id=\"part-2-mathematical-fields\">Part 2: Mathematical Fields<\/h1>\n\n<p>If we pick a prime number \\(p\\), we can define multiplication, addition,\nsubtraction and division module \\(p\\):<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">class<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">p<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">):<\/span>\n            <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"o\">=<\/span> <span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">multiply<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">b<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">+<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">sub<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">-<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">div<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">b<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">b<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nb\">ZeroDivisionError<\/span>\n        <span class=\"n\">inv_b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">egcd<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"c1\"># Euclidean algorithm\n<\/span>        <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">multiply<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">inv_b<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<p>Mathematically, this means that we have a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Field_(mathematics)\">field<\/a>, \\(\\mathbb{F}_p\\). Real\nnumbers form a field too, so you probably have a good intuition for how fields\nwork.<\/p>\n\n<p>Here are arithmetic tables for \\(\\mathbb{F}_{7}\\), skipping subtraction as I don\u2019t have space:<\/p>\n\n<table style=\"border: none;\"><tr><td style=\"border: none;\">\n<table>\n<thead>\n<tr><th style=\"text-align: right;\">*<\/th><th>1  <\/th><th>2  <\/th><th>3  <\/th><th>4  <\/th><th>5  <\/th><th>6  <\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td style=\"text-align: right;\"> 1<\/td><td>1  <\/td><td>2  <\/td><td>3  <\/td><td>4  <\/td><td>5  <\/td><td>6  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 2<\/td><td>2  <\/td><td>4  <\/td><td>6  <\/td><td>1  <\/td><td>3  <\/td><td>5  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 3<\/td><td>3  <\/td><td>6  <\/td><td>2  <\/td><td>5  <\/td><td>1  <\/td><td>4  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 4<\/td><td>4  <\/td><td>1  <\/td><td>5  <\/td><td>2  <\/td><td>6  <\/td><td>3  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 5<\/td><td>5  <\/td><td>3  <\/td><td>1  <\/td><td>6  <\/td><td>4  <\/td><td>2  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 6<\/td><td>6  <\/td><td>5  <\/td><td>4  <\/td><td>3  <\/td><td>2  <\/td><td>1  <\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/td><td style=\"border: none;\">\n<table>\n<thead>\n<tr><th style=\"text-align: right;\">\/<\/th><th>1  <\/th><th>2  <\/th><th>3  <\/th><th>4  <\/th><th>5  <\/th><th>6  <\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td style=\"text-align: right;\"> 1<\/td><td>1  <\/td><td>2  <\/td><td>3  <\/td><td>4  <\/td><td>5  <\/td><td>6  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 2<\/td><td>4  <\/td><td>1  <\/td><td>5  <\/td><td>2  <\/td><td>6  <\/td><td>3  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 3<\/td><td>5  <\/td><td>3  <\/td><td>1  <\/td><td>6  <\/td><td>4  <\/td><td>2  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 4<\/td><td>2  <\/td><td>4  <\/td><td>6  <\/td><td>1  <\/td><td>3  <\/td><td>5  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 5<\/td><td>3  <\/td><td>6  <\/td><td>2  <\/td><td>5  <\/td><td>1  <\/td><td>4  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 6<\/td><td>6  <\/td><td>5  <\/td><td>4  <\/td><td>3  <\/td><td>2  <\/td><td>1  <\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/td><td style=\"border: none;\">\n<table>\n<thead>\n<tr><th style=\"text-align: right;\">+<\/th><th>1  <\/th><th>2  <\/th><th>3  <\/th><th>4  <\/th><th>5  <\/th><th>6  <\/th><\/tr>\n<\/thead>\n<tbody>\n<tr><td style=\"text-align: right;\"> 1<\/td><td>2  <\/td><td>3  <\/td><td>4  <\/td><td>5  <\/td><td>6  <\/td><td>0  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 2<\/td><td>3  <\/td><td>4  <\/td><td>5  <\/td><td>6  <\/td><td>0  <\/td><td>1  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 3<\/td><td>4  <\/td><td>5  <\/td><td>6  <\/td><td>0  <\/td><td>1  <\/td><td>2  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 4<\/td><td>5  <\/td><td>6  <\/td><td>0  <\/td><td>1  <\/td><td>2  <\/td><td>3  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 5<\/td><td>6  <\/td><td>0  <\/td><td>1  <\/td><td>2  <\/td><td>3  <\/td><td>4  <\/td><\/tr>\n<tr><td style=\"text-align: right;\"> 6<\/td><td>0  <\/td><td>1  <\/td><td>2  <\/td><td>3  <\/td><td>4  <\/td><td>5  <\/td><\/tr>\n<\/tbody>\n<\/table>\n<\/td><\/tr><\/table>\n\n<p>Plot twist: we are now going to deal with an elliptic curve defined over\n\\(\\mathbb{F}_p\\). Turns out the equations for addition with respect to a curve,\n\\eqref{eqn:point_r}, are still well-defined: they only use simple arithmetic\noperations (*, \/, +, -) anyway. Unfortunately, we no longer have the geometric\nintuition, as our curve plotted will now look like just a bunch of points.<\/p>\n\n<h1 id=\"part-3-toy-elliptic-curve-over-mathbbf_37\">Part 3: Toy Elliptic Curve over \\(\\mathbb{F}_{37}\\)<\/h1>\n\n<p>I wrote some auxiliary code that implements fields and elliptic curves, attached in\nappendix. For now, let\u2019s use play with it to get used to the elliptic curves\nover prime fields:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">def<\/span> <span class=\"nf\">generate_span<\/span><span class=\"p\">(<\/span><span class=\"n\">start_point<\/span><span class=\"p\">):<\/span>  <span class=\"c1\"># keep adding until we hit zero\n<\/span>    <span class=\"n\">span<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">start_point<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">while<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">span<\/span><span class=\"p\">[<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"n\">zero<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">span<\/span><span class=\"p\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">span<\/span><span class=\"p\">[<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span> <span class=\"n\">start_point<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">span<\/span>\n\n<span class=\"n\">ec<\/span> <span class=\"o\">=<\/span> <span class=\"n\">EC<\/span><span class=\"p\">(<\/span><span class=\"mi\">11<\/span><span class=\"p\">,<\/span> <span class=\"mi\">16<\/span><span class=\"p\">)<\/span> <span class=\"c1\"># initiate y^2 = x^3 + 11x + 16\n<\/span><span class=\"n\">field_37<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Field<\/span><span class=\"p\">(<\/span><span class=\"mi\">37<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">point1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"n\">field_37<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">),<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span> <span class=\"c1\"># y=None will find a point on the curve\n<\/span><span class=\"n\">span1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">generate_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point1<\/span><span class=\"p\">)<\/span>\n\n<span class=\"o\">&gt;<\/span> <span class=\"n\">span1<\/span>\n<span class=\"p\">[[<\/span><span class=\"mi\">0<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">4<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"mi\">36<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"mi\">5<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">23<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"mi\">5<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">14<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"mi\">36<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">35<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">33<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">,<\/span>\n <span class=\"p\">[<\/span><span class=\"bp\">None<\/span><span class=\"p\">,<\/span> <span class=\"bp\">None<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><span class=\"p\">]<\/span> <span class=\"c1\"># zero<\/span><\/code><\/pre><\/figure>\n\n<p>I started with a point \\((0, 4)\\), module 37, and kept adding it until I reached\n\\(O\\). I have to reach \\(O\\), because the number of points on the curve is\nfinite, so they have to start repeating:<\/p>\n\n\\[nP = mP \\implies (n-m)P = 0,\\]\n\n<p>for some \\(n \\neq m\\). Are there any more points on the curve? Let\u2019s find out:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">def<\/span> <span class=\"nf\">find_outside_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">span<\/span> <span class=\"o\">=<\/span> <span class=\"n\">generate_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"n\">point<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">p<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"n\">point<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"p\">),<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">except<\/span> <span class=\"nb\">ValueError<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">continue<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">p<\/span> <span class=\"ow\">not<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">span<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">p<\/span>\n\n<span class=\"n\">point2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">find_outside_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point1<\/span><span class=\"p\">)<\/span>\n<span class=\"o\">&gt;<\/span><span class=\"n\">point2<\/span>\n<span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2083\u2087<\/span><span class=\"p\">,<\/span> <span class=\"mi\">18<\/span><span class=\"p\">]<\/span><span class=\"n\">_<\/span><span class=\"err\">\u2081\u2081<\/span><span class=\"p\">,<\/span><span class=\"err\">\u2081\u2086<\/span><\/code><\/pre><\/figure>\n\n<p>Yes, there\u2019s at least one more point: \\((1, 18)\\). Any more?<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"o\">&gt;<\/span> <span class=\"n\">find_outside_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point2<\/span><span class=\"p\">)<\/span>\n<span class=\"bp\">None<\/span><\/code><\/pre><\/figure>\n\n<p>Looks like \\((1, 18)\\) generates all points on our curve. How many points do\nwe have? 49:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"o\">&gt;<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">generate_span<\/span><span class=\"p\">(<\/span><span class=\"n\">point2<\/span><span class=\"p\">)),<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">span1<\/span><span class=\"p\">)<\/span>\n<span class=\"mi\">49<\/span><span class=\"p\">,<\/span> <span class=\"mi\">7<\/span><\/code><\/pre><\/figure>\n\n<p>In mathematics , we say that the order of <code class=\"language-plaintext highlighter-rouge\">point2<\/code> is 49, whilst the\norder of <code class=\"language-plaintext highlighter-rouge\">point1<\/code> is 7, where order is the number of times we add until we\nreach zero. <code class=\"language-plaintext highlighter-rouge\">point2<\/code> in this toy example plays the same role that number\n\\(1\\) plays in integers: by adding \\(1\\) repeatedly we an generate all\npositive integers. Same holds for <code class=\"language-plaintext highlighter-rouge\">point2<\/code>: by adding it repeatedly we generate\nall points on the curve. OK, hopefully you get a better feel for this object.\nLet\u2019s proceed.<\/p>\n\n<h1 id=\"part-4-ethereum-address\">Part 4: Ethereum Address<\/h1>\n\n<p>I went on <a href=\"https:\/\/vanity-eth.tk\/\">vanity-eth.tk<\/a> and generated a public and a\nprivate key:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"mh\">0xeace72e038dd840a468986654448a7d6d3e1a750<\/span> <span class=\"c1\"># public\n<\/span><span class=\"mh\">0xf6096531d756e52953455522cacc2a1effe504577233df66d3a3110231ff918c<\/span> <span class=\"c1\"># private<\/span><\/code><\/pre><\/figure>\n\n<p>We have already covered all the material needed to replicate such\ncomputation. Both Ethereum and Bitcoin use an elliptic curve \\(y^2 = x^3 + 7\\)\nover \\(\\mathbb{F}_p\\), where\n\\(p = 2^{256} - 2^{32} - 2^{9} - 2^{8} - 2^{7} - 2^{6} - 2^{4} - 1\\), a very large prime.<\/p>\n\n<p>It turns out whilst calculating \\(n * P = Q\\), i.e. summing \\(P\\) with\nitself \\(n\\)-times, is computationally easy, finding \\(n\\), given \\(P\\)\nand \\(Q\\) is computationally hard. So the private key is \\(n\\), whilst the\npublic key is \\(n * P\\), for some specified \\(P\\). Below is the code that\ndefines the curve and the specified point, taken from the <a href=\"https:\/\/en.bitcoin.it\/wiki\/Secp256k1\">secp256k1<\/a> specs:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">p<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">256<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">32<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">9<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">8<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">7<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">6<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">2<\/span><span class=\"o\">**<\/span><span class=\"mi\">4<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span>\n<span class=\"c1\"># hex codes for compactness, those are just large integers\n<\/span><span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"mh\">0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798<\/span>\n<span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"mh\">0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8<\/span>\n<span class=\"n\">point<\/span> <span class=\"o\">=<\/span> <span class=\"n\">EC<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">7<\/span><span class=\"p\">).<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"n\">Field<\/span><span class=\"p\">(<\/span><span class=\"n\">p<\/span><span class=\"p\">).<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">),<\/span> <span class=\"n\">y<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<p>Finally, we can generate the public point using multiplication:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">pp<\/span> <span class=\"o\">=<\/span> <span class=\"mh\">0xf6096531d756e52953455522cacc2a1effe504577233df66d3a3110231ff918c<\/span> <span class=\"o\">*<\/span> <span class=\"n\">point<\/span><\/code><\/pre><\/figure>\n\n<p>That\u2019s almost our public key, but not quite. We now encode (x, y) coordinates\nof our public point in hex, to get something like<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">def<\/span> <span class=\"nf\">public<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">or<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n\t<span class=\"k\">raise<\/span> <span class=\"nb\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Zero can't be public\"<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">)<\/span> <span class=\"k\">else<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span>\n    <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">)<\/span> <span class=\"k\">else<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span>\n    <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"s\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">x<\/span><span class=\"si\">:<\/span><span class=\"mi\">064<\/span><span class=\"n\">x<\/span><span class=\"si\">}{<\/span><span class=\"n\">y<\/span><span class=\"si\">:<\/span><span class=\"mi\">064<\/span><span class=\"n\">x<\/span><span class=\"si\">}<\/span><span class=\"s\">\"<\/span>\n\n<span class=\"o\">&gt;<\/span> <span class=\"n\">pp<\/span><span class=\"p\">.<\/span><span class=\"n\">public<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">c662ecf3e1c45eefbacd6244863dff8a23e414fc7f52567dcaf1796c898730ab8392<\/span>\n<span class=\"n\">c6811de16d4c235a7522b83cba9ed1824af40ac72932863689a342215033<\/span><\/code><\/pre><\/figure>\n\n<p>Finally, we compute <a href=\"https:\/\/en.wikipedia.org\/wiki\/SHA-3\">Keccak-256<\/a> hash function on the public point, and take\nlast 40 characters:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"o\">&gt;<\/span> <span class=\"n\">pp<\/span><span class=\"p\">.<\/span><span class=\"n\">ethereum<\/span><span class=\"p\">()<\/span>\n<span class=\"mh\">0xeace72e038dd840a468986654448a7d6d3e1a750<\/span><\/code><\/pre><\/figure>\n\n<p>Voil\u00e0!<\/p>\n\n<h1 id=\"credits\">Credits<\/h1>\n\n<p>Thanks to <a href=\"https:\/\/gist.github.com\/bellbind\/1414867\/04ccbaa3fe97304d3d9d91c36520a662f2e28a45\">bellbind<\/a> github account for his toy implementations and <a href=\"https:\/\/www.freecodecamp.org\/news\/how-to-create-an-ethereum-wallet-address-from-a-private-key-ae72b0eee27b\/\">Timur\nBadretdinov<\/a> for his blog post.<\/p>\n\n<h1 id=\"appendix\">Appendix<\/h1>\n<details><summary>ALL THE CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">from<\/span> <span class=\"nn\">__future__<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">annotations<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">typing<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">,<\/span> <span class=\"n\">Union<\/span><span class=\"p\">,<\/span> <span class=\"n\">Tuple<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">math<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">codecs<\/span>\n\n\n<span class=\"k\">def<\/span> <span class=\"nf\">to_subscript<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">SUB<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">str<\/span><span class=\"p\">.<\/span><span class=\"n\">maketrans<\/span><span class=\"p\">(<\/span><span class=\"s\">\"0123456789\"<\/span><span class=\"p\">,<\/span> <span class=\"s\">\"\u2080\u2081\u2082\u2083\u2084\u2085\u2086\u2087\u2088\u2089\"<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">).<\/span><span class=\"n\">translate<\/span><span class=\"p\">(<\/span><span class=\"n\">SUB<\/span><span class=\"p\">)<\/span>\n\n\n<span class=\"k\">def<\/span> <span class=\"nf\">egcd<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Tuple<\/span><span class=\"p\">[<\/span><span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">]:<\/span>\n    <span class=\"s\">\"\"\"extended GCD\n    returns: (s, t, gcd) as a*s + b*t == gcd\n    &gt;&gt;&gt; s, t, gcd = egcd(a, b)\n    &gt;&gt;&gt; assert a % gcd == 0 and b % gcd == 0\n    &gt;&gt;&gt; assert a * s + b * t == gcd\n    \"\"\"<\/span>\n    <span class=\"n\">s0<\/span><span class=\"p\">,<\/span> <span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">t0<\/span><span class=\"p\">,<\/span> <span class=\"n\">t1<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span>\n    <span class=\"k\">while<\/span> <span class=\"n\">b<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">q<\/span><span class=\"p\">,<\/span> <span class=\"n\">r<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">divmod<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">b<\/span><span class=\"p\">,<\/span> <span class=\"n\">r<\/span>\n        <span class=\"n\">s0<\/span><span class=\"p\">,<\/span> <span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">t0<\/span><span class=\"p\">,<\/span> <span class=\"n\">t1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">s0<\/span> <span class=\"o\">-<\/span> <span class=\"n\">q<\/span> <span class=\"o\">*<\/span> <span class=\"n\">s1<\/span><span class=\"p\">,<\/span> <span class=\"n\">t1<\/span><span class=\"p\">,<\/span> <span class=\"n\">t0<\/span> <span class=\"o\">-<\/span> <span class=\"n\">q<\/span> <span class=\"o\">*<\/span> <span class=\"n\">t1<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">s0<\/span><span class=\"p\">,<\/span> <span class=\"n\">t0<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span>\n\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Field<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">def<\/span> <span class=\"nf\">to_int<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">other<\/span>\n            <span class=\"k\">elif<\/span> <span class=\"nb\">hasattr<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">,<\/span> <span class=\"s\">'a'<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"nb\">hasattr<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">,<\/span> <span class=\"s\">'field'<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">assert<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"o\">==<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span>\n            <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">raise<\/span> <span class=\"nb\">NotImplementedError<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">field<\/span><span class=\"p\">:<\/span> <span class=\"n\">Field<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">):<\/span>\n            <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"o\">=<\/span> <span class=\"n\">field<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nb\">str<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__repr__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"s\">\"<\/span><span class=\"si\">{<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"si\">}<\/span><span class=\"s\">_<\/span><span class=\"si\">{<\/span><span class=\"n\">to_subscript<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">\"<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__mul__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">multiply<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__rmul__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">__mul__<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__add__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">add<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__radd__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">__add__<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__sub__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">sub<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__rsub__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">sub<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">),<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__neg__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">sub<\/span><span class=\"p\">(<\/span><span class=\"mi\">0<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__truediv__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">div<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">)))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__rtruediv__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">div<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">),<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__pow__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"nb\">pow<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">))<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__eq__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"nb\">object<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">eq<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">to_int<\/span><span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">))<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">False<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">p<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">):<\/span>\n        <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"o\">=<\/span> <span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">n<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">multiply<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">b<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">add<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">+<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">sub<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">-<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">div<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">b<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">b<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">raise<\/span> <span class=\"nb\">ZeroDivisionError<\/span>\n        <span class=\"n\">inv_b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">egcd<\/span><span class=\"p\">(<\/span><span class=\"n\">b<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">multiply<\/span><span class=\"p\">(<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">inv_b<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">pow<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"nb\">pow<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">div<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">),<\/span> <span class=\"o\">-<\/span><span class=\"n\">n<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span>\n        <span class=\"k\">while<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&amp;<\/span> <span class=\"mi\">1<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">1<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">r<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">multiply<\/span><span class=\"p\">(<\/span><span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&gt;&gt;<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">multiply<\/span><span class=\"p\">(<\/span><span class=\"n\">m2<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">r<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">eq<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">a<\/span> <span class=\"o\">-<\/span> <span class=\"n\">b<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">0<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">sqrt<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">int<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">a<\/span> <span class=\"o\">=<\/span> <span class=\"n\">a<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">i<\/span> <span class=\"o\">*<\/span> <span class=\"n\">i<\/span><span class=\"p\">)<\/span> <span class=\"o\">%<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">p<\/span> <span class=\"o\">==<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">i<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nb\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"s\">\"not found\"<\/span><span class=\"p\">)<\/span>\n\n\n<span class=\"k\">class<\/span> <span class=\"nc\">EC<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Point<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">ec<\/span><span class=\"p\">:<\/span> <span class=\"n\">EC<\/span><span class=\"p\">,<\/span>\n                     <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">[<\/span><span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]]<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">,<\/span>\n                     <span class=\"n\">y<\/span><span class=\"p\">:<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">[<\/span><span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]]<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">None<\/span><span class=\"p\">):<\/span>\n            <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">zero<\/span> <span class=\"o\">=<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">at<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">)<\/span>\n            <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ec<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__eq__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"o\">==<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">and<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"o\">==<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__neg__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">and<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"o\">-<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__add__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">or<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">other<\/span>\n            <span class=\"k\">if<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">or<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span>\n            <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span> <span class=\"o\">==<\/span> <span class=\"o\">-<\/span><span class=\"n\">other<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"bp\">None<\/span><span class=\"p\">,<\/span> <span class=\"bp\">None<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span> <span class=\"o\">==<\/span> <span class=\"n\">other<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">slope<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"mi\">3<\/span> <span class=\"o\">*<\/span> <span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">)<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"o\">+<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"mi\">2<\/span> <span class=\"o\">*<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">else<\/span><span class=\"p\">:<\/span>\n                <span class=\"n\">slope<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"o\">-<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"p\">(<\/span><span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"o\">-<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">)<\/span>\n\n            <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"n\">slope<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span> <span class=\"o\">-<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"o\">-<\/span> <span class=\"n\">other<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span>\n            <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">slope<\/span> <span class=\"o\">*<\/span> <span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"o\">-<\/span> <span class=\"n\">x<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span>\n\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__mul__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">r<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">point<\/span><span class=\"p\">(<\/span><span class=\"bp\">None<\/span><span class=\"p\">,<\/span> <span class=\"bp\">None<\/span><span class=\"p\">),<\/span> <span class=\"bp\">self<\/span>\n            <span class=\"c1\"># O(log2(n)) add\n<\/span>            <span class=\"k\">while<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&gt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">if<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&amp;<\/span> <span class=\"mi\">1<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">1<\/span><span class=\"p\">:<\/span>\n                    <span class=\"n\">r<\/span> <span class=\"o\">+=<\/span> <span class=\"n\">m2<\/span>\n                <span class=\"n\">n<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">n<\/span> <span class=\"o\">&gt;&gt;<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"n\">m2<\/span> <span class=\"o\">+<\/span> <span class=\"n\">m2<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">r<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__rmul__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">n<\/span><span class=\"p\">:<\/span> <span class=\"nb\">int<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">__mul__<\/span><span class=\"p\">(<\/span><span class=\"n\">n<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"s\">\"[<\/span><span class=\"si\">{<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"si\">}<\/span><span class=\"s\">, <\/span><span class=\"si\">{<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"si\">}<\/span><span class=\"s\">]\"<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">__repr__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">):<\/span>\n            <span class=\"n\">t<\/span> <span class=\"o\">=<\/span> <span class=\"n\">to_subscript<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"s\">\"[<\/span><span class=\"si\">{<\/span><span class=\"nb\">repr<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">, <\/span><span class=\"si\">{<\/span><span class=\"nb\">str<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">]_<\/span><span class=\"si\">{<\/span><span class=\"n\">t<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">,<\/span><span class=\"si\">{<\/span><span class=\"n\">t<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">ec<\/span><span class=\"p\">.<\/span><span class=\"n\">b<\/span><span class=\"p\">)<\/span><span class=\"si\">}<\/span><span class=\"s\">\"<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">public<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">if<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span> <span class=\"ow\">or<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span> <span class=\"ow\">is<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">raise<\/span> <span class=\"nb\">ValueError<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Zero can't be public\"<\/span><span class=\"p\">)<\/span>\n\n            <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">)<\/span> <span class=\"k\">else<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span>\n            <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">)<\/span> <span class=\"k\">else<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y<\/span>\n            <span class=\"k\">return<\/span> <span class=\"sa\">f<\/span><span class=\"s\">\"<\/span><span class=\"si\">{<\/span><span class=\"n\">x<\/span><span class=\"si\">:<\/span><span class=\"mi\">064<\/span><span class=\"n\">x<\/span><span class=\"si\">}{<\/span><span class=\"n\">y<\/span><span class=\"si\">:<\/span><span class=\"mi\">064<\/span><span class=\"n\">x<\/span><span class=\"si\">}<\/span><span class=\"s\">\"<\/span>\n\n        <span class=\"k\">def<\/span> <span class=\"nf\">ethereum<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">str<\/span><span class=\"p\">:<\/span>\n            <span class=\"c1\"># pip install pycryptodomex\n<\/span>            <span class=\"kn\">from<\/span> <span class=\"nn\">Cryptodome.Hash<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">keccak<\/span>\n            <span class=\"n\">public_key_bytes<\/span> <span class=\"o\">=<\/span> <span class=\"n\">codecs<\/span><span class=\"p\">.<\/span><span class=\"n\">decode<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">public<\/span><span class=\"p\">(),<\/span> <span class=\"s\">'hex'<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">keccak_hash<\/span> <span class=\"o\">=<\/span> <span class=\"n\">keccak<\/span><span class=\"p\">.<\/span><span class=\"n\">new<\/span><span class=\"p\">(<\/span><span class=\"n\">digest_bits<\/span><span class=\"o\">=<\/span><span class=\"mi\">256<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">keccak_hash<\/span><span class=\"p\">.<\/span><span class=\"n\">update<\/span><span class=\"p\">(<\/span><span class=\"n\">public_key_bytes<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">keccak_digest<\/span> <span class=\"o\">=<\/span> <span class=\"n\">keccak_hash<\/span><span class=\"p\">.<\/span><span class=\"n\">hexdigest<\/span><span class=\"p\">()<\/span>\n            <span class=\"c1\"># Take the last 20 bytes\n<\/span>            <span class=\"n\">wallet_len<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">40<\/span>\n            <span class=\"n\">wallet<\/span> <span class=\"o\">=<\/span> <span class=\"s\">'0x'<\/span> <span class=\"o\">+<\/span> <span class=\"n\">keccak_digest<\/span><span class=\"p\">[<\/span><span class=\"o\">-<\/span><span class=\"n\">wallet_len<\/span><span class=\"p\">:]<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">wallet<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">__init__<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">a<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">],<\/span> <span class=\"n\">b<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]):<\/span>\n        <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">b<\/span> <span class=\"o\">=<\/span> <span class=\"n\">a<\/span><span class=\"p\">,<\/span> <span class=\"n\">b<\/span>  <span class=\"c1\"># y^2 = (x^3 + ax + b) % p\n<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">point<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">[<\/span><span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]],<\/span> <span class=\"n\">y<\/span><span class=\"p\">:<\/span> <span class=\"n\">Optional<\/span><span class=\"p\">[<\/span><span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]]):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">EC<\/span><span class=\"p\">.<\/span><span class=\"n\">Point<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">y_squared<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">x<\/span><span class=\"o\">**<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span> <span class=\"o\">*<\/span> <span class=\"n\">x<\/span> <span class=\"o\">+<\/span> <span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">b<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">at<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">,<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">])<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">Union<\/span><span class=\"p\">[<\/span><span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">]:<\/span>\n        <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"nb\">int<\/span><span class=\"p\">,<\/span> <span class=\"nb\">float<\/span><span class=\"p\">)):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">math<\/span><span class=\"p\">.<\/span><span class=\"n\">sqrt<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y_squared<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">if<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"n\">Field<\/span><span class=\"p\">.<\/span><span class=\"n\">Int<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">field<\/span><span class=\"p\">.<\/span><span class=\"n\">sqrt<\/span><span class=\"p\">(<\/span><span class=\"bp\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">y_squared<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"n\">a<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"nb\">NotImplementedError<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<script type=\"text\/javascript\">\nvar request = new XMLHttpRequest();\nrequest.open(\"GET\", \"..\/..\/..\/..\/..\/assets\/elliptic.bokeh.js\", false);\nrequest.send(null)\nvar item = JSON.parse(request.responseText);\nBokeh.embed.embed_item(item, \"elliptic\");\n<\/script>\n\n"},{"title":"What the hell is t-SNE?","link":"https:\/\/afiodorov.github.io\/2019\/05\/27\/tsne\/","pubDate":"Mon, 27 May 2019 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>The other day I presented a t-SNE plot to a software engineer. \u201cBut what is\nit\u201d, I was asked. Good question, I thought to myself.<\/p>\n\n<h1 id=\"introduction\">Introduction<\/h1>\n\n<p>t-distributed Stochastic Neighbor Embedding (t-SNE) is a technique of\ndimensionality reduction. Data that has more than 3 dimensions is extremely\ncommon but is impossible to visualise. t-SNE is often used to reduce the data\nto 2 or 3 dimensions to produce beautiful plots like this:<\/p>\n\n<p><img src=\"\/assets\/tsne-mnist.png\" alt=\"tsne-mnist\" \/><\/p>\n\n<p>Above t-SNE was used to visualise <a href=\"https:\/\/en.wikipedia.org\/wiki\/MNIST_database\">MNIST dataset<\/a> which consists of single\ndigits like this:<\/p>\n\n<p><img src=\"\/assets\/MnistExamples.png\" alt=\"MnistExamples\" \/><\/p>\n\n<p>As we can see t-SNE correctly detected structure in the data and clustered\npoints correspondingly. But how?<\/p>\n\n<h1 id=\"watch-me-build-something-like-t-sne-from-scratch\">Watch me build something like t-SNE from scratch<\/h1>\n\n<p>I am not intending to re-build the entire algorithm here. Firstly, it\u2019s been\ndone by <a href=\"https:\/\/nlml.github.io\/in-raw-numpy\/in-raw-numpy-t-sne\/\">before<\/a> by another blogger who loves this shit. Secondly, I found\nsklearn\u2019s <a href=\"https:\/\/github.com\/scikit-learn\/scikit-learn\/blob\/master\/sklearn\/manifold\/t_sne.py\">implementation<\/a> self-explanatory for a motivated reader. I\u2019d like to\nexplain t-SNE for someone who is not <em>that<\/em> motivated. So let\u2019s build something\nlike t-SNE but not quite.<\/p>\n\n<p>First, for each pair of points, \\( i, j \\), in our dataset, convert the\nEuclidian distance between them into a conditional Gaussian probability. This\nmeans for each sample we concentrate most of the mass on its nearest neighbours.<\/p>\n\n\\[p_{j|i} = \\frac{\\exp \\left ( - || x_i - x_j || ^2 \\right ) }{\\sum_{k \\neq i} \\exp \\left ( - || x_i - x_k || ^2 \\right )}  \\hspace{2em} (1)\\]\n\n<p>For example, let\u2019s start with generating 7 random points in 2 dimensions. This\nis our data. In practice the data is typically multidimensional, but it\u2019s\nbetter to illustrate the intuition behind t-SNE using this simple example.<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">numpy<\/span> <span class=\"k\">as<\/span> <span class=\"n\">np<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">seaborn<\/span> <span class=\"k\">as<\/span> <span class=\"n\">sns<\/span>\n\n<span class=\"n\">seed<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">5<\/span>\n<span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">random<\/span><span class=\"p\">.<\/span><span class=\"n\">seed<\/span><span class=\"p\">(<\/span><span class=\"n\">seed<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">points<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">random<\/span><span class=\"p\">.<\/span><span class=\"n\">uniform<\/span><span class=\"p\">(<\/span><span class=\"n\">low<\/span><span class=\"o\">=-<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"n\">high<\/span><span class=\"o\">=<\/span><span class=\"mi\">3<\/span><span class=\"p\">,<\/span> <span class=\"n\">size<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"mi\">7<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">make_scatter<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">offset<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"nb\">max<\/span><span class=\"p\">()<\/span> <span class=\"o\">-<\/span> <span class=\"n\">X<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"nb\">min<\/span><span class=\"p\">())<\/span> <span class=\"o\">\/<\/span> <span class=\"mi\">100<\/span>\n    <span class=\"n\">ax<\/span> <span class=\"o\">=<\/span> <span class=\"n\">sns<\/span><span class=\"p\">.<\/span><span class=\"n\">scatterplot<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">],<\/span> <span class=\"n\">X<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">],<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">)):<\/span>\n        <span class=\"n\">ax<\/span><span class=\"p\">.<\/span><span class=\"n\">text<\/span><span class=\"p\">(<\/span><span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span> <span class=\"n\">offset<\/span><span class=\"p\">,<\/span> <span class=\"n\">X<\/span><span class=\"p\">[<\/span><span class=\"n\">i<\/span><span class=\"p\">,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">],<\/span> <span class=\"nb\">str<\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"p\">))<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ax<\/span>\n\n<span class=\"n\">make_scatter<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<p><img src=\"\/assets\/points_tsne.png\" alt=\"points-generated\" \/><\/p>\n\n<p>Next, we compute the conditional probabilities:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">pandas<\/span> <span class=\"k\">as<\/span> <span class=\"n\">pd<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">scipy.spatial.distance<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">pdist<\/span><span class=\"p\">,<\/span> <span class=\"n\">squareform<\/span>\n<span class=\"n\">MACHINE_EPSILON<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">finfo<\/span><span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">double<\/span><span class=\"p\">).<\/span><span class=\"n\">eps<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">compute_distances<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">transform<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">exp<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"n\">x<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">)):<\/span>\n    <span class=\"n\">distances<\/span> <span class=\"o\">=<\/span> <span class=\"n\">squareform<\/span><span class=\"p\">(<\/span><span class=\"n\">pdist<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">))<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">transform<\/span><span class=\"p\">(<\/span><span class=\"n\">distances<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">compute_probabilities<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">transform<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">exp<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"n\">x<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">)):<\/span>\n    <span class=\"n\">eye<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">eye<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">),<\/span> <span class=\"n\">dtype<\/span><span class=\"o\">=<\/span><span class=\"nb\">bool<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">distances_t<\/span> <span class=\"o\">=<\/span> <span class=\"n\">compute_distances<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">transform<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">distances_t<\/span><span class=\"p\">[<\/span><span class=\"n\">eye<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">0.0<\/span>\n    <span class=\"n\">distances_t<\/span> <span class=\"o\">\/=<\/span> <span class=\"n\">distances_t<\/span><span class=\"p\">.<\/span><span class=\"nb\">sum<\/span><span class=\"p\">(<\/span><span class=\"n\">axis<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">distances_t<\/span><span class=\"p\">[<\/span><span class=\"o\">~<\/span><span class=\"n\">eye<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">maximum<\/span><span class=\"p\">(<\/span><span class=\"n\">distances_t<\/span><span class=\"p\">[<\/span><span class=\"o\">~<\/span><span class=\"n\">eye<\/span><span class=\"p\">],<\/span> <span class=\"n\">MACHINE_EPSILON<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">distances_t<\/span>\n\n<span class=\"n\">x1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">around<\/span><span class=\"p\">(<\/span><span class=\"n\">compute_probabilities<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">),<\/span>  <span class=\"n\">decimals<\/span><span class=\"o\">=<\/span><span class=\"mi\">4<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span><span class=\"n\">x1<\/span><span class=\"p\">,<\/span>\n             <span class=\"n\">columns<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"sa\">f<\/span><span class=\"s\">\"p_<\/span><span class=\"si\">{<\/span> <span class=\"si\">{<\/span><span class=\"n\">j<\/span><span class=\"o\">|<\/span><span class=\"si\">{<\/span><span class=\"n\">i<\/span><span class=\"si\">}}}<\/span><span class=\"s\">\"<\/span> <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">))],<\/span>\n             <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">RangeIndex<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">),<\/span> <span class=\"n\">name<\/span><span class=\"o\">=<\/span><span class=\"s\">'j'<\/span><span class=\"p\">))<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<table>\n  <thead>\n    <tr>\n      <th>j<\/th>\n      <th>p_{j|0}<\/th>\n      <th>p_{j|1}<\/th>\n      <th>p_{j|2}<\/th>\n      <th>p_{j|3}<\/th>\n      <th>p_{j|4}<\/th>\n      <th>p_{j|5}<\/th>\n      <th>p_{j|6}<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.8373<\/td>\n      <td>0.1219<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.5947<\/td>\n      <td>0<\/td>\n    <\/tr>\n    <tr>\n      <td>1<\/td>\n      <td>0.774<\/td>\n      <td>0<\/td>\n      <td>0.034<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.402<\/td>\n      <td>0<\/td>\n    <\/tr>\n    <tr>\n      <td>2<\/td>\n      <td>0.0059<\/td>\n      <td>0.0018<\/td>\n      <td>0<\/td>\n      <td>0.9952<\/td>\n      <td>0.0009<\/td>\n      <td>0.0032<\/td>\n      <td>0.0012<\/td>\n    <\/tr>\n    <tr>\n      <td>3<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.8022<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.0005<\/td>\n    <\/tr>\n    <tr>\n      <td>4<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.0072<\/td>\n      <td>0.0002<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.9983<\/td>\n    <\/tr>\n    <tr>\n      <td>5<\/td>\n      <td>0.2201<\/td>\n      <td>0.161<\/td>\n      <td>0.0248<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n    <\/tr>\n    <tr>\n      <td>6<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n      <td>0.0099<\/td>\n      <td>0.0046<\/td>\n      <td>0.9991<\/td>\n      <td>0<\/td>\n      <td>0<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<p>Above, each column adds up to 1, meaning for each point we have a probability\ndistribution. As expected, points that are closest receive significantly more\nweight than points that are further away, e.g. point <code class=\"language-plaintext highlighter-rouge\">0<\/code> is close to <code class=\"language-plaintext highlighter-rouge\">1<\/code> and\nthe \\( p_{1|0} \\) value is 77.4%.<\/p>\n\n<p>Now, to find a t-SNE-like representation of our points, we are going to try to\nfind new 7 points, but instead of using a Gaussian density, we will use\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Student%27s_t-distribution\">Student\u2019s t-distribution<\/a> with 1 degree of freedom (also known as\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Cauchy_distribution\">Cauchy<\/a>). So the challenge is to find new 7 points, \\(y_{\\cdot}\\), such that\ntheir transformed Euclidean distances, \\(q_{j|i}\\),<\/p>\n\n\\[q_{j|i} = \\frac{ \\left ( 1 + || y_i - y_j || ^2 \\right ) ^ {-1} }{\\sum_{k \\neq l} \\left ( 1 + || y_k - y_l || ^2 \\right ) ^ {-1} }\\]\n\n<p>are very close to \\(p_{j|i}\\). Let\u2019s just do it by brute-forcing<sup id=\"fnref:1\" role=\"doc-noteref\"><a href=\"#fn:1\" class=\"footnote\" rel=\"footnote\">1<\/a><\/sup>. I\u2019ll start\nwith exact same data-points but iteratively adjust their positions until the\nmatrix of <code class=\"language-plaintext highlighter-rouge\">q<\/code>\u2019s is close to the matrix of <code class=\"language-plaintext highlighter-rouge\">p<\/code>\u2019s. A process that I visualised in\nthe video below:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">from<\/span> <span class=\"nn\">scipy.optimize<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">minimize<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">make_loss<\/span><span class=\"p\">(<\/span><span class=\"n\">target_points<\/span><span class=\"p\">,<\/span> <span class=\"n\">itermediate<\/span><span class=\"o\">=<\/span><span class=\"bp\">None<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">accumulate<\/span> <span class=\"o\">=<\/span> <span class=\"n\">itermediate<\/span> <span class=\"k\">if<\/span> <span class=\"n\">itermediate<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"bp\">None<\/span> <span class=\"k\">else<\/span> <span class=\"bp\">None<\/span>\n\n    <span class=\"n\">distances_eucledian<\/span> <span class=\"o\">=<\/span> <span class=\"n\">compute_probabilities<\/span><span class=\"p\">(<\/span><span class=\"n\">target_points<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">loss<\/span><span class=\"p\">(<\/span><span class=\"n\">points_raveled<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">accumulate<\/span> <span class=\"ow\">is<\/span> <span class=\"ow\">not<\/span> <span class=\"bp\">None<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">accumulate<\/span><span class=\"p\">.<\/span><span class=\"n\">append<\/span><span class=\"p\">(<\/span><span class=\"n\">points_raveled<\/span><span class=\"p\">)<\/span>\n\n        <span class=\"n\">points<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"n\">points_raveled<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n        <span class=\"n\">distances<\/span> <span class=\"o\">=<\/span> <span class=\"n\">compute_probabilities<\/span><span class=\"p\">(<\/span>\n                        <span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">transform<\/span><span class=\"o\">=<\/span><span class=\"k\">lambda<\/span> <span class=\"n\">x<\/span><span class=\"p\">:<\/span> <span class=\"mi\">1<\/span><span class=\"o\">\/<\/span><span class=\"p\">(<\/span><span class=\"mi\">1<\/span> <span class=\"o\">+<\/span> <span class=\"n\">x<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"nb\">sum<\/span><span class=\"p\">((<\/span><span class=\"n\">distances<\/span> <span class=\"o\">-<\/span> <span class=\"n\">distances_eucledian<\/span><span class=\"p\">)<\/span><span class=\"o\">**<\/span><span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">loss<\/span>\n\n<span class=\"n\">accumulate<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[]<\/span>\n<span class=\"n\">loss<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_loss<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">itermediate<\/span><span class=\"o\">=<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">res<\/span> <span class=\"o\">=<\/span> <span class=\"n\">minimize<\/span><span class=\"p\">(<\/span><span class=\"n\">loss<\/span><span class=\"p\">,<\/span> <span class=\"n\">points<\/span><span class=\"p\">.<\/span><span class=\"n\">ravel<\/span><span class=\"p\">(),<\/span> <span class=\"n\">tol<\/span><span class=\"o\">=<\/span><span class=\"mf\">1e-6<\/span><span class=\"p\">)<\/span>\n\n<span class=\"n\">new_points<\/span> <span class=\"o\">=<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"n\">res<\/span><span class=\"p\">.<\/span><span class=\"n\">x<\/span><span class=\"p\">,<\/span> <span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">))<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<video width=\"480\" height=\"320\" controls=\"controls\">\n  <source src=\"\/assets\/points_moving.mp4\" type=\"video\/mp4\" \/>\n<\/video>\n\n<p>Let\u2019s compare the new points to the original points:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">matplotlib.pyplot<\/span> <span class=\"k\">as<\/span> <span class=\"n\">plt<\/span>\n\n<span class=\"n\">fig<\/span> <span class=\"o\">=<\/span> <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"n\">figure<\/span><span class=\"p\">(<\/span><span class=\"n\">figsize<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"mi\">14<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">))<\/span>\n<span class=\"n\">ax1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">add_subplot<\/span><span class=\"p\">(<\/span><span class=\"mi\">121<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">make_scatter<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax1<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">add_subplot<\/span><span class=\"p\">(<\/span><span class=\"mi\">122<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">make_scatter<\/span><span class=\"p\">(<\/span><span class=\"n\">new_points<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax2<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax1<\/span><span class=\"p\">.<\/span><span class=\"n\">set_title<\/span><span class=\"p\">(<\/span><span class=\"s\">'original points'<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax2<\/span><span class=\"p\">.<\/span><span class=\"n\">set_title<\/span><span class=\"p\">(<\/span><span class=\"s\">'new points, minimising |P-Q|'<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<p><img src=\"\/assets\/new_points_tsne.png\" alt=\"new-points-tsne\" \/><\/p>\n\n<p>We see that points that were close together got even closer and points that\nwere far apart got spread out. This is the underlying idea behind t-SNE: to\nwarp the space in this manner. This happened because the tail of the\nt-distribution is much heavier than the tail of the Gaussian distribution:<\/p>\n\n<p><img src=\"\/assets\/tails.png\" alt=\"tails\" \/><\/p>\n\n<p>This means that we have to push distant points further away and pull close\npoints closer for our new probabilities to match the original probabilities. The\nmotivation behind applying such transformation is to address the so-called\n\u201ccrowding problem\u201d. If we were to distribute points uniformly at random on a\nhypersphere with many dimensions, most points would end up close to the edges.\nThis is because the proportion of volume close to the edges\nrapidly approaches one as we increase the number of dimensions:<\/p>\n\n\\[\\frac{r^{d} - (r-1)^{d}}{r^d} \\xrightarrow[d \\to \\infty]{} 1,\\]\n\n<p>where \\(r^d\\) is the volume of a hypersphere and \\(r^d - (r-1)^d\\) is the\nvolume of the crust of the hypersphere.<\/p>\n\n<p>The above limit means if we projected linearly we\u2019d see points crowded around\nthe edges of a circle. With warping we pull some of those closer to the center\nand push many points far way from the origin.<\/p>\n\n<h1 id=\"conclusion\">Conclusion<\/h1>\n\n<p>If you have made this far, hopefully you have a better understanding of how\nt-SNE works. Well, at least I do. Now I am going to go over details that I\nglossed over, but briefly.<\/p>\n\n<p>t-SNE actually deals with joint probabilities, defined as<\/p>\n\n\\[p_{ij} = \\frac{p_{i|j} + p_{j|i}}{2N},\\]\n\n<p>where \\(N\\) is the size of the dataset. Division by \\(2N\\) simply makes\nsure probabilities add up to 1. This makes the algorithm more robust to\noutliers.  Note that joint probabilities are symmetric.  When looking for\n\\(q_{ij}\\) <a href=\"https:\/\/en.wikipedia.org\/wiki\/Kullback%E2%80%93Leibler_divergence\">Kullback-Leibler divergence<\/a> is used, as it\u2019s the\ninformation-theoretic way of defining how similar two distributions are one to\nanother. In equation (1) I used Gaussian distribution with variance 2.\nHowever, in real t-SNE variance is estimated for each point using perplexity\nparameter, defined as 2 raised to the power of <a href=\"https:\/\/en.wikipedia.org\/wiki\/Entropy_(information_theory)\">Shannon\u2019s entropy<\/a>.\nThe perplexity is constant for each point: this way the variance is determined\nby the density of the region around each point.  Finally, when \\(q\\)\u2019s are\nsearched for, a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Gradient_descent#The_momentum_method\">gradient descent with momentum<\/a> is used.<\/p>\n\n<p>To complete the post, I am including real t-SNE applied to the 7 datapoints:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">from<\/span> <span class=\"nn\">sklearn.manifold<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">TSNE<\/span>\n\n<span class=\"n\">fig<\/span> <span class=\"o\">=<\/span> <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"n\">figure<\/span><span class=\"p\">(<\/span><span class=\"n\">figsize<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"mi\">14<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">))<\/span>\n<span class=\"n\">ax1<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">add_subplot<\/span><span class=\"p\">(<\/span><span class=\"mi\">121<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">make_scatter<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax1<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax2<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">add_subplot<\/span><span class=\"p\">(<\/span><span class=\"mi\">122<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">make_scatter<\/span><span class=\"p\">(<\/span>\n    <span class=\"n\">TSNE<\/span><span class=\"p\">(<\/span><span class=\"n\">perplexity<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">,<\/span>\n         <span class=\"n\">method<\/span><span class=\"o\">=<\/span><span class=\"s\">'exact'<\/span><span class=\"p\">,<\/span>\n         <span class=\"n\">random_state<\/span><span class=\"o\">=<\/span><span class=\"n\">seed<\/span><span class=\"p\">).<\/span><span class=\"n\">fit_transform<\/span><span class=\"p\">(<\/span><span class=\"n\">points<\/span><span class=\"p\">),<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax2<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax1<\/span><span class=\"p\">.<\/span><span class=\"n\">set_title<\/span><span class=\"p\">(<\/span><span class=\"s\">'original points'<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">ax2<\/span><span class=\"p\">.<\/span><span class=\"n\">set_title<\/span><span class=\"p\">(<\/span><span class=\"s\">'real t-SNE'<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<p><img src=\"\/assets\/real_tsne.png\" alt=\"real_tsne\" \/><\/p>\n\n<h1 id=\"see-more\">See more:<\/h1>\n\n<ul>\n  <li><a href=\"http:\/\/jmlr.csail.mit.edu\/papers\/volume9\/vandermaaten08a\/vandermaaten08a.pdf\">Original paper<\/a><\/li>\n  <li><a href=\"https:\/\/www.oreilly.com\/learning\/an-illustrated-introduction-to-the-t-sne-algorithm\">An illustrated introduction to the t-SNE algorithm<\/a><\/li>\n  <li><a href=\"https:\/\/distill.pub\/2016\/misread-tsne\/\">How to Use t-SNE Effectively<\/a><\/li>\n<\/ul>\n\n<h1 id=\"appendix\">Appendix<\/h1>\n\n<p>Animation code can be found here:<\/p>\n\n<details><summary>CODE<\/summary><p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">from<\/span> <span class=\"nn\">matplotlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">animation<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">IPython.display<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">HTML<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">find_lims<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">x_min<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"n\">x_max<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"n\">y_min<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"n\">y_max<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n\n    <span class=\"k\">for<\/span> <span class=\"n\">frame_points<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">accumulate<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">reshaped<\/span> <span class=\"o\">=<\/span> <span class=\"n\">frame_points<\/span><span class=\"p\">.<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">x<\/span> <span class=\"o\">=<\/span> <span class=\"n\">reshaped<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">reshaped<\/span><span class=\"p\">[:,<\/span> <span class=\"mi\">1<\/span><span class=\"p\">]<\/span>\n        <span class=\"n\">curr_xmin<\/span> <span class=\"o\">=<\/span> <span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">curr_xmax<\/span> <span class=\"o\">=<\/span> <span class=\"n\">x<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">curr_ymin<\/span> <span class=\"o\">=<\/span> <span class=\"n\">y<\/span><span class=\"p\">.<\/span><span class=\"nb\">min<\/span><span class=\"p\">()<\/span>\n        <span class=\"n\">curr_ymax<\/span> <span class=\"o\">=<\/span> <span class=\"n\">y<\/span><span class=\"p\">.<\/span><span class=\"nb\">max<\/span><span class=\"p\">()<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">curr_xmin<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">x_min<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">x_min<\/span> <span class=\"o\">=<\/span> <span class=\"n\">curr_xmin<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">curr_xmax<\/span> <span class=\"o\">&gt;<\/span> <span class=\"n\">x_max<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">x_max<\/span> <span class=\"o\">=<\/span> <span class=\"n\">curr_xmax<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">curr_ymin<\/span> <span class=\"o\">&lt;<\/span> <span class=\"n\">y_min<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">y_min<\/span> <span class=\"o\">=<\/span> <span class=\"n\">curr_ymin<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"n\">curr_ymax<\/span> <span class=\"o\">&gt;<\/span> <span class=\"n\">y_max<\/span><span class=\"p\">:<\/span>\n            <span class=\"n\">y_max<\/span> <span class=\"o\">=<\/span> <span class=\"n\">curr_ymax<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">array<\/span><span class=\"p\">([<\/span><span class=\"n\">x_min<\/span><span class=\"p\">,<\/span> <span class=\"n\">x_max<\/span><span class=\"p\">]),<\/span> <span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">array<\/span><span class=\"p\">([<\/span><span class=\"n\">y_min<\/span><span class=\"p\">,<\/span> <span class=\"n\">y_max<\/span><span class=\"p\">]))<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">animate<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">,<\/span> <span class=\"n\">frames<\/span><span class=\"o\">=<\/span><span class=\"mi\">1000<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">step<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">int<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">frames<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"n\">fig<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span> <span class=\"o\">=<\/span> <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"n\">subplots<\/span><span class=\"p\">()<\/span>\n    <span class=\"n\">scatter<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ax<\/span><span class=\"p\">.<\/span><span class=\"n\">scatter<\/span><span class=\"p\">([],<\/span> <span class=\"p\">[])<\/span>\n    <span class=\"n\">lims<\/span> <span class=\"o\">=<\/span> <span class=\"n\">find_lims<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">ax<\/span><span class=\"p\">.<\/span><span class=\"n\">set_xlim<\/span><span class=\"p\">(<\/span><span class=\"n\">lims<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span> <span class=\"o\">*<\/span> <span class=\"mf\">1.05<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">ax<\/span><span class=\"p\">.<\/span><span class=\"n\">set_ylim<\/span><span class=\"p\">(<\/span><span class=\"n\">lims<\/span><span class=\"p\">[<\/span><span class=\"mi\">1<\/span><span class=\"p\">]<\/span> <span class=\"o\">*<\/span> <span class=\"mf\">1.05<\/span><span class=\"p\">)<\/span>\n\n\n    <span class=\"c1\"># initialization function: plot the background of each frame\n<\/span>    <span class=\"k\">def<\/span> <span class=\"nf\">init<\/span><span class=\"p\">():<\/span>\n        <span class=\"n\">scatter<\/span><span class=\"p\">.<\/span><span class=\"n\">set_offsets<\/span><span class=\"p\">(<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">array<\/span><span class=\"p\">([[],<\/span> <span class=\"p\">[]]).<\/span><span class=\"n\">T<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">scatter<\/span><span class=\"p\">,)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">animate<\/span><span class=\"p\">(<\/span><span class=\"n\">i<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">j<\/span> <span class=\"o\">=<\/span> <span class=\"n\">i<\/span> <span class=\"o\">*<\/span> <span class=\"n\">step<\/span>\n        <span class=\"n\">scatter<\/span><span class=\"p\">.<\/span><span class=\"n\">set_offsets<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">[<\/span><span class=\"n\">j<\/span><span class=\"p\">].<\/span><span class=\"n\">reshape<\/span><span class=\"p\">(<\/span><span class=\"o\">-<\/span><span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"p\">(<\/span><span class=\"n\">scatter<\/span><span class=\"p\">,)<\/span>\n\n    <span class=\"n\">anim<\/span> <span class=\"o\">=<\/span> <span class=\"n\">animation<\/span><span class=\"p\">.<\/span><span class=\"n\">FuncAnimation<\/span><span class=\"p\">(<\/span><span class=\"n\">fig<\/span><span class=\"p\">,<\/span> <span class=\"n\">animate<\/span><span class=\"p\">,<\/span> <span class=\"n\">init_func<\/span><span class=\"o\">=<\/span><span class=\"n\">init<\/span><span class=\"p\">,<\/span>\n                                   <span class=\"n\">frames<\/span><span class=\"o\">=<\/span><span class=\"n\">frames<\/span><span class=\"p\">,<\/span> <span class=\"n\">interval<\/span><span class=\"o\">=<\/span><span class=\"mi\">10<\/span><span class=\"p\">,<\/span> <span class=\"n\">blit<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">anim<\/span>\n\n<span class=\"n\">HTML<\/span><span class=\"p\">(<\/span><span class=\"n\">animate<\/span><span class=\"p\">(<\/span><span class=\"n\">accumulate<\/span><span class=\"p\">).<\/span><span class=\"n\">to_html5_video<\/span><span class=\"p\">())<\/span><\/code><\/pre><\/figure>\n\n<\/p><\/details>\n\n<div class=\"footnotes\" role=\"doc-endnotes\">\n  <ol>\n    <li id=\"fn:1\" role=\"doc-endnote\">\n      <p><code class=\"language-plaintext highlighter-rouge\">scipy.optimize.minimize<\/code> uses <a href=\"https:\/\/en.wikipedia.org\/wiki\/Broyden%E2%80%93Fletcher%E2%80%93Goldfarb%E2%80%93Shanno_algorithm\">Broyden\u2013Fletcher\u2013Goldfarb\u2013Shanno<\/a>\n   algorithm, which tries to approximate gradient and the second derivative:\n   so it\u2019s not quite brute force.\u00a0<a href=\"#fnref:1\" class=\"reversefootnote\" role=\"doc-backlink\">&#8617;<\/a><\/p>\n    <\/li>\n  <\/ol>\n<\/div>\n"},{"title":"Computing SHAP values from scratch","link":"https:\/\/afiodorov.github.io\/2019\/05\/20\/shap-values-explained\/","pubDate":"Mon, 20 May 2019 00:00:00 +0000","author":"Tom A. Fiodorov","description":"<p>Recently I tested <a href=\"\/2019\/05\/19\/shap-feature-importances\/\">shap<\/a> feature importances. SHAP is a novel way of computing\nwhich features contributed the most towards the prediction. Whereas the method\nitself can be generalised to any classifier, it is especially well-suited for\ntree-based models.<\/p>\n\n<p>In this blog post I will try to explain what SHAP values are and why I find\nthem very compelling. Following Feynman\u2019s \u201cwhat I cannot create, I do not\nunderstand\u201d, let\u2019s try to compute SHAP feature contributions via a simple\nexample.<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">pandas<\/span> <span class=\"k\">as<\/span> <span class=\"n\">pd<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">matplotlib.pyplot<\/span> <span class=\"k\">as<\/span> <span class=\"n\">plt<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">sklearn.datasets<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">load_boston<\/span>\n<span class=\"kn\">from<\/span> <span class=\"nn\">sklearn.tree<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">DecisionTreeRegressor<\/span><span class=\"p\">,<\/span> <span class=\"n\">plot_tree<\/span>\n\n<span class=\"n\">d<\/span> <span class=\"o\">=<\/span> <span class=\"n\">load_boston<\/span><span class=\"p\">()<\/span>\n<span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"s\">'data'<\/span><span class=\"p\">],<\/span> <span class=\"n\">columns<\/span><span class=\"o\">=<\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"s\">'feature_names'<\/span><span class=\"p\">])<\/span>\n<span class=\"n\">y<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">Series<\/span><span class=\"p\">(<\/span><span class=\"n\">d<\/span><span class=\"p\">[<\/span><span class=\"s\">'target'<\/span><span class=\"p\">])<\/span>\n<span class=\"n\">df<\/span> <span class=\"o\">=<\/span> <span class=\"n\">df<\/span><span class=\"p\">[[<\/span><span class=\"s\">'RM'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'LSTAT'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'DIS'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'NOX'<\/span><span class=\"p\">]]<\/span>\n<span class=\"n\">clf<\/span> <span class=\"o\">=<\/span> <span class=\"n\">DecisionTreeRegressor<\/span><span class=\"p\">(<\/span><span class=\"n\">max_depth<\/span><span class=\"o\">=<\/span><span class=\"mi\">3<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">fit<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">,<\/span> <span class=\"n\">y<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">fig<\/span> <span class=\"o\">=<\/span> <span class=\"n\">plt<\/span><span class=\"p\">.<\/span><span class=\"n\">figure<\/span><span class=\"p\">(<\/span><span class=\"n\">figsize<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"mi\">20<\/span><span class=\"p\">,<\/span> <span class=\"mi\">5<\/span><span class=\"p\">))<\/span>\n<span class=\"n\">ax<\/span> <span class=\"o\">=<\/span> <span class=\"n\">fig<\/span><span class=\"p\">.<\/span><span class=\"n\">add_subplot<\/span><span class=\"p\">(<\/span><span class=\"mi\">111<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">_<\/span> <span class=\"o\">=<\/span> <span class=\"n\">plot_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">ax<\/span><span class=\"o\">=<\/span><span class=\"n\">ax<\/span><span class=\"p\">,<\/span> <span class=\"n\">feature_names<\/span><span class=\"o\">=<\/span><span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">columns<\/span><span class=\"p\">)<\/span><\/code><\/pre><\/figure>\n\n<p>Above I grabbed a <a href=\"https:\/\/scikit-learn.org\/stable\/modules\/generated\/sklearn.datasets.load_boston.html\">Boston dataset<\/a>, restricted it to 4 columns <code class=\"language-plaintext highlighter-rouge\">['RM', 'LSTAT',\n'DIS', 'NOX']<\/code> and built a decision tree, depicted below.<\/p>\n\n<p><img src=\"\/assets\/tree.png\" alt=\"Tree\" \/><\/p>\n\n<p>First, let\u2019s compute the shap values for the first row using the official\nimplementation:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">import<\/span> <span class=\"nn\">shap<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">tabulate<\/span>\n<span class=\"n\">explainer<\/span> <span class=\"o\">=<\/span> <span class=\"n\">shap<\/span><span class=\"p\">.<\/span><span class=\"n\">TreeExplainer<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">shap_values<\/span> <span class=\"o\">=<\/span> <span class=\"n\">explainer<\/span><span class=\"p\">.<\/span><span class=\"n\">shap_values<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">])<\/span>\n<span class=\"k\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">tabulate<\/span><span class=\"p\">.<\/span><span class=\"n\">tabulate<\/span><span class=\"p\">(<\/span><span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">{<\/span><span class=\"s\">'shap_value'<\/span><span class=\"p\">:<\/span> <span class=\"n\">shap_values<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">(),<\/span>\n     <span class=\"s\">'feature_value'<\/span><span class=\"p\">:<\/span> <span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"n\">values<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">()},<\/span> <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">columns<\/span><span class=\"p\">),<\/span>\n                        <span class=\"n\">tablefmt<\/span><span class=\"o\">=<\/span><span class=\"s\">\"github\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"s\">\"keys\"<\/span><span class=\"p\">))<\/span><\/code><\/pre><\/figure>\n\n<table>\n  <thead>\n    <tr>\n      <th>\u00a0<\/th>\n      <th>shap_value<\/th>\n      <th>feature_value<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>RM<\/td>\n      <td>-2.3953<\/td>\n      <td>6.575<\/td>\n    <\/tr>\n    <tr>\n      <td>LSTAT<\/td>\n      <td>2.46131<\/td>\n      <td>4.98<\/td>\n    <\/tr>\n    <tr>\n      <td>DIS<\/td>\n      <td>-0.329802<\/td>\n      <td>4.09<\/td>\n    <\/tr>\n    <tr>\n      <td>NOX<\/td>\n      <td>0.636187<\/td>\n      <td>0.538<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<p>Note: one nice property of SHAP contributions is that their sum + sample mean\nis the same as the prediction:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"o\">&gt;<\/span> <span class=\"n\">shap_values<\/span><span class=\"p\">.<\/span><span class=\"nb\">sum<\/span><span class=\"p\">()<\/span> <span class=\"o\">+<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">()<\/span>\n<span class=\"mf\">22.905199364899673<\/span>\n<span class=\"o\">&gt;<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">predict<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">])<\/span>\n<span class=\"n\">array<\/span><span class=\"p\">([<\/span><span class=\"mf\">22.9052<\/span><span class=\"p\">])<\/span><\/code><\/pre><\/figure>\n\n<p>Below we\u2019ll figure out why that\u2019s the case. For now, let\u2019s start on computing\nthose values \u201cby hand\u201d.<\/p>\n\n<h1 id=\"shapley-values\">Shapley values<\/h1>\n\n<p>The underlying computation behind shap feature contributions is powered by a\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Shapley_value\">solution<\/a> taken from game theory. The setup in our case is as follows:\n\\(N=4\\) features are now allowed to form coalitions. The worth, \\(v\\), of a\ncoalition <code class=\"language-plaintext highlighter-rouge\">['RM', 'LSTAT']<\/code> is simply<\/p>\n\n\\[v(RM, LSTAT) = E[y|RM=6.575,LSTAT=4.980]\\]\n\n<p>i.e. the prediction of the classifier if only values of <code class=\"language-plaintext highlighter-rouge\">RM<\/code> and <code class=\"language-plaintext highlighter-rouge\">LSTAT<\/code> are\nknown. Following<\/p>\n\n\\[{\\displaystyle \\varphi _{i}(v)={\\frac {1}{N}}\\sum _{S\\subseteq N\\setminus \\{i\\}}{\\binom {N-1}{|S|}}^{-1}(v(S\\cup \\{i\\})-v(S))}\\]\n\n<p>solution from the wikipedia page we can now redistribute total \u201cwinnings\u201d,\n\\(v(RM, LSTAT, DIS, NOX) - v()\\), fairly so that each feature \\(i\\) gets\n\\( \\varphi_{i} \\) contribution. Remark that total \u201cwinnings\u201d is simply\n\\(E[y|LSTAT=4.98,NOX=0.538,DIS=4.09,RM=6.575] - E[y]\\)<\/p>\n\n<p>where<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"p\">]<\/span><span class=\"o\">=<\/span><span class=\"n\">np<\/span><span class=\"p\">.<\/span><span class=\"n\">mean<\/span><span class=\"p\">(<\/span><span class=\"n\">y<\/span><span class=\"p\">)<\/span><span class=\"o\">=<\/span><span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">].<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">()<\/span><span class=\"o\">=<\/span><span class=\"mf\">22.5328<\/span><\/code><\/pre><\/figure>\n\n<p>and<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span><span class=\"o\">=<\/span><span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">predict<\/span><span class=\"p\">(<\/span><span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">])<\/span><span class=\"o\">=<\/span><span class=\"mf\">22.9052<\/span><\/code><\/pre><\/figure>\n\n<p>In English, we want to attribute how much we deviate from the naive prediction\n(sample mean) to each feature. Expanding the formula above we get that feature\ncontribution of <code class=\"language-plaintext highlighter-rouge\">RM<\/code>, \\( 4 \\varphi_{i} \\), is<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"p\">]<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"p\">(<\/span><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">])<\/span><span class=\"o\">\/<\/span><span class=\"mi\">3<\/span> <span class=\"o\">+<\/span>\n<span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">-<\/span> <span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">DIS<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.09<\/span><span class=\"p\">]<\/span><\/code><\/pre><\/figure>\n\n<p>For the sake of brevity, I would like to omit the explanation of the intuition\nbehind such formula. However I found skim-reading <a href=\"https:\/\/towardsdatascience.com\/one-feature-attribution-method-to-supposedly-rule-them-all-shapley-values-f3e04534983d\">this article<\/a> and watching\n<a href=\"https:\/\/www.youtube.com\/watch?v=w9O0fkfMkx0\">this video<\/a> helping me with understanding why Shapley values are calculated\nthis way.<\/p>\n\n<h2 id=\"figuring-out-conditional-expectations\">Figuring out conditional expectations<\/h2>\n\n<p>The remaining question is now how can we compute the conditional expectations\nin the above formula. Remember I said that SHAP method can in principle be\napplied to any classifier? The reason behind this is that<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span><\/code><\/pre><\/figure>\n\n<p>is just a prediction if <code class=\"language-plaintext highlighter-rouge\">DIS<\/code> value for the feature was not known. We could, in\ntheory, retrain without the <code class=\"language-plaintext highlighter-rouge\">DIS<\/code> feature and get a classifier to output this\nquantity. Or, alternatively, we could marginalise by ranging over observed\n<code class=\"language-plaintext highlighter-rouge\">DIS<\/code> values, getting a prediction, and taking a weighted sum according to how common\nthe value of <code class=\"language-plaintext highlighter-rouge\">DIS<\/code> is. However, all of those methods are prohibitively slow.\nIn the past I tried to approximate this quantity with the <a href=\"\/2016\/04\/26\/feature-contributions\/\">mode<\/a> of <code class=\"language-plaintext highlighter-rouge\">DIS<\/code>\ndistribution: however it only worked in a binary classification case.<\/p>\n\n<p>Turns out in a tree-based classifier, such quantity is easy to compute. Look at\nour tree again:<\/p>\n\n<p><img src=\"\/assets\/tree.png\" alt=\"Tree\" \/><\/p>\n\n<p>Our row forces us to walk the leftmost path of the tree. However, once we hit\nthe <code class=\"language-plaintext highlighter-rouge\">DIS &lt;= 1.385<\/code> node we\u2019re not sure where to go as <code class=\"language-plaintext highlighter-rouge\">DIS<\/code> is unknown.\nSolution: go both left and right and take a weighted sum. In other words:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"n\">E<\/span><span class=\"p\">[<\/span><span class=\"n\">y<\/span><span class=\"o\">|<\/span><span class=\"n\">LSTAT<\/span><span class=\"o\">=<\/span><span class=\"mf\">4.98<\/span><span class=\"p\">,<\/span><span class=\"n\">NOX<\/span><span class=\"o\">=<\/span><span class=\"mf\">0.538<\/span><span class=\"p\">,<\/span><span class=\"n\">RM<\/span><span class=\"o\">=<\/span><span class=\"mf\">6.575<\/span><span class=\"p\">]<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">5<\/span><span class=\"o\">\/<\/span><span class=\"mi\">255<\/span> <span class=\"o\">*<\/span> <span class=\"mf\">45.58<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">250<\/span><span class=\"o\">\/<\/span><span class=\"mi\">255<\/span> <span class=\"o\">*<\/span> <span class=\"mf\">22.905<\/span> <span class=\"o\">=<\/span> <span class=\"mf\">23.3496<\/span><\/code><\/pre><\/figure>\n\n<p>Let\u2019s write some code that does this for us:<\/p>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"k\">def<\/span> <span class=\"nf\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">node<\/span><span class=\"o\">=<\/span><span class=\"mi\">0<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">left_node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">children_left<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">right_node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">children_right<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">is_leaf<\/span> <span class=\"o\">=<\/span> <span class=\"n\">left_node<\/span> <span class=\"o\">==<\/span> <span class=\"n\">right_node<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"n\">is_leaf<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">].<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"n\">feature<\/span> <span class=\"o\">=<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span><span class=\"p\">[<\/span><span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">feature<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]]<\/span>\n    <span class=\"k\">if<\/span> <span class=\"n\">feature<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">if<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"n\">loc<\/span><span class=\"p\">[<\/span><span class=\"n\">feature<\/span><span class=\"p\">]<\/span> <span class=\"o\">&lt;=<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">threshold<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]:<\/span>\n            <span class=\"c1\"># go left\n<\/span>            <span class=\"k\">return<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">node<\/span><span class=\"o\">=<\/span><span class=\"n\">left_node<\/span><span class=\"p\">)<\/span>\n        <span class=\"c1\"># go right\n<\/span>        <span class=\"k\">return<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">node<\/span><span class=\"o\">=<\/span><span class=\"n\">right_node<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"c1\"># take weighted average of left and right\n<\/span>    <span class=\"n\">wl<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">n_node_samples<\/span><span class=\"p\">[<\/span><span class=\"n\">left_node<\/span><span class=\"p\">]<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">n_node_samples<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">wr<\/span> <span class=\"o\">=<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">n_node_samples<\/span><span class=\"p\">[<\/span><span class=\"n\">right_node<\/span><span class=\"p\">]<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">clf<\/span><span class=\"p\">.<\/span><span class=\"n\">tree_<\/span><span class=\"p\">.<\/span><span class=\"n\">n_node_samples<\/span><span class=\"p\">[<\/span><span class=\"n\">node<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">value<\/span> <span class=\"o\">=<\/span> <span class=\"n\">wl<\/span> <span class=\"o\">*<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">node<\/span><span class=\"o\">=<\/span><span class=\"n\">left_node<\/span><span class=\"p\">)<\/span>\n    <span class=\"n\">value<\/span> <span class=\"o\">+=<\/span> <span class=\"n\">wr<\/span> <span class=\"o\">*<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">node<\/span><span class=\"o\">=<\/span><span class=\"n\">right_node<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">value<\/span>\n\n<span class=\"o\">&gt;<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">coalition<\/span><span class=\"o\">=<\/span><span class=\"p\">[<\/span><span class=\"s\">'LSTAT'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'NOX'<\/span><span class=\"p\">,<\/span> <span class=\"s\">'RM'<\/span><span class=\"p\">],<\/span> <span class=\"n\">row<\/span><span class=\"o\">=<\/span><span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"n\">T<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">())<\/span>\n<span class=\"mf\">23.349803921568633<\/span><\/code><\/pre><\/figure>\n\n<h2 id=\"putting-it-all-together\">Putting it all together<\/h2>\n\n<figure class=\"highlight\"><pre><code class=\"language-python\" data-lang=\"python\"><span class=\"kn\">from<\/span> <span class=\"nn\">itertools<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">combinations<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">scipy<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">make_value_function<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">value<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">):<\/span>\n        <span class=\"n\">marginal_gain<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">c<\/span> <span class=\"o\">+<\/span> <span class=\"p\">[<\/span><span class=\"n\">col<\/span><span class=\"p\">],<\/span> <span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"n\">pred_tree<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">c<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">num_coalitions<\/span> <span class=\"o\">=<\/span> <span class=\"n\">scipy<\/span><span class=\"p\">.<\/span><span class=\"n\">special<\/span><span class=\"p\">.<\/span><span class=\"n\">comb<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"o\">-<\/span> <span class=\"mi\">1<\/span><span class=\"p\">,<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">marginal_gain<\/span> <span class=\"o\">\/<\/span> <span class=\"n\">num_coalitions<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">value<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">make_coalitions<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">rest<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">x<\/span> <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">row<\/span><span class=\"p\">.<\/span><span class=\"n\">index<\/span> <span class=\"k\">if<\/span> <span class=\"n\">x<\/span> <span class=\"o\">!=<\/span> <span class=\"n\">col<\/span><span class=\"p\">]<\/span>\n    <span class=\"k\">for<\/span> <span class=\"n\">i<\/span> <span class=\"ow\">in<\/span> <span class=\"nb\">range<\/span><span class=\"p\">(<\/span><span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">rest<\/span><span class=\"p\">)<\/span> <span class=\"o\">+<\/span> <span class=\"mi\">1<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">combinations<\/span><span class=\"p\">(<\/span><span class=\"n\">rest<\/span><span class=\"p\">,<\/span> <span class=\"n\">i<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">yield<\/span> <span class=\"nb\">list<\/span><span class=\"p\">(<\/span><span class=\"n\">x<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">compute_shap<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">v<\/span> <span class=\"o\">=<\/span> <span class=\"n\">make_value_function<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">sum<\/span><span class=\"p\">([<\/span><span class=\"n\">v<\/span><span class=\"p\">(<\/span><span class=\"n\">coal<\/span><span class=\"p\">)<\/span> <span class=\"o\">\/<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">coal<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">make_coalitions<\/span><span class=\"p\">(<\/span><span class=\"n\">row<\/span><span class=\"p\">,<\/span> <span class=\"n\">col<\/span><span class=\"p\">)])<\/span>\n\n<span class=\"k\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">tabulate<\/span><span class=\"p\">.<\/span><span class=\"n\">tabulate<\/span><span class=\"p\">(<\/span><span class=\"n\">pd<\/span><span class=\"p\">.<\/span><span class=\"n\">DataFrame<\/span><span class=\"p\">(<\/span>\n    <span class=\"p\">{<\/span><span class=\"s\">'shap_value'<\/span><span class=\"p\">:<\/span> <span class=\"n\">shap_values<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">(),<\/span>\n     <span class=\"s\">'my_shap'<\/span><span class=\"p\">:<\/span> <span class=\"p\">[<\/span><span class=\"n\">compute_shap<\/span><span class=\"p\">(<\/span><span class=\"n\">clf<\/span><span class=\"p\">,<\/span> <span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"n\">T<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">(),<\/span> <span class=\"n\">x<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">x<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">columns<\/span><span class=\"p\">],<\/span>\n     <span class=\"s\">'feature_value'<\/span><span class=\"p\">:<\/span> <span class=\"n\">df<\/span><span class=\"p\">[:<\/span><span class=\"mi\">1<\/span><span class=\"p\">].<\/span><span class=\"n\">values<\/span><span class=\"p\">.<\/span><span class=\"n\">squeeze<\/span><span class=\"p\">()<\/span>\n    <span class=\"p\">},<\/span> <span class=\"n\">index<\/span><span class=\"o\">=<\/span><span class=\"n\">df<\/span><span class=\"p\">.<\/span><span class=\"n\">columns<\/span><span class=\"p\">),<\/span>\n                        <span class=\"n\">tablefmt<\/span><span class=\"o\">=<\/span><span class=\"s\">\"github\"<\/span><span class=\"p\">,<\/span> <span class=\"n\">headers<\/span><span class=\"o\">=<\/span><span class=\"s\">\"keys\"<\/span><span class=\"p\">))<\/span><\/code><\/pre><\/figure>\n\n<table>\n  <thead>\n    <tr>\n      <th>\u00a0<\/th>\n      <th>shap_value<\/th>\n      <th>my_shap<\/th>\n      <th>feature_value<\/th>\n    <\/tr>\n  <\/thead>\n  <tbody>\n    <tr>\n      <td>RM<\/td>\n      <td>-2.3953<\/td>\n      <td>-2.3953<\/td>\n      <td>6.575<\/td>\n    <\/tr>\n    <tr>\n      <td>LSTAT<\/td>\n      <td>2.46131<\/td>\n      <td>2.46131<\/td>\n      <td>4.98<\/td>\n    <\/tr>\n    <tr>\n      <td>DIS<\/td>\n      <td>-0.329802<\/td>\n      <td>-0.329802<\/td>\n      <td>4.09<\/td>\n    <\/tr>\n    <tr>\n      <td>NOX<\/td>\n      <td>0.636187<\/td>\n      <td>0.636187<\/td>\n      <td>0.538<\/td>\n    <\/tr>\n  <\/tbody>\n<\/table>\n\n<p>And there you have it: we have replicated the computations in the <code class=\"language-plaintext highlighter-rouge\">shap<\/code>\n<a href=\"https:\/\/github.com\/slundberg\/shap\">library<\/a>. When SHAP values are computed for a forest of decision trees, we\nsimply average those. Because SHAP contributions are Shapley values we get\ncertain desired properties \u201cfor free\u201d:<\/p>\n\n<ul>\n  <li>contributions + bias = prediction<\/li>\n  <li>contributions of irrelevant features are 0<\/li>\n  <li>consistency: changing a model so a feature has a larger impact on the model\n             will never decrease the contribution assigned to that feature<\/li>\n<\/ul>\n\n<p>and thus I have become an advocate for using this method.<\/p>\n\n<h1 id=\"final-thoughts\">Final thoughts<\/h1>\n\n<p>In my eyes, the genius of Scott M. Lundberg, Gabriel G. Erion, and Su-In Lee\nwho published the shap library isn\u2019t that they used Shapley values: this has\nbeen known prior to them by Strumbelj, Erik, and Igor Kononenko all the way\nback in 2014, but the fact that they invented a fast <code class=\"language-plaintext highlighter-rouge\">pred_tree<\/code> algorithm. The\nprimitive recursive algorithm presented in this blog post would be too slow to\ndeploy in a live system for any reasonably-sized tree. When faced with a similar\nproblem of computing conditional expectations in the past and I ended up\napproximating these by going down the path that is closest to the current value\ninstead of taking the weighted average of the children. My hacky solution makes\ncomputations of contributions just as fast as predictions however it is less\nrobust. I include the fast \u201cAlgorithm 2\u201d from the <a href=\"https:\/\/arxiv.org\/pdf\/1802.03888.pdf\">tree shap paper<\/a>, but, after\nstaring at it for a few days by now, I have given up on any hope of\nunderstanding it just by reading it. Perhaps some motivated reader could email\nme the explanation. For now, this is good bye!<\/p>\n\n<p><img src=\"\/assets\/shap_algo2.png\" alt=\"shap_algo2\" \/><\/p>\n\n"}]}}