<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[HowdyTX]]></title><description><![CDATA[The unexamined algorithm is not worth implementing.]]></description><link>https://howdytx.technology/</link><image><url>https://howdytx.technology/favicon.png</url><title>HowdyTX</title><link>https://howdytx.technology/</link></image><generator>Ghost 5.81</generator><lastBuildDate>Tue, 14 Apr 2026 22:00:16 GMT</lastBuildDate><atom:link href="https://howdytx.technology/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Tech Policy Should Look Like Engineering Requirements]]></title><description><![CDATA[Why do some regulations fail to achieve their goals? Are they doomed to fail from the start?]]></description><link>https://howdytx.technology/tech-policy/</link><guid isPermaLink="false">68e03daa8daf5d0001ac419b</guid><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Tue, 30 Dec 2025 16:43:41 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="why-do-some-regulations-fail-to-achieve-their-goals" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Why do some regulations fail to achieve their goals?</span></h2>
                    <p id="are-they-doomed-to-fail-from-the-start" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Are they doomed to fail from the start?</span></p>
                    
                </div>
            </div>
        </div><p>In 1973, oil-exporting Arab countries embargoed shipments to countries that had supported Israel in the Yom Kippur War of that same year. This included the United States. Congress, in an attempt to reduce fuel consumption at home, signed the first Corporate Average Fuel Economy (CAFE) standards into law as a result.</p><p>These standards stuck around and evolved to focus on global warming and emissions instead. Around 2007, Congress rewrote the legislation to deal with some (legitimate) concerns. They created different efficiency targets for different vehicle &quot;footprints&quot; (base size, length times width) with larger vehicles having lower mileage per gallon requirements.</p><p>While the legislation was intended to reduce the amount of fuel consumed, it actually just <a href="https://me.engin.umich.edu/news-events/news/cafe-standards-could-mean-bigger-cars-not-smaller-ones/?ref=howdytx.technology" rel="noreferrer">incentivized manufacturers</a> to build larger vehicles and stop selling small ones. The CAFE standards killed the station wagon, birthed the modern SUV and luxury pickup truck, and failed to get us to the goal of 50 MPG average efficiency by 2025.</p><p>There&apos;s a similar story about unintended side effects from the British colonial administration of India. The government was concerned about the number of cobras in Delhi, and offered a bounty for each dead cobra brought in by hunters. The locals hunted cobras and were rewarded.</p><p>However, some of them started <em>breeding</em> cobras to take in and claim bounties with. As soon as the British got wind of the scam, they canceled the program. The scammers released their captive cobras, and the city was worse off than before. This idea of regulations creating &quot;perverse incentives&quot; is even called the &quot;<a href="https://en.wikipedia.org/wiki/Perverse_incentive?ref=howdytx.technology" rel="noreferrer">cobra effect.</a>&quot;</p><p>These are both famous examples of policy having unintended side effects. But why did CAFE fail to achieve the (ambitious) goals Congress set in 2007? Was it doomed to fail from the start?</p><p>CAFE&apos;s story isn&apos;t unique. A couple of conversations I&apos;ve had in the past six months got me thinking: regulations that suffer from the cobra effect have something in common. They&apos;re not written like engineering requirements, yet engineers have to follow them. In this post I&apos;ll touch on a couple other examples, and hopefully leave you wondering whether engineers could have written them better.</p><h2 id="how-lawyers-screwed-up">How Lawyers Screwed Up</h2><h3 id="gdpr-and-the-cost-of-compliance">GDPR and the Cost of Compliance</h3><p>Since 2018 the European Union has required all organizations which handle EU citizens&apos; data to comply with the General Data Protection Regulation (GDPR). This legislation was promoted as a way to give consumers power over how their data was used, and break the stranglehold of data-collecting/advertising monopolies like Google.</p><p>Well, <a href="https://siepr.stanford.edu/publications/policy-brief/balancing-act-protecting-privacy-protecting-competition?ref=howdytx.technology" rel="noreferrer">it didn&apos;t.</a> In fact, it actually made the advertising space <em>less</em> competitive. Big companies like Google easily absorbed the cost of GDPR compliance, while smaller companies and startups had their margins squeezed out by the extra burden. Companies like Microsoft, which is famously a law firm with a software engineering division attached, were already dealing with large-scale compliance tracking. Smaller firms were not, and were more impacted than the big ones.</p><p>GDPR and, to a lesser extent, other regulations like it (in <a href="https://www.legislation.gov.uk/ukpga/2018/12/contents?ref=howdytx.technology" rel="noreferrer">the UK</a>, <a href="https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?division=3.&amp;part=4.&amp;lawCode=CIV&amp;title=1.81.5&amp;ref=howdytx.technology" rel="noreferrer">California</a>, <a href="https://capitol.texas.gov/tlodocs/88R/billtext/html/HB00004F.htm?ref=howdytx.technology" rel="noreferrer">Texas</a>, and some other states) are more examples of a well-intentioned piece of legislation written by lawyers having the opposite effect they wanted. It fortified the position of the monopolies instead of breaking it.</p><p>To get a feel for how the GDPR reads, let&apos;s look at how <a href="https://gdpr-info.eu/art-32-gdpr/?ref=howdytx.technology" rel="noreferrer">Article 32</a> (Security of processing) opens:</p><blockquote>Taking into account the state of the art, the costs of implementation and the nature, scope, context and purposes of processing as well as the risk of varying likelihood and severity for the rights and freedoms of natural persons, the controller and the processor shall implement appropriate technical and organisational measures to ensure a level of security appropriate to the risk, including inter alia as appropriate:<br>    (1) the pseudonymisation and encryption of personal data;<br>    (2) the ability to ensure the ongoing confidentiality, integrity, availability and resilience of processing systems and services;<br>    (3) the ability to restore the availability and access to personal data in a timely manner in the event of a physical or technical incident;<br>    (4) a process for regularly testing, assessing and evaluating the effectiveness of technical and organisational measures for ensuring the security of the processing.</blockquote><p>What is a &quot;level of security appropriate to the risk?&quot; What does it mean to take into account &quot;costs of implementation?&quot; How available and resilient should processing systems be? What does &quot;timely manner&quot; mean? All of these questions are (intentionally) left to the courts to decide, but that creates friction and uncertainty.</p><p>Remember, GDPR was brought to you by the same geniuses that created cookie pop-ups. We&apos;ll come back to this later.</p><h3 id="americas-ear-fdpr-and-semiconductors">America&apos;s EAR, FDPR, and Semiconductors</h3><p>To slow the PRC&apos;s progress in designing advanced chips, the US government has applied export controls and other restrictions, with varying levels of effect. The regulations we&apos;ll discuss here were intended to hinder China&apos;s progress and protect American companies.</p><p>The US uses the Export Administration Regulations (EAR) as the primary framework for export controls. An entire agency, the Bureau of Industry and Security, handles the task of preventing sensitive technology from being sold to the wrong people. <em>This is not a bad thing;</em> our foreign trade shouldn&apos;t directly hurt our national interests. However, as a side effect, the regulations also hurt America&apos;s position in the semiconductor supply chain.</p><p>Before 2020, any foreign-made products containing more than 25% American-origin components were subject to US export controls. This was the <em>de minimis</em> rule, and it meant a device (e.g. a graphics card) made in Taiwan could be export-controlled by the US if more than 25% of the parts were American. Since the US doesn&apos;t want China to have access to advanced chips or chipmaking equipment, that card couldn&apos;t be sold to China.</p><p>However, the PRC has a population of over a billion people. It&apos;s a huge market. Of course companies want to sell to China. So they started &quot;designing out&quot; American components and swapping them for Japanese or Korean components instead, to keep the American-origin percentage below 25%. Then they could sell their product to China without being subject to changing export controls.</p><p>In 2020 the Foreign Direct Product Rule (FDPR) <a href="https://www.csis.org/analysis/contextualizing-national-security-concerns-over-chinas-domestically-produced-high-end-chip?ref=howdytx.technology" rel="noreferrer">was expanded</a> to fight the <em>de minimis</em> loophole. Now, all products designed with US software (e.g. Cadence EDA tools) or made with US-designed machines (e.g. semiconductor fabs) are subject to US export controls <em>regardless</em> of what percentage of the finished product is American.</p><p>This greatly expanded the scope of US export controls, but it also drove companies doing business with China to transition away from US toolchains. Huawei is <a href="https://technode.com/2023/09/21/huaweis-5g-chip-is-it-that-surprising/?ref=howdytx.technology" rel="noreferrer">swapping</a> US-sourced RF chips for Chinese ones, SMIC <a href="https://abachy.com/news/chinas-chipmaking-equipment-spending-set-decline-due-overcapacity-and?ref=howdytx.technology" rel="noreferrer">stockpiled</a> Japanese lithography equipment, and European companies like STMicroelectronics gained market share by positioning themselves as &quot;independent.&quot;</p><p>Asian and European companies benefitted from a &quot;de-risking&quot; spending spree by Chinese companies while American firms lost revenue and Japan kept supplying &quot;mature node&quot; (read: old) chip tech to China. The policies are slowing China&apos;s growth in semiconductors, but they&apos;ve also harmed the competitiveness of American firms in the process.</p><p>I&apos;m not going to pretend I know better on this one. National security and economic policy are full of cost-benefit analyses and weighing of trade-offs, and I have nowhere near a complete picture of what&apos;s involved. But surely a more coherent effort could have stopped advanced tech sales without incentivizing &quot;de-risking&quot; and &quot;designing out&quot; strategies in friendly countries.</p><h2 id="how-engineers-couldve-done-better">How Engineers Could&apos;ve Done Better</h2><p>Engineers write product requirements that lay out expectations for a completed system. These requirements have some features that CAFE, the GDPR, and America&apos;s export control regime all lack.</p><p>Some relevant properties of engineering requirements are these:</p><ul><li><strong>Atomicity: </strong>Compound statements are disallowed. An individual statement contains a single atomic requirement.</li><li><strong>Unambiguity: </strong>Subjective words like &quot;timely&quot; or &quot;safe&quot; aren&apos;t helpful; the courts just wind up defining them later.</li><li><strong>Verifiability:</strong> There is a feasible way to check that the requirement is met. This means you need a metric you can test.</li><li><strong>Quantifiability:</strong> The targets are specified precisely, so that they&apos;re unambiguous and verifiable.</li><li><strong>Consistency: </strong>Individual requirements don&apos;t contradict each other without defining a trade-off. You generally can&apos;t design a part with 300% margins that&apos;s <em>also</em> weight-efficient.</li><li><strong>Completeness:</strong> There are no unhandled edge cases, and negative requirements (what the system should <em>not</em> do) are included.</li></ul><p>Would regulations be improved if their authors tried to apply these principles? I think so.</p><h3 id="ada-requirements-done-right">ADA &amp; Requirements Done Right</h3><p>The Americans with Disabilities Act (ADA) changed the way our buildings and cities look by requiring accessibility be baked into designs from the start. It&apos;s had a massive positive impact, <a href="https://en.wikipedia.org/wiki/Curb_cut_effect?ref=howdytx.technology" rel="noreferrer">even for people without disabilities.</a> It&apos;s a case study in writing requirements-based regulation.</p><p>As an example, let&apos;s look at an excerpt of <a href="https://www.ada.gov/law-and-regs/ada/?ref=howdytx.technology#title-47---telegraphs-telephones-and-radiotelegraphs-title-iv" rel="noreferrer">Title IV</a> of the ADA.</p><blockquote>The [Federal Communications] Commission shall, not later than 1 year after July 26, 1990, prescribe regulations to implement this section, including regulations that&#x2014;<br>    (A) establish functional requirements, guidelines, and operations procedures for telecommunications relay services;<br>    (B) establish minimum standards that shall be met in carrying out subsection (c) of this section;<br>    (C) require that telecommunications relay services operate every day for 24 hours per day;<br>    (D) require that users of telecommunications relay services pay rates no greater than the rates paid for functionally equivalent voice communication services with respect to such factors as the duration of the call, the time of day, and the distance from point of origination to point of termination;<br>    (E) prohibit relay operators from failing to fulfill the obligations of common carriers by refusing calls or limiting the length of calls that use telecommunications relay services;<br>    (F) prohibit relay operators from disclosing the content of any relayed conversation and from keeping records of the content of any such conversation beyond the duration of the call; and<br>    (G) prohibit relay operators from intentionally altering a relayed conversation.</blockquote><p>This act empowers the FCC to set up hard engineering requirements for public infrastructure (in this case, telecomms equipment), so it&apos;s accessible to everyone. It&apos;s a brilliant and thoughtful piece of legislation.</p><p>One of the critiques of regulations that look like engineering requirements is that they&apos;re &quot;brittle.&quot; If a piece of legislation had, say, mandated SHA-1 as a hashing algorithm, it would be outdated today since SHA-1 is insecure. An amendment would be needed. By assigning an agency the power to update the specifics, you get clear engineering requirements that can be updated as technology evolves.</p><p>You can read the regulations implemented by the FCC <a href="https://www.ecfr.gov/current/title-47/part-64/subpart-F?ref=howdytx.technology#p-64.604(b)" rel="noreferrer">here.</a> No matter where you scroll, it feels a lot like an actual Product Requirements Document, but look at the section I linked. Each line lays out an atomic, verifiable, quantifiable, and unambiguous requirement. An engineer can test a system or building and determine whether it&apos;s compliant.</p><p>I&apos;m not saying the ADA <em>hasn&apos;t</em> created some perverse incentives. It has, especially around hiring decisions. But in general, the technical aspects are well-written and builders can reliably verify compliance.</p><h3 id="back-to-the-gdpr">Back to the GDPR</h3><p>The GPDR, on the other hand, violates every principle in the list, but perhaps it violates &quot;unambiguity&quot; most egregiously. Many terms in it lack hard definitions, and in the absence of rulings from the Court of Justice of the European Union (CJEU), lower authorities have issued directives and advice.</p><p>In September the CJEU <a href="https://www.kennedyslaw.com/en/thought-leadership/article/2025/what-key-eu-data-ruling-means-for-cross-border-transfers/?ref=howdytx.technology" rel="noreferrer">delivered a judgement</a> on whether &quot;pseudonymized&quot; data is personal data. The court considers a dataset &quot;personal data&quot; if <em>the intended recipient</em> is able to reconstruct the identities of the people involved. However, the current guidance from the European Data Protection Board (EDPB) considers pseudonymized data &quot;personal data&quot; in all cases. The EDPB directive is <em>more strict</em> than the current legal precedent, so the Board and the Court disagree.</p><p>If the term &quot;personal data&quot; was better defined, this conflict would be impossible, but at the moment, it smells like a loophole. I could offload data processing to a third party without having to keep up with GDPR compliance, as long as they don&apos;t have access to the identifiers or look-up table. According to the court, this is okay. According to the EDPB, I am about to be fined for non-compliance. Who&apos;s right?</p><p>I&apos;m convinced the ADA offers a better model. If all the GDPR did was empower the Data Protection Board to write specific requirements, the Board&apos;s definition would be the only definition. But that&apos;s not what happened, and now the EU is stuck with ambiguous definitions that must be hammered out in court.</p><h3 id="fixing-cafe">Fixing CAFE</h3><p>Like GDPR, I think CAFE violates the properties of good requirements, but in a different way. The issue with CAFE is more about &quot;consistency&quot; than &quot;unambiguity.&quot; You cannot simultaneously ask for a more efficient vehicle fleet <em>and</em> allow vehicles to be less efficient if they are larger. Companies will just build larger vehicles to avoid the extra engineering effort.</p><p>CAFE failed because it &quot;punished&quot; the wrong thing. Congress wanted to reduce fuel usage. Yet the standards made it harder to build smaller vehicles. Shouldn&apos;t the regulations have made it harder to guzzle gas instead?</p><p>I&apos;m no economist, but it seems like making more efficient cars cheaper, and making less efficient cars more expensive, would incentivize people to buy more efficient cars. Maybe a flat tax on less efficient vehicles would have the desired effect? I don&apos;t see it leading to ever-larger SUVs as a side effect, so perhaps it&apos;s already an improvement.</p><h3 id="good-requirements-bad-requirements">Good Requirements &amp; Bad Requirements</h3><p>This comes down to a fundamental idea in systems engineering: requirements should be descriptive, not prescriptive.</p><p>I&apos;ll say it again. Requirements should be descriptive, not prescriptive.</p><p>A <em>descriptive requirement</em> describes what things the system shall and shall not do. A <em>prescriptive requirement</em> prescribes how the system shall do &quot;the things.&quot;</p><p>I picked up an example at Trane. One of the mechanical engineers was drafting some requirements for firmware in our lab automation set-up. He <em>prescribed</em> a seach algorithm: &quot;iterate through the list until you&apos;ve found the key.&quot; One of the software guys explained that we have better search algorithms, but his <em>prescriptive requirement</em> would block us from using them. He refactored it into a <em>descriptive requirement,</em> &quot;the system shall locate the key in the list,&quot; and everyone was happy.</p><p>CAFE used prescriptive requirements to tell companies how efficient cars of certain sizes must be, instead of describing the objective: &quot;less efficient cars shall be less attractive to operate.&quot; Congress tried to be too clever, and wound up creating a perverse incentive.</p><h3 id="consistent-export-controls">Consistent Export Controls</h3><p>As with CAFE, Congress tried to be too clever with the 25% <em>de minimis</em> threshold. If the objective was to block sales of advanced technologies to China, that should have been the law. Instead, Congress said, &quot;any advanced technology <em>with more than 25% American components</em> cannot be exported to China.&quot;</p><p>That created a perverse incentive to swap American-made components with foreign ones, so companies could keep the American-origin share below 25%. For years, that impacted America&apos;s position in the semiconductor industry. Congress and the federal government eventually course-corrected by implementing FDPR and getting other nations like the Netherlands and Japan to agree on sanctions. The question is, why didn&apos;t we go for that from the start?</p><p>The failure here was an example of <a href="https://en.wikipedia.org/wiki/Goodhart%27s_law?ref=howdytx.technology" rel="noreferrer">Goodhart&apos;s Law:</a></p><blockquote>When a measure becomes a target, it ceases to be a good measure.</blockquote><p>The <em>de minimis</em> threshold (measure) became a target, and ceased to fulfil the purpose of blocking advanced tech from entering China. The FDPR is a better method of determining what is export-controlled and what is not, because there&apos;s no arbitrary measure companies can game. So the first Trump administration and the Biden administration actually fixed this regulatory issue by moving to more descriptive, more consistent requirements.</p><p>Again, national security and trade policy are especially complicated, and I&apos;m not claiming to know better. I just think a more coordinated strategy could have minimized side effects.</p><h2 id="conclusion">Conclusion</h2><p>The cobra policy, CAFE, the GDPR, and the EAR&apos;s <em>de minimis</em> rule all created perverse incentives. CAFE and the EAR were too prescriptive. The GDPR was too ambiguous. In contrast, ADA is generally unambiguous and consistent.</p><p>To be clear, I&apos;m not saying a &quot;product requirements mindset&quot; would fix <em>every</em> piece of legislation, or that every piece of legislation should look like the ADA. I&apos;m saying that the product requirements mindset can improve regulations which engineers have to follow.</p><p>If policy-makers drew on the principles of good requirements in their regulations, I think verifying compliance would be easier and creating perverse incentives would be harder. But so many of our politicians are lawyers by training (I think there&apos;s exactly <em>one</em> engineer in Congress), so they probably aren&apos;t used to writing &quot;good requirements.&quot; They&apos;re used to writing legal documents. I&apos;m not trying to bash the lawyers; they&apos;re just not usually exposed to systems engineering (as far as I know!)</p><p>This is one of those areas where people with a lot of different backgrounds have to collaborate. Governments aren&apos;t going to get tech policy right unless technical people can weigh in. I learned a lot from writing this post, and I&apos;m interested in reading more in this space. If you have an example of regulation done well, or more stories about perverse incentives, I&apos;d love to hear about it. If you think this idea is ridiculous, or that I&apos;ve overlooked something important, let me know! You can email me at <a href="mailto:ethanbarry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a> or reach out via LinkedIn.</p><p>Thanks for reading!</p>]]></content:encoded></item><item><title><![CDATA[Game Theory & Topology—An Unexpected Connection]]></title><description><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-regular kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="or-what-international-politics-has-to-do-with-stirring-coffee" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Or, what international politics has to do with stirring coffee.</span></h2>
                    
                    
                </div>
            </div>
        </div><p>I love coffee; don&apos;t you? Even if (somehow) you don&apos;t, I think you&apos;ll enjoy this article.</p><p>I found out about this connection from reading <em>Games &amp; Decisions</em> by Luce and Raiffa. It&apos;s</p>]]></description><link>https://howdytx.technology/game-theory-topology/</link><guid isPermaLink="false">677f2b49ebac340001acb767</guid><category><![CDATA[Math]]></category><category><![CDATA[game theory]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Thu, 09 Jan 2025 21:51:27 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-regular kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="or-what-international-politics-has-to-do-with-stirring-coffee" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Or, what international politics has to do with stirring coffee.</span></h2>
                    
                    
                </div>
            </div>
        </div><p>I love coffee; don&apos;t you? Even if (somehow) you don&apos;t, I think you&apos;ll enjoy this article.</p><p>I found out about this connection from reading <em>Games &amp; Decisions</em> by Luce and Raiffa. It&apos;s a book on game theory, the mathematical study of decision-making. We use phrases like &quot;zero-sum game&quot; and &quot;optimal strategy&quot; in everyday speech, but they come from this field, which has an enormous number of applications.</p><p>The history of game theory is fascinating, thanks to the people who had a hand in forming it. Daniel Bernoulli and his brother Nicholas analyzed an <a href="https://en.wikipedia.org/wiki/St._Petersburg_paradox?ref=howdytx.technology" rel="noreferrer">early problem</a> in the 18th century, and &#xC9;mile Borel (of <em>infinite monkey theorem</em> fame) published some (ultimately incorrect) work on it in the early 1920s. By far the most important were John von Neumann, the great mathematician and computer scientist, and Oskar Morgenstern, who worked with him at the Institute for Advanced Study, when the <em>Anschluss</em> prevented him from returning to Austria.</p><p>They coauthored a book, <em>Theory of Games and Economic Behavior,</em> which built on von Neumann&apos;s 1928 proof of the <a href="https://en.wikipedia.org/wiki/Minimax?ref=howdytx.technology#Minimax_theorem" rel="noreferrer">minimax theorem</a> for two-person zero-sum games (which Borel had discarded). It laid the foundation for work in the &apos;50s by <a href="https://en.wikipedia.org/wiki/John_Forbes_Nash_Jr.?ref=howdytx.technology" rel="noreferrer">John Nash</a>, who essentially rewrote the theory to give it more &quot;teeth&quot; when dealing with harder problems.</p><div class="kg-card kg-toggle-card" data-kg-toggle-state="close">
            <div class="kg-toggle-heading">
                <h4 class="kg-toggle-heading-text"><span style="white-space: pre-wrap;">Aside about John Nash</span></h4>
                <button class="kg-toggle-card-icon" aria-label="Expand toggle to read content">
                    <svg id="Regular" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                        <path class="cls-1" d="M23.25,7.311,12.53,18.03a.749.749,0,0,1-1.06,0L.75,7.311"/>
                    </svg>
                </button>
            </div>
            <div class="kg-toggle-content"><p><span style="white-space: pre-wrap;">If you haven&apos;t watched the movie </span><i><em class="italic" style="white-space: pre-wrap;">A Beautiful Mind,</em></i><span style="white-space: pre-wrap;"> I highly recommend it. It tells the story of his life, his work, and the challenges caused by his mental illness. Despite that, his work was so influential that he eventually received the Nobel Prize in Economics, and the Abel Prize in mathematics.</span></p></div>
        </div><p>It&apos;s John Nash&apos;s contribution that I want to share, but to share it, I have to do a bit of setup.</p><h2 id="a-simple-game">A Simple Game</h2><p>When I say &quot;game&quot; in this article, I mean this: \(n\) players, each with a set \(S_n\) of possible decisions, and a set of associated outcomes. If player 1 chooses his strategy 3, and player 2 chooses his strategy 5, then there is an outcome for that particular choice, telling what each player gains or loses. <em>Time for an example!</em></p><h3 id="battle-of-the-sexes">Battle of the Sexes</h3><p>Say a man and a woman want to see a movie. The man would rather see an action movie, and the woman would rather see a romantic comedy. However, they both prefer going to <em>any</em> movie together over going alone. We can rank the satisfaction or payoff with a numerical ordering. </p><p>The woman would <em>most like</em> to see the rom-com with the man, but she&apos;d <em>dislike</em> seeing the rom-com alone. You can assign those the scores 2 and -1. She&apos;d like watching the action movie with him, but would dislike seeing it alone, so assign those 1 and -1.</p><p>Now we can do the same for the man. You can swap their places in the ranking above&#x2014;just reverse the 2 and the 1. We can make a table, called the <em>payoff matrix.</em></p><table>
<thead>
<tr>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td><strong>Action Movie</strong></td>
<td><strong>Rom-com</strong></td>
</tr>
<tr>
<td><strong>Action Movie</strong></td>
<td>(1, 2)</td>
<td>(-1, -1)</td>
</tr>
<tr>
<td><strong>Rom-com</strong></td>
<td>(-1, -1)</td>
<td>(2, 1)</td>
</tr>
</tbody>
</table>
<p>In the table, the man&apos;s choice is on the left, and the woman&apos;s choice is on top. The ordered pairs are the payoffs \((w, v)\) to the woman and man, respectively. (Each choice, by the way, is an example of a <em>pure strategy</em> in the game.)</p><p>A game theorist wants to know what they should choose to maximize their happiness. A little critical thinking rules out either case where they aren&apos;t together. That leaves our hypothetical couple with the choices \((1, 2)\) and \((2, 1)\). Which is the &quot;best?&quot;</p><p>Of course, you already know the answer intuitively. There is no &quot;best.&quot; Someone has to compromise (accept less than a 2), or both will be miserable!</p><p>Let&apos;s consider what happens when we repeat the experiment multiple times. In real life, people take turns compromising. They go to a rom-com one night, and an action movie the next. That&apos;s a great solution! As we repeat the experiment more times, the <em>overall</em> payoff gets closer to \((\frac{3}{2}, \frac{3}{2})\), the average of 1 and 2, and they&apos;re both equally happy.</p><p>There&apos;s also no way either one can get an advantage by changing their strategy, assuming the other player makes no change. If the man suddenly goes to action movies 3 out of 4 times, instead of 1 out of 2, he&apos;ll be worse off. This is what we call an <em>equilibrium point,</em> and in a sense, it&apos;s the &quot;best solution&quot; to the game.</p><h3 id="cool-so-what">Cool; so what?</h3><p>The battle of the sexes was a very simple example, but it&apos;s not hard to see how you could model a complicated situation like a barter, labor dispute, or international political squabble in this framework&#x2014;each side has some choices that lead to some outcomes. We also saw that, even though there was no good solution for either player in terms of a single <em>pure</em> strategy, there was one in terms of <em>mixed</em> strategies.</p><blockquote><em><strong>Question:</strong> Is it always the case there is a best solution, or equilibrium point?</em></blockquote><p>The answer is yes&#x2014;this is John Nash&apos;s major contribution. It&apos;s called the <em>Nash equilibrium</em>, and the proof that it exists is actually very beautiful.</p><h2 id="coffee-the-existence-of-equilibrium-points">Coffee &amp; the Existence of Equilibrium Points</h2><p>Let&apos;s put game theory on hold for a moment, and back up to the end of the 19th century. Henri Poincar&#xE9; was trying to answer an old question&#x2014;is the Solar System stable? He considered the motion of objects flowing on a level surface, and made a discovery. However, this discovery is usually credited to (and was actually proved by) L. E. J. Brouwer. There&apos;s a nice (apocryphal) story associated with it, so I&apos;ll tell that instead. Just remember that Poincar&#xE9; published on it first.</p><p>The story goes like this: As Brouwer was stirring sugar into his coffee one morning, he noticed that one point in the coffee always seemed to be stationary. He realized this must always be the case&#x2014;what would it look like if <em>every</em> point on the surface were moving? It&apos;s not physically possible.</p><h3 id="the-theorem-we-need">The Theorem We Need</h3><p>This visual intuition is connected to an actual mathematical fact, now known as <em>Brouwer&apos;s fixed-point theorem.</em> I&apos;ll give you an even more intuitive example, after the mathematical statement.</p><blockquote><strong>Brouwer&apos;s fixed-point theorem: </strong>Every continuous function from a closed disk onto itself has at least one fixed point.</blockquote><p>Let&apos;s break this down. We have a disk (the surface of the coffee) which is closed (has a boundary), and a function mapping points on the disk, to other points on the disk. (A stirring motion moves the coffee around, but it never leaves the cup.)</p><p>Also, this function is continuous, which means all points initially in a neighborhood stay in a neighborhood after applying the function. (The coffee doesn&apos;t &quot;jump&quot; to a new location; it moves &quot;continuously.&quot;)</p><p>This actually applies to any nonempty, convex, compact subset \(U\) of Euclidean space, and continuous transformation \(T : U \rarr U\).</p><p>Now for the visual example. Imagine you&apos;re holding a map of the state or country you&apos;re standing in. You know the transformation from the map to the country is always continuous&#x2014;you just scale up. Points in a neighborhood remain neighbors. Spread the map on a table, and there will always be a &quot;You Are Here&quot; point that&apos;s the same on the map as it is in the country.</p><p>Are you convinced yet? It seemed pretty intuitive to me&#x2014;it&apos;s almost one of those things where you say &quot;I wish I&apos;d thought of that!&quot;</p><h3 id="nashs-proof">Nash&apos;s Proof</h3><p>Let&apos;s return to game theory. So far, we have a game, and Brouwer&apos;s fixed point theorem. If we can make a transformation from the set of payoffs, to the set of payoffs, in such a way that a fixed point must be an equilibrium point, we have proved the existence of an equilibrium point for all finite games. </p><p>Now I can sketch the outline of Nash&apos;s proof. I&apos;ll follow the notation and structure of Nash&apos;s doctoral thesis, found <a href="https://www.princeton.edu/mudd/news/faq/topics/Non-Cooperative_Games_Nash.pdf?ref=howdytx.technology" rel="noreferrer">here</a>. You can follow the entire thing if you&apos;ve taken a bit of calculus, yet it was revolutionary in its field! If you just want the TL;DR you can skip to the summary.</p><p>Here are the definitions we need:</p><blockquote><strong>Definition: Finite game:</strong> A finite game is \(n\) players, ea. with a finite set of pure strategies, and for ea. player \(i\), a payoff function \(p_i\) which maps all \(n\)-tuples of pure strategies into an ordered set, e.g. \(\Bbb{R}\) or \(\Bbb{Z}\).</blockquote><blockquote><strong>Definition: Mixed strategy:</strong> A mixed strategy of a player \(i\), denoted \(S_i\), is a collection of weights or probabilites (like \(\frac{1}{2}\) in &quot;Battle of the Sexes&quot;) on his pure strategies. \[S_i = \sum_\alpha c_{i\alpha} \pi_{i\alpha}\] where \(\sum_\alpha c_{i\alpha} = 1\) &amp; \(c_{i\alpha} \ge 0\) (it&apos;s a probability), and \( \pi_{i\alpha}\) is player \(i\)&apos;s \(\alpha\)-th pure strategy.</blockquote><blockquote><strong>Definition: Payoff function:</strong> We can extend the payoff function in our definition of the finite game to cover all \(n\)-tuples of mixed strategies. We&apos;ll use this definition of \(p_i\) from now on. So for any mixed strategy \(&#x1D4AE;\), we&apos;d write:<br>\[p_i(&#x1D4AE;) = p_i(S_1, S_2, \dots , S_n).\] Also note that any \(&#x1D4AE;\) is a point in \(n\)-dimensional vector space, and the set of all \(&#x1D4AE;\)s is a convex subset of that space. (Think about our payoff matrix, but for mixed strategies&#x2014;that&apos;s what this represents.)</blockquote><blockquote><strong>Definition: Equilibrium point:</strong> a point where no player can get an advantage by changing their strategy, assuming the other players make no change. Formally, a mixed strategy \(&#x1D4AE;\) is an equilibrium point if and only if for every \(i\), \[p_i(&#x1D4AE;) = \underset{\text{all}\&gt;r_i\text{&apos;s}}\max\,\big[\,p_i(&#x1D4AE;; r_i)\,\big],\] <em>given that </em>\((&#x1D4AE;; r_i)\) <em>means &quot;substitute mixed strategy </em>\(r_i\) <em>for the </em>\(i\)<em>-th player&apos;s strategy.&quot;</em></blockquote><p>Nash actually constructs a sequence of continuous transformations, which we&apos;ll look at below. First, let&apos;s specify exactly what we&apos;re proving.</p><blockquote><strong>Theorem: </strong>Every finite game has an equilibrium point.</blockquote><p>To prove this, we need some continuous functions of a mixed strategy \(&#x1D4AE;\). Remember that \(p_{i\alpha}(&#x1D4AE;)\) is player \(i\)&apos;s payoff from pure strategy \(\pi_{i\alpha}\) when the other players use their strategies in \(&#x1D4AE;\). For each \(\lambda \in \Bbb{Z}\), \[\begin{gather}q_i(&#x1D4AE;) = \underset{\alpha}\max\&gt;p_{i\alpha}(&#x1D4AE;) \\ \Phi_{i\alpha}(&#x1D4AE;, \lambda) = p_{i\alpha} - q_i(&#x1D4AE;) + \frac{1}{\lambda} \\ \Phi^+_{i\alpha}(&#x1D4AE;, \lambda) = \max \big(0, \Phi_{i\alpha}(&#x1D4AE;, \lambda)\big). \end{gather}\]</p><p>Function (2) is either \(\frac{1}{\lambda}\), or \(\frac{1}{\lambda}\) plus some negative number. That lets us show the rational function \[ C&apos;_{i\alpha} = \frac{\Phi^+_{i\alpha}(&#x1D4AE;, \lambda)}{ \sum_{\beta}\Phi^+_{i\beta}(&#x1D4AE;, \lambda) } \] is also continuous, since the denominator is never zero.</p><p>Nash then defines \( S&apos;_i(&#x1D4AE;, \lambda) = \sum_\alpha \pi_{i\alpha} C&apos;_{i\alpha}(&#x1D4AE;, \lambda) \), which are different mixed strategies for every player \(i\). We combine all those into a new point \(&#x1D4AE;&apos;\), given by \( &#x1D4AE;&apos;(&#x1D4AE;, \lambda) = (S&apos;_1, S&apos;_2, \dots , S&apos;_n) \). The transformation \(&#x1D4AE;\rarr &#x1D4AE;&apos;(&#x1D4AE;, \lambda)\) is continuous because all the operations that compose it are continuous. The space of all mixed strategies is also non-empty, convex, and compact (lacking &quot;holes&quot;). Thus, there will be a fixed point \( &#x1D4AE;^* \), by the Brouwer fixed point theorem.</p><p>We haven&apos;t yet proved that this fixed point must be an equilibrium point. Nash does that by contradiction&#x2014;assuming it <em>isn&apos;t</em> an equilibrium point&#x2014;which implies that one of its strategies \(\pi_{i\alpha}\) is non-optimal. If that were so then we can show, based on  functions (1)&#x2013;(3), that \(&#x1D4AE;^*\) is not a fixed point. (I&apos;ll leave that to Nash&apos;s thesis. See page 6.) This contradicts the fact that \(&#x1D4AE;^*\) <em>is</em> indeed a fixed point. Therefore, each strategy in \(&#x1D4AE;^*\) must be optimal against the others. No player can gain by changing to a different strategy, so by definition, \(&#x1D4AE;^*\) is an equilibrium point.</p><h3 id="proof-summary">Proof Summary</h3><p>Nash created some transformation \(T\), mapping \(n\)-tuples of mixed strategies into \(n\)-tuples of mixed strategies, where \(T\) has two properties:</p><ul><li>\(n\)-tuple \(&#x1D4AE;\) is an optimal strategy if and only if \(T(&#x1D4AE;) = &#x1D4AE;\), that is, \(&#x1D4AE;\) is a fixed point under \(T\).</li><li>\(T\) satisfies the conditions of Brouwer&apos;s fixed-point theorem, and consequently has a fixed point.</li></ul><p>If those are the case, and Nash proved they must be, then any \(n\)-player finite game does indeed have at least one Nash equilibrium. This means there is a solution to any &quot;game&quot;&#x2014;meaning an abstract model for anything from a couple at the movies to national governments&#x2014;which no player can improve by switching strategies. To prove that, we used a single theorem in topology that a mathematician allegedly discovered when stirring sugar into his coffee.</p><p>If that&apos;s not a fascinating connection, I don&apos;t know what is.</p><hr><h3 id="references">References</h3><p><a href="https://www.princeton.edu/mudd/news/faq/topics/Non-Cooperative_Games_Nash.pdf?ref=howdytx.technology" rel="noreferrer">John Nash: <em>Non-Cooperative Games.</em></a><br><a href="https://archive.org/details/gamesdecisions00rdun/mode/2up" rel="noreferrer">R. Duncan Luce &amp; Howard Raiffa: <em>Games &amp; Decisions.</em></a><br><a href="https://en.wikipedia.org/wiki/Brouwer_fixed-point_theorem?ref=howdytx.technology" rel="noreferrer">Wikipedia: &quot;Brouwer fixed-point theorem&quot;</a><br><a href="https://en.wikipedia.org/wiki/John_Forbes_Nash_Jr.?ref=howdytx.technology" rel="noreferrer">Wikipedia: &quot;John Forbes Nash, Jr.&quot;</a></p><p>As always, thanks for reading! If you have a comment, I&apos;d love to hear from you! My email is <a href="mailto:ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>. You can also reach me at my LinkedIn or GitHub, linked in the header.</p>]]></content:encoded></item><item><title><![CDATA[End of the Year Thoughts]]></title><description><![CDATA[At the end of the year, I always put some thoughts down in one of my notebooks. Writing things out helps me focus on them, and I figured it would be nice to do it on my blog this year, especially since no one reads this anyway.]]></description><link>https://howdytx.technology/year-end-thoughts/</link><guid isPermaLink="false">67689809c0a775000191fa8a</guid><category><![CDATA[Off-Topic]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Mon, 23 Dec 2024 03:51:24 GMT</pubDate><content:encoded><![CDATA[<p>This is a quick one; Christmas is <s>a week</s> a few days away, and there&apos;s plenty to do. I can&apos;t do much baking for friends or family, as I have a cold, but it should pass by tomorrow afternoon. I can feel it in my bones! (Sinuses, actually...)</p><p>At the end of the year, I always put some thoughts down in one of my notebooks. Writing things out helps me focus on them, and a bulleted list is easier to understand than an abstract thought cloud. I figured it would be nice to do it on my blog this year, especially since no one reads this anyway.</p><p>The spring was great&#x2014;it feels like it was ages ago I finished Calculus II, which was the highlight of that semester, and I&apos;m sure I&apos;ve forgotten many things already. What I <em>haven&apos;t</em> forgotten is the group of friends I made there. I ran into most of them on campus at one point or another in the fall, and it&apos;s a blast watching them dive into their majors.</p><p>That informed a decision I made at the beginning of the fall semester. I&apos;d never made social activities a priority before, and the spring was over so quickly I didn&apos;t get to know more than a few people. But for the fall, I wanted social activity to be on the same footing as my studies. Universities are about more than grades, after all, and we can learn as much from our peers as from our professors.</p><p>I&apos;m happy to report that it paid off&#x2014;I got to do a <a href="https://github.com/emilio-zuniga/Swordfish?ref=howdytx.technology" rel="noreferrer">team project</a> with an<em> amazing </em>group of fellow CS majors, and I got involved in student organizations, mainly as secretary of the Assoc. for Computing Machinery chapter. I&apos;m grateful for the opportunities, and I learned a lot about teamwork from both.</p><p>The fall was more <em>fun</em> in some ways, but it was worse in others. Despite being 16 credit-hours instead of 19 like the spring, it was a harder workload. But, because of my choice to make social activities a priority, I still spent plenty of time with friends. We went out to lunches, discussed everything from music to life goals, and generally had a grand old time.</p><p>I&apos;ll finish with a couple specific things that happened to me, and then the bulleted list of observations I mentioned. First, I found out I have three semesters of compsci courses left, not two. (One would have a single class.) So, I decided to go all-in and double major in mathematics. That also gave me a chance to participate in the Honors College; I&apos;ll get to do a two-semester research project in my major.</p><p>Second, a couple days after that, I received an offer from Trane Technologies, and will be joining them as a co-op/intern on the controls software team in January. I&apos;m incredibly excited to get a taste of the industry and solve real-world problems. It means I&apos;m not taking classes in the spring, but I&apos;ll be back in the fall with a new perspective and, I&apos;m sure, more friends!</p><h3 id="the-list-of-lessons-learned">The List of Lessons Learned</h3><p>In no particular order, the lessons I learned (or should have learned!) from this year:</p><ul><li>Classes are only exciting if teachers are excited to teach them, and a good teacher makes hard material enjoyable.</li><li>It always pays to listen to people. Time is precious, and they notice when you invest it.</li><li>It always pays to ask questions. You&apos;re guaranteed to be no <em>worse</em> off than before, and you&apos;ll have rephrased the problem to ask the question. Oftentimes, that reveals the solution.</li><li>When they tell you a physics lab is one credit-hour, it&apos;s a trap. <em>They&apos;re lying</em>.</li><li>The Probability &amp; Statistics class (MATH 3351) is evil. It looks like math, but it isn&apos;t, because <em>math</em> is fun.</li><li>Social life matters more than grades. I walked out of this semester with a 3.9 GPA, not a 4.0, and it was worth it.</li><li>It&apos;s always better to handle problems early. (I keep forgetting and relearning this one.)</li><li>Helping people learn, whether as a TA for Data Structures &amp; Algorithms, or as a friend giving calculus tips, is extremely rewarding. The &quot;Aha!&quot; moment, when someone finally gets it, is worth every minute spent.</li></ul><p>I&apos;d love to hear from anyone reading this, if there are such people. Stranger things have happened on the internet. My email is <a href="mailto:ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>.</p>]]></content:encoded></item><item><title><![CDATA[UNIX History & the `dc` Calculator]]></title><description><![CDATA[An elegant weapon for a more civilized age; or, why RPN is the coolest thing since sliced silicon.]]></description><link>https://howdytx.technology/unix-history-the-dc-calculator/</link><guid isPermaLink="false">66c8d4093aad30000112e11c</guid><category><![CDATA[Rust]]></category><category><![CDATA[Math]]></category><category><![CDATA[Compilers]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Fri, 23 Aug 2024 21:20:16 GMT</pubDate><media:content url="https://howdytx.technology/content/images/2024/08/HP-15C_Programmable_Scientific_Calculator_introduced_1982_-edited-_built_from_2_images-.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="an-elegant-weapon-for-a-more-civilized-age" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">&quot;...an elegant weapon for a more civilized age.&quot;</span></h2>
                    <img src="https://howdytx.technology/content/images/2024/08/HP-15C_Programmable_Scientific_Calculator_introduced_1982_-edited-_built_from_2_images-.jpg" alt="UNIX History &amp; the `dc` Calculator"><p id="or-why-rpn-is-the-coolest-thing-since-sliced-silicon" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Or, why RPN is the coolest thing since sliced silicon.</span></p>
                    
                </div>
            </div>
        </div><p>When you need to do a bit of math, like most people, you probably reach for your phone&apos;s built-in calculator. If you&apos;re on a computer, you might bust open the Windows calculator, or any of the Linux equivalents. Perhaps, if you&apos;re in a terminal, you do something like:</p><pre><code class="language-text">$ python
Python 3.12.4 (main, Jun  7 2024, 06:33:07) [GCC 14.1.1 20240522] on linux
Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.
&gt;&gt;&gt; 39480 * 4
157920
&gt;&gt;&gt;</code></pre><p>You may even know that there&apos;s a dedicated UNIX utility, <code>bc</code>, which can do the exact same thing, and can run interactively, or with piped input, or a script. But have you ever tried <code>dc</code>? Maybe your fingers slipped one day, and you accidentally typed <code>dc</code> instead of <code>cd</code>, as I did. In that case, like me, you were presented with a simple blank line&#x2014;not a prompt, not a copyright message, but just a blank line.</p><p>If you had that experience, you may have typed <code>man dc</code> out of curiosity (<a href="https://github.com/dbrgn/tealdeer?ref=howdytx.technology" rel="noreferrer"><code>tldr</code></a><code>dc</code> if you were in a hurry). In that case, you&apos;d see this:</p><pre><code class="language-text">dc(1)                                                                 
General Commands Manual                                                     
            dc(1)

NAME
       dc - an arbitrary precision calculator

SYNOPSIS
       dc [-V] [--version] [-h] [--help]
          [-e scriptexpression] [--expression=scriptexpression]
          [-f scriptfile] [--file=scriptfile]
          [file ...]

DESCRIPTION
       dc is a reverse-polish desk calculator which supports unlimited
precision arithmetic.  It also allows you to define and call macros.  
Normally dc reads from the  standard  input;  if any command arguments are 
given to it, they are filenames, and dc reads and executes the contents of 
the files before reading from standard input.  All normal output is to 
standard output; all error output is to standard error.

       A reverse-polish calculator stores numbers on a stack.  Entering a 
number pushes it on the stack.  Arithmetic operations pop arguments  off  
the  stack  and push the results.

       To enter a number in dc, type the digits (using upper case letters A 
through F as &quot;digits&quot; when working with input bases greater than ten), with 
an optional  decimal  point.  Exponential notation is not supported.  To 
enter a negative number, begin the number with &#x2018;&#x2018;_&apos;&apos;.  &#x2018;&#x2018;-&apos;&apos; cannot be used 
for this, as it is a binary operator for subtraction instead.  To enter two 
numbers in succession, separate them with spaces or newlines.  These have 
no meaning as commands.</code></pre><p>Well, that seems redundant. Just how many calculators does one need? My dear reader, the correct answer is &quot;all of them.&quot; But what makes this calculator special, and what is all that about &quot;reverse-polish calculators&quot; and &quot;stacks?&quot;</p><p>To answer that, we need to examine the usual way of writing math. For example, when you want to operate on a couple of numbers, you typically write the operator between them, like this: \(1 + 2 = 3\). But there are other ways. There&apos;s function notation, which might look like \(\mathrm{add}(1, 2) = 3\). You could even have a lambda calculus notation, e.g. \(\mathrm{add}\,m\,n = \lambda s.\,\lambda z.\,m\,s\,(n\,s\,z)\) where \(1 + 2 = 3\) would be written \(5 = \mathrm{add}\,2\,3 = \lambda s.\, \lambda z.\,2\,s\,(3\,s\,z)\).</p><p>You could also have prefix, or Polish notation, where addition is written \(+\,3\,4\). This is really recognizable to lisp users. Reverse Polish notation, or postfix notation, is the opposite. It has operators following operands, like so: \(3\,4\,+\). You may wonder why on earth anyone would write math that way, but there is a good technical reason. Reverse Polish notation, or RPN, removes the need for operator precedence.</p><p>If you write a na&#xEF;ve program reading symbols and doing operations for infix notation, you&apos;ll quickly wind up tripping over expressions like \(3 + 4 \times 9 + 2\). The correct answer is \(41\). A simple interpreter would evaluate from left to right, and wind up with 63. To correctly apply the order of operations with infix notation, you would need to include either a parser that builds and evaluates an expression tree, or parentheses to specify the order. In contrast, the RPN equivalent of \(4\,9\,\times\,2\,3\,+\,+\) is easy to parse. Here&apos;s why.</p><p>Parsers aren&apos;t <em>hard</em> to implement for simple infix notation, but right-associative operators like exponentiation can be more difficult. In any case, a parse tree needs to be built somehow, and the tree needs to be simplified from its leaves downwards to its root. But with postfix operators, the only data structure you need is a stack.</p><p>The process is simple. Push numbers onto the stack. When you encounter a binary operator, pop two and operate, else, pop one. Push the result back onto the stack. At the end, the answer will be the only number left.</p><h2 id="the-history">The History</h2><p>This is a very simple algorithm, and it needs only very simple tools. Perhaps this is why <code>dc</code>, the UNIX RPN calculator, was the first utility <em>ported</em> to UNIX, way back in the PDP-11 days. It even predates the C programming language; originally it was implemented in B. This program is <em>ancient</em> in computing terms&#x2014;right up there with dinosaurs, magnetic tape, and punch cards. <a href="https://en.wikipedia.org/wiki/Dc_(computer_program)?ref=howdytx.technology" rel="noreferrer">Wikipedia</a> calls it the &quot;oldest surviving UNIX program.&quot;</p><p>RPN isn&apos;t unique to <code>dc</code>. The first recognizable electronic (or electromechanical) computer, Konrad Zuse&apos;s <a href="https://en.wikipedia.org/wiki/Z3_(computer)?ref=howdytx.technology" rel="noreferrer">Z3</a>, used RPN as its input scheme in 1941. Since that time, all manner of calculators and computers, desktop, handheld, or otherwise, have used RPN as the input scheme because it is efficient and unambiguous. Hewlett-Packard&apos;s calculators notably used RPN for every field, from accounting to engineering. You may know the venerable <a href="https://en.wikipedia.org/wiki/HP-15C?ref=howdytx.technology" rel="noreferrer">HP-15C</a>, which offered everything from matrix operations to numerical integration, all with RPN on 1980s hardware.</p><p>Ah, simplicity...</p><h2 id="now">Now</h2><p>Just for fun, yesterday afternoon I implemented a little <code>dc</code>-like calculator in Rust. It doesn&apos;t have registers or support for macros yet, but it does implement addition/subtraction, multiplication/division, exponentiation, and square and cube roots. The arbitrary precision is supplied by the <a href="https://docs.rs/bigdecimal/latest/bigdecimal/?ref=howdytx.technology" rel="noreferrer"><code>bigdecimal</code></a> crate. I thought about using Malachite, but neither it nor <code>num</code> support taking roots. They want their operations to remain closed on the ring &#x211A;, and roots are a great way to get irrational numbers!</p><p>You can find the source code <a href="https://github.com/ethanbarry/dcrs?ref=howdytx.technology" rel="noreferrer">here</a>. Just clone the repo and do:</p><pre><code class="language-shell">cargo run</code></pre><p>to start the program. Then, type in your RPN expressions. You can print the entire stack with &quot;p,&quot; clear it with &quot;c,&quot; print the top item with &quot;t,&quot; and take square and cube roots with &quot;v&quot; and &quot;b,&quot; respectively.</p><p>I&apos;m especially proud of my little prompt macro, which is the first Rust macro I&apos;ve written. I never understood why something like this wasn&apos;t included in the standard library, but here you go, for what it&apos;s worth:</p><pre><code class="language-rust">/// A simple macro to grab input from the user.
#[macro_export]
macro_rules! prompt {
    ($prompt:expr) =&gt; {{
        print!(&quot;{}&quot;, $prompt);
        use std::io::Write;
        std::io::stdout()
            .flush()
            .expect(&quot;Writing to stdout failed!&quot;);
        let mut input = String::new();
        match std::io::stdin().read_line(&amp;mut input) {
            Ok(0) =&gt; std::process::exit(0), // Handle EOF
            _ =&gt; {}
        };
        input.trim().to_string()
    }};
}</code></pre><p>You use it like this, which I think is pretty handy.</p><pre><code class="language-rust">let input = prompt!(&quot;Enter a number&gt; &quot;);</code></pre><p>Thanks for reading! I&apos;d appreciate your comments. Please, connect with me on LinkedIn, or email me at <a href="mailto:ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>.</p>]]></content:encoded></item><item><title><![CDATA[Creating a LaTeX Template for UT Tyler]]></title><description><![CDATA[Why you should use the LaTeX memoir class, in 5 minutes or less!]]></description><link>https://howdytx.technology/creating-a-latex-template/</link><guid isPermaLink="false">6671f32f10bbb80001a80292</guid><category><![CDATA[Art]]></category><category><![CDATA[Typography]]></category><category><![CDATA[Research]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Thu, 20 Jun 2024 11:46:37 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-layout-split kg-width-full kg-content-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
            <picture><img class="kg-header-card-image" src="https://howdytx.technology/content/images/2024/06/Thesis_Titlepage-2.png" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Thesis_Titlepage-2.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Thesis_Titlepage-2.png 1000w, https://howdytx.technology/content/images/2024/06/Thesis_Titlepage-2.png 1499w" loading="lazy" alt></picture>
        
                <div class="kg-header-card-text ">
                    <h2 id="because-everyone-needs-more-latex-in-their-life" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Because everyone needs more LaTeX in their life.</span></h2>
                    <p id="at-least-the-easytouse-kind" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">At least, the easy-to-use kind.</span></p>
                    
                </div>
            </div>
        </div><p>Most folks in STEM fields know about \(\LaTeX\). It&apos;s the gold standard for scientific writing, desktop publishing, and math typesetting. Its algorithms still beat MS Word&apos;s, Google Docs&apos;, or even Adobe&apos;s InDesign&apos;s. (If you haven&apos;t heard of \(\LaTeX\), it&apos;s a way to make PDFs with code.)</p><p>The website <a href="https://overleaf.com/?ref=howdytx.technology" rel="noreferrer">Overleaf.com</a> is an easy-to-use experience for anyone who would rather sit down and write than fiddle with \(\LaTeX\) installation on, say, a Windows computer. Because of that, many thousands of students, academics, and professionals worldwide use it daily to typeset documents. The platform has a huge <a href="https://www.overleaf.com/latex/templates?ref=howdytx.technology" rel="noreferrer">collection</a> of templates, which can provide your document&apos;s formatting and looks.</p><h2 id="the-problem">The Problem</h2><p>Half the problem is that most of the templates are boring, and only some are exceptional. Of course, any one you choose will produce a better document than MS Word would give you.  The issue is that most users never tap into the superpowers of \(\LaTeX\). This is the fault of something called the &quot;document class.&quot; A document class defines macros (shortcuts) for the user to set text with. The document classes everyone uses (<code>article</code>, <code>book</code>, &amp;c.) are old, try to be as backwards-compatible as possible, and break easily if you try to be too cute.</p><p>Ask me how I know.</p><p>Anyway, for a new document, people should <em>ideally</em> be using the <code>memoir</code> class. It is a modern class (from 2001!) which is entirely dedicated to ergonomics. The original developer wanted users to create professional documents without knowing anything about typography. It provides a whole host of deeply integrated functionality that <code>article</code> and <code>book</code> can only dream of.</p><p><em>Side Note: The class has 400 pages of documentation, 500 pages in the user manual, and even comes with a 130 pages of typographical notes by the developer. You will not lack for help resources if you adopt <code>memoir</code>.</em></p><p>Having a general overabundance of okay-ish templates wouldn&apos;t be a problem on its own. The other half of the problem is that many universities provide \(\LaTeX\) templates, while mine does not! So, can we create a decent template using <code>memoir</code> that fixes UT Tyler&apos;s lack of an Overleaf template?</p><h2 id="the-solution">The Solution</h2><p>We have a default <code>article</code> document that looks like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/Article_Class_Screencap.png" class="kg-image" alt="A picture of a plainly-styled document. The layout and font are very boring." loading="lazy" width="1291" height="1688" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Article_Class_Screencap.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Article_Class_Screencap.png 1000w, https://howdytx.technology/content/images/2024/06/Article_Class_Screencap.png 1291w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Icky article class with lorem ipsum text.</span></figcaption></figure><p>But, we want to turn it into something pretty. If we simply change from <code>article</code> to <code>memoir</code> as our document class, very little happens. We need to do more. I&apos;ll walk through the changes I made, and a beginner-level \(\LaTeX\) user should have no problem following along in the code, available <a href="https://www.overleaf.com/latex/templates/ut-tyler-general-template/qybwhpyzrvkw?ref=howdytx.technology" rel="noreferrer">here</a>.</p><p>Here is a page from the final result:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/Thesis_Screencap.png" class="kg-image" alt="A much nicer document. The font is more lively, the margins are better sized, and the spacing is great." loading="lazy" width="1521" height="1986" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Thesis_Screencap.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Thesis_Screencap.png 1000w, https://howdytx.technology/content/images/2024/06/Thesis_Screencap.png 1521w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">My template, showcasing some math and graphics typesetting.</span></figcaption></figure><p>So, what changed? </p><h3 id="visible-changes">Visible Changes</h3><p>First, the font. There&apos;s nothing <em>wrong</em> with the default latin-modern font, but it is a bit spindly at larger sizes, and we want something classic. You&apos;ll find there is no better option than EB Garamond. If you haven&apos;t overridden my CSS, this blog is set in EB Garamond as well. You can insert <code>\usepackage{ebgaramond}</code> to set it as the main font. I&apos;ve included a package that sets it as the math font, too. Notice how nice the Schr&#xF6;dinger equation looks!</p><p>Second, the margins are different&#x2014;I used a wider right margin so I can insert margin notes&#x2014;which gives the document a more book-like feel. I want to use margin notes to introduce variables. I saw this done in an older journal, and I think it&apos;s a very handy idea. It&apos;s a shame we don&apos;t see it more often. Notice how \(x\) and \(z\) are shown below. If you were skimming the paper for some variable&apos;s definition, you could easily find it!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/Thesis_Margins.png" class="kg-image" alt="The same nice document, but a different page. This one has small italic notes in the margin." loading="lazy" width="1499" height="1964" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Thesis_Margins.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Thesis_Margins.png 1000w, https://howdytx.technology/content/images/2024/06/Thesis_Margins.png 1499w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">A showcase of what margins and pretty math fonts can do.</span></figcaption></figure><p>Boldface is used sparingly, with italics and smallcaps (<code>\scshape</code>) providing most of the emphasis. Bold faces are not a major element of classic typography, so it&apos;s nice to minimize their use. It goes a long way to making the document more readable.</p><p>Finally, my favorite part is the title page and frontmatter. I&apos;ll let the images speak for themselves.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/Thesis_Titlepage.png" class="kg-image" alt loading="lazy" width="1499" height="1961" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Thesis_Titlepage.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Thesis_Titlepage.png 1000w, https://howdytx.technology/content/images/2024/06/Thesis_Titlepage.png 1499w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">The title page, showing the university seal in all its glory...</span></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/Thesis_Copyrightpage.png" class="kg-image" alt loading="lazy" width="1499" height="1961" srcset="https://howdytx.technology/content/images/size/w600/2024/06/Thesis_Copyrightpage.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/Thesis_Copyrightpage.png 1000w, https://howdytx.technology/content/images/2024/06/Thesis_Copyrightpage.png 1499w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">The copyright page, showing nice spacings and beautiful small caps that only EB Garamond can provide.</span></figcaption></figure><p>The title page is inspired by <a href="https://www.overleaf.com/latex/templates/thesis-template/xrqcvvbkfxnb?ref=howdytx.technology" rel="noreferrer">this template</a> by Mario Vilar on Overleaf, though I didn&apos;t use any code from it in this document. I especially like his faint background. It&apos;s similar to my research paper&apos;s title page <a href="https://howdytx.technology/mosaics-paper/" rel="noreferrer">here</a>.</p><h3 id="changes-under-the-hood">Changes &quot;Under the Hood&quot;</h3><p>The code itself is fanatically organized and heavily commented. I want it to be as easy as possible to do whatever needs to be done. It has sane defaults for document divisions and page styles, with most of the options visible in the preamble.</p><p>You can explore it for yourself on <a href="https://github.com/ethanbarry/UT_Tyler_Thesis?ref=howdytx.technology" rel="noreferrer">GitHub</a> or <a href="https://www.overleaf.com/latex/templates/ut-tyler-general-template/qybwhpyzrvkw?ref=howdytx.technology" rel="noreferrer">Overleaf</a>.</p><h3 id="conclusion">Conclusion</h3><p>I am excited to see whether this gets any notice on Overleaf from my fellow students, but regardless of whether it does, I want to use it for my own papers. Hopefully none of the professors will be too draconian about formatting rules in the coming semesters.</p><p>As for extensions to the template, I&apos;m adding some macros for margin notes and variables in the margins. I realized after I took the screenshots that the margin notes should be set <code>\raggedright</code> instead of justified. I think a macro that takes the note as an argument and automatically formats it will be useful.</p><p>As always, please send me any feedback you have at <a href="mailto://ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>, or drop me a message on <a href="https://linkedin.com/in/ethanbarry?ref=howdytx.technology" rel="noreferrer">LinkedIn</a>!</p>]]></content:encoded></item><item><title><![CDATA[The Best Possible Quadrature Routine (Within Reason)]]></title><description><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="gausslobattokronrod-quadratures" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Gauss-Lobatto-Kronrod Quadratures</span></h2>
                    <p id="in-rust-of-course" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">...in Rust, of course.</span></p>
                    
                </div>
            </div>
        </div><p>Originally all I wanted to do with numerical analysis was string together some functions and plot an ephemeris, given the right data. Planetary motions are fascinating, and I think it will be a really cool project. However, after reading the first chapter of the</p>]]></description><link>https://howdytx.technology/the-best-possible-quadrature-routine-within-reason/</link><guid isPermaLink="false">665ab075fedcc2000182e4e1</guid><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Mon, 10 Jun 2024 18:15:15 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="gausslobattokronrod-quadratures" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Gauss-Lobatto-Kronrod Quadratures</span></h2>
                    <p id="in-rust-of-course" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">...in Rust, of course.</span></p>
                    
                </div>
            </div>
        </div><p>Originally all I wanted to do with numerical analysis was string together some functions and plot an ephemeris, given the right data. Planetary motions are fascinating, and I think it will be a really cool project. However, after reading the first chapter of the textbook <em>Celestial Mechanics</em>, where the author lists important numerical methods, I realized that numerical analysis by itself is something interesting.</p><p>In the last section of the first chapter he gives a list of programs or routines that are useful to him. One of those was using Gaussian quadrature to compute a definite integral. I already discussed the problem of quadrature in the post on <a href="https://howdytx.technology/simpsons-rule-more/" rel="noreferrer">Simpson&apos;s Rule</a>, and I mentioned Gaussian quadrature specifically in the post on <a href="https://howdytx.technology/lagrange-interpolation/" rel="noreferrer">Lagrange interpolation</a>. But, it&apos;s still worth revisiting the question of what quadrature means, before I share what I learned about Gaussian quadrature.</p><h2 id="computing-definite-integrals">Computing Definite Integrals</h2><p>In calculus we learn that a definite integral is actually the area beneath a curve. We approximate this with a sum of the areas of many small slices. In fact, the exact value is the number the sum approaches as the number of slices goes to infinity. This is called the Riemann sum approach, and essentially, it chops the integral up in nice rectangular bits. If we wanted to approximate an integral, one way would be to chop it up into lots of rectangles, and add their areas. If we want a closer approximation, then we just make finer slices.</p><p>This is certainly a fine method, but it would be a nightmare to compute by hand. Every slice needs its own function evaluation. Even in a computer, this can be slow. And, since we would be using rectangles to approximate a smooth function, this would still be inaccurate.</p><p>If, instead of using a flat-topped rectangle, we used a slope-topped trapezoid as our slice shape, we could make the slope line up with the function. That would mean our calculation would be more accurate, and would require fewer function evaluations. This is the trapezoid rule.</p><p>And, if we use a quadratic curve as the top of the slice, it can fit the function even more tightly still. That was Simpson&apos;s Rule, from my earlier post. In fact, there&apos;s a whole class of quadrature rules called <a href="https://en.wikipedia.org/wiki/Newton%E2%80%93Cotes_formulas?ref=howdytx.technology" rel="noreferrer">Newton-Cotes formulas</a>, which extend this idea, using higher-order polynomials to interpolate the points.</p><p>With these methods, we have one degree of freedom. We get to choose the weighting coefficients in equations like Simpson&apos;s Rule:</p><p>\[\int_a^b f(x)\,dx \approx \frac{1}{3}(f(a) + 4f(c) + f(b))\]</p><p>The big idea behind Gaussian quadrature is that it allows us to choose both the weights and the locations at which we evaluate \(f(x)\), giving us two degrees of freedom. With Newton-Cotes formulas, our accuracy increased at \(\mathcal{O}(n)\), as we added more slices. Now, we can converge to the result at \(\mathcal{O}(n^2)\), with the extra degree of freedom. </p><p>Let&apos;s examine the main idea.</p><h2 id="gaussian-quadrature">Gaussian Quadrature</h2><p>Simpson&apos;s Rule and the rest of the Newton-Cotes formulas essentially represent the integrand with polynomials. Gaussian quadrature lets us represent our integrand as a polynomial <em>times a weight function</em>. This is good, because some functions aren&apos;t nicely interpolated by polynomials. We can also evaluate at different points by applying weights to the evaluations.</p><p>This gives us the general Gaussian quadrature rule</p><p>\[\int_{-1}^1 W(x)f(x)\,dx \approx \sum_{1=0}^n w_if(x_i)\]</p><p>The polynomials we need to use are called Legendre polynomials. So, in our equation, \(n\) is the number of sample points, \(w_i\) are the weights, and \(x_i\) are the roots of the \(n\)th Legendre polynomial. The integral is given on the interval \([-1,1]\) because that is where Legendre polynomials have most of their useful properties, but we can scale up or down to any interval \([a,b]\).</p><p>We can compute the roots on the fly for any order \(n\), within reason. There is a technique called the <a href="https://en.wikipedia.org/wiki/Newton%27s_method?ref=howdytx.technology" rel="noreferrer">Newton-Raphson method</a> which finds roots of nonlinear functions. It takes a starting guess and iteratively improves it until the difference between the new value and the old one is within tolerance. It&apos;s a surprisingly simple technique.</p><p>\[x_{new} = x_{old} - \frac{f(x_{old})}{f&apos;(x_{old})}\]</p><p>Now we just need the polynomials! There&apos;s a recurrence relation for them, so starting with the first two, we can build all the Legendre polynomials after that.</p><p>\[\begin{align}p_{-1}(x) &amp;= 0\\ p_0(x) &amp;= 1\\ p_{j+1}(x) &amp;= (x-a_j)p_j(x) - b_jp_{j-1}(x),\quad j = 1,2,...,n\end{align}\]</p><p>We need a good guess to use Newton-Raphson. Usually the roots are closely approximated by \[r=\cos\left(\pi\frac{i + \frac{3}{4}}{n + \frac{1}{2}}\right)\quad i = 0,...,\frac{(n+1)}{2}\] where \(n\) is the order of the quadrature.</p><p>Once we have the weights \(w_i\), given by \[w_i = \frac{2}{(1-x_i^2)\left[p_n&apos;(x_i)\right]^2}\] where \(p_n&apos;\) is the derivative of the \(n\)th Legendre polynomial. Finally, we can mix all these numbers together in some code. But first, I want to show a result this algorithm gives.</p><p>Here&apos;s a test problem with the correct approximation to 9 decimal places: \[\int_0^1 \frac{ x^4 }{ \sqrt{ 2(1+x^2) }}\,dx \approx 0.108\,709\,465\,052\,586\,44\] The Rust code I wrote returns this value to nine decimal places with a 7-point Gauss-Legendre quadrature. That means the function only had to be evaluated seven times. I also used Simpson&apos;s Rule with seven evaluations, and it gave me an answer of 0.108 710, which is not bad.</p><p>Now, if I raise the Gaussian quadrature&apos;s order to eight, I get the answer 0.108 709 465 037, which is correct to 10 decimal places. If I raise the Simpson&apos;s Rule order to eight as well, I get 0.108 709 862, which is still only correct to six decimal places.</p><p>The code is below.</p><pre><code class="language-rust">pub fn gaussian_quad&lt;F&gt;(f: F, a: f64, b: f64, n: u32) -&gt; f64
where
    F: Fn(f64) -&gt; f64,
{
    const NEWTON_PRECISION: f64 = 1.0e-10;
    let mut res = 0.0;
    // Scale the bounds of integration a and b to [-1, 1]
    // using the change of variables
    // x = st + c for t &#x2208; [-1, 1]
    // where
    // s = (b - a) / 2
    // and
    // c = (b + a) / 2.
    let s = (b - a) / 2.0;
    let c = (b + a) / 2.0;
    let m = (n + 1) / 2;
    let mut roots = vec![0.0; n as usize];
    let mut weights = vec![0.0; n as usize];
    for i in 0..m {
        // Approximate the ith root of this Legendre polynomial.
        let mut z = f64::cos(consts::PI * (i as f64 + 0.75) / (n as f64 + 0.5));
        let mut z1 = z - 1.0; // Ensure an initial difference.
        let mut p_prime = 0.0;
        while (z - z1).abs() &gt; NEWTON_PRECISION {
            let mut p1 = 1.0;
            let mut p2 = 0.0;
            // Build the Legendre polynomial using the recurrence relation here...
            for j in 0..n {
                let p3 = p2;
                p2 = p1;
                p1 = ((2.0 * j as f64 + 1.0) * z * p2 - j as f64 * p3) / (j + 1) as f64;
            }
            // p1 is now the desired Legendre polynomial.
            // let p_prime be its derivative, computed by a known relation.
            p_prime = n as f64 * (z * p1 - p2) / (z * z - 1.0);
            z1 = z;
            z = z1 - p1 / p_prime; // Newton-Raphson method.
        }
        // z is now the ith root of the polynomial.
        roots[i as usize] = z;
        roots[(n - 1 - i) as usize] = -z;
        weights[i as usize] = 2.0 / ((1.0 - z * z) * p_prime * p_prime);
        weights[(n - 1 - i) as usize] = weights[i as usize];
    }

    for i in 0..n as usize {
        res += weights[i] * f(s * roots[i] + c);
    }
    res * s // Scale back to normal size.
}</code></pre><p>Now, if we have a function that is well-behaved, this will work nicely. But if there&apos;s an irregularity in just one or two places, we have to raise the number of points just to cover those two subintervals. Wouldn&apos;t it be nice if we could somehow adapt to a problem like that, and only do more evaluations when we need them?</p><h2 id="adaptive-quadrature">Adaptive Quadrature</h2><p>Remember that the heart of numerical integration is chopping area into smaller pieces. If there&apos;s an interval where the function goes crazy, and one where it&apos;s smooth, then let&apos;s not worry about the smooth interval too much, and focus on the crazy one. How do we measure &quot;craziness?&quot; The general method is to evaluate the integral on the interval twice&#x2014;once at low precision, then again at high precision&#x2014;which gives us a difference. If that difference is within a tolerance, then we leave it alone. If not, we split the interval and repeat the process.</p><p>You might think that this will cost us a lot of function evaluations. It <em>will</em> take more, but maybe we can minimize the number needed. And an adaptive routine is already saving us evaluations in comparison to just globally increasing evaluations to boost accuracy, like with Simpson&apos;s Rule.</p><p>With Gaussian quadrature, a low-precision rule will not have the same \(x\)-coordinates as a high-precision one. That means we can&apos;t reuse any of those function values. What we&apos;re looking for is a <em>nested quadrature</em>, which &quot;nests&quot; a higher-order quadrature inside a lower-order one. There are two options, <a href="https://en.wikipedia.org/wiki/Clenshaw%E2%80%93Curtis_quadrature?ref=howdytx.technology" rel="noreferrer">Clenshaw-Curtis</a>, and <a href="https://en.wikipedia.org/wiki/Gauss%E2%80%93Kronrod_quadrature_formula?ref=howdytx.technology" rel="noreferrer">Gauss-Kronrod</a>. Both were invented around 1960; the first by two Western (British, I think) mathematicians, and the second by a Soviet mathematician, Aleksandr Semyonovich Kronrod.</p><p>This particular algorithm, from the paper &quot;<a href="https://link.springer.com/article/10.1023/A:1022318402393?ref=howdytx.technology" rel="noreferrer">Adaptive Quadrature&#x2014;Revisited</a>&quot; by W. Gander and W. Gautschi, is an example of Gauss-Lobatto-Kronrod quadrature. Kronrod&apos;s extension of Gaussian quadrature allows us to reuse function evaluations for higher precision, and the &quot;Lobatto&quot; part means we use the endpoints as well.</p><p>A Kronrod Rule uses \(2n+1\) points, where \(n\) is the number of points for the Gaussian quadrature. This makes the Kronrod Rule exact for a polynomial up to degree \(3n+1\). The extra \(x\)-values (abscissas) are nowadays calculated with some linear algebra tricks, as described in the paper. They can also be found by solving non-linear equations with Newton&apos;s Method, but because either one would be expensive, we&apos;ll use tabulated values.</p><p>As an example of what Gaussian quadrature and the Kronrod extension are really doing, I produced a little graphic with <code>gnuplot</code>. Here is a 4-point Gauss-Lobatto quadrature of our example \(\int_0^1 \frac{ x^4 }{ \sqrt{ 2(1+x^2) }}\,dx\). The lines pass through the \(y\)-values of the Gaussian abscissas, so the abscissas lie below the intersection of the line and the curve. The Kronrod abscissas would occur somewhere between the Gaussian ones.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/06/plot.png" class="kg-image" alt="Function plot showing where the Gaussian abscissas land." loading="lazy" width="1920" height="1200" srcset="https://howdytx.technology/content/images/size/w600/2024/06/plot.png 600w, https://howdytx.technology/content/images/size/w1000/2024/06/plot.png 1000w, https://howdytx.technology/content/images/size/w1600/2024/06/plot.png 1600w, https://howdytx.technology/content/images/2024/06/plot.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Function plot showing where the Gaussian abscissas land.</span></figcaption></figure><p>The function I created has a pretty simple interface. I didn&apos;t include controls on how many iterations to allow, or what precision to calculate the integral to. It simply computes until the answer is stable to within machine precision.</p><pre><code class="language-rust">pub fn gaussian_kronrod_quad&lt;F&gt;(func: F, a: f64, b: f64) -&gt; f64
where
    F: Fn(f64) -&gt; f64,
{
/* SNIP; CODE BELOW */
}</code></pre><p>This has given very good results on the integrals I&apos;ve tested. For example, on our problem from earlier, \[\int_0^1 \frac{ x^4 }{ \sqrt{ 2(1+x^2) }}\,dx \approx 0.108\,709\,465\,052\,586\,44\] I get the answer to the ~17 digits allowed by a double precision float <code>f64</code>.</p><p>The basic steps are:</p><ol><li>Evaluate a 4-point Gauss-Lobatto quadrature on the scaled interval.</li><li>Evaluate a 7-point Kronrod extension using the 4-point values.</li><li>Evaluate a general estimate for the entire integral with a 13-point Kronrod extension using stored values from the previous two.</li><li>If the 4- and 7-point values differ by more than machine precision, split the interval into six parts, and perform the same 4- &amp; 7-point procedure on those. Add their results.</li></ol><p>This is a very good quadrature method, comparable to Julia&apos;s QuadGK.jl package, or some tools from other dedicated systems, like GNU OCTAVE and MATLAB. In fact, in the paper linked above, the authors show that it was actually an improvement over the quadatures available at the time in MATLAB, and the NAG and IMSL libraries.</p><h2 id="conclusion">Conclusion</h2><p>The speed and type safety of Rust make it a very attractive option for scientific computing, but so far, it hasn&apos;t made much headway against more established languages like FORTRAN, Python, and Julia. The numerical analysis and linear algebra packages in Rust are improving, but they&apos;re often less-complete than counterparts elsewhere.</p><p>I think the killer application of Rust in this space might be concurrency. Rust makes parallelization much more achievable. Rust&apos;s SIMD wrappers are nicer than most languages&apos; equivalents as well, so parallelizing and vectorizing sci-comp workloads is a unique benefit Rust can offer. I&apos;m excited to see what happens in this space.</p><hr><pre><code class="language-rust">/// An adaptive 4-point Gauss-Lobatto quadrature routine.
/// Kronrod&apos;s Rule is used to reduce the computations needed,
/// while using 7- &amp; 13-point Kronrod quadratures for error checking.
///
/// ## Inputs
/// - f: The integrand (must be integrable on \[a,b\])
/// - a: The lower bound of integration.
/// - b: The upper bound of integration.
///
/// NOTE: The algorithm assumes a &lt; b.
/// ## Outputs
/// An `f64` value containing the definite integral calculated to machine precision.
/// ## Examples
/// ```rust
/// use symmetria::quadrature::gaussian_kronrod_quad;
/// use std::f64::consts;
/// let f = |x: f64| x.cos();
/// let val = gaussian_kronrod_quad(f, 0.0, (consts::PI / 2.0));
/// assert!((1.0 - val).abs() &lt; 1.0e-17);
/// ```
pub fn gaussian_kronrod_quad&lt;F&gt;(func: F, a: f64, b: f64) -&gt; f64
where
    F: Fn(f64) -&gt; f64,
{
    // This algorithm was adopted from the paper
    // &quot;Adaptive Quadrature --- Revisited&quot; by Walter Gander and Walter Gautschi.
    // published in BIT Numerical Mathematics, vol. 40, No. 1, pp. 84-101.

    // Scale the bounds of integration a and b to [-1, 1].
    // This converts
    // \int_a^b f(x)dx to \int_{-1}^1 f(sx + c)sdx
    // using the change of variables
    // x = scale * t + coscale for t &#x2208; [-1, 1]
    // where
    // scale = (b - a) / 2
    // and
    // coscale = (b + a) / 2.
    let scale = (b - a) / 2.0;
    let coscale = (b + a) / 2.0;
    // Now, f must always be evaluated at scale * x + coscale, not simply x, and the answer multiplied by scale.

    let gl4_weights = [1.0 / 6.0, 5.0 / 6.0];
    let gl4_fnevals = [
        func(scale * -1.0 + coscale),
        func(scale * 1.0 + coscale),
        func(scale * -1.0 / 5.0_f64.sqrt() + coscale),
        func(scale * 1.0 / 5.0_f64.sqrt() + coscale),
    ];
    // Next, use the 4-point Gauss-Lobatto quadrature given by
    // \int_{-1}^1 f(x)dx &#x2248; \frac{1}{6}[f(-1) + f(1)]
    //                      + \frac{5}{6}[f(-\frac{1}{\sqrt{5}}) + f(\frac{1}{\sqrt{5}})]
    let gl4 = gl4_weights[0] * ((gl4_fnevals[0] + gl4_fnevals[1]) * scale)
        + gl4_weights[1] * ((gl4_fnevals[2] + gl4_fnevals[3]) * scale);

    let kron7_fnevals = [
        func(scale * -((2. / 3.0_f64).sqrt()) + coscale),
        func(scale * (2. / 3.0_f64).sqrt() + coscale),
        func(coscale), // scale * 0.0 is 0.
    ];
    // Then we compare this to its 7-point Kronrod extension, given by
    // \int_{-1}^1 f(x)dx &#x2248; \frac{11}{210}[f(-1) + f(1)]
    //                      + \frac{72}{245}[f(-\sqrt{\frac{2}{3}}) + f(\sqrt{\frac{2}{3}})]
    //                      + \frac{125}{294}[f(-\frac{1}{\sqrt{5}}) + f(\frac{1}{\sqrt{5}})]
    //                      + \frac{16}{35}[f(0)]
    let kron7 = (11. / 210.) * ((gl4_fnevals[0] + gl4_fnevals[1]) * scale)
        + (72. / 245.) * ((kron7_fnevals[0] + kron7_fnevals[1]) * scale)
        + (125. / 294.) * ((gl4_fnevals[2] + gl4_fnevals[3]) * scale)
        + (16. / 35.) * (kron7_fnevals[2] * scale);

    // Finally, we compare all of them to the 13-point Kronrod extension, given by
    // \int_{-1}^1 f(x)dx &#x2248; A * [f(-1) + f(1)]
    //                      + B * [f(-x_1) + f(x_1)]
    //                      + C * [f(-\sqrt{\frac{2}{3}}) + f(\sqrt{\frac{2}{3}})]
    //                      + D * [f(-x_2) + f(x_2)]
    //                      + E * [f(-\frac{1}{\sqrt{5}}) + f(\frac{1}{\sqrt{5}})]
    //                      + F * [f(-x_3) + f(x_3)]
    //                      + G * [f(0)]
    // where
    // A = .015827191973480183087169986733305510591,
    // B = .094273840218850045531282505077108171960,
    // C = .15507198733658539625363597980210298680,
    // D = .18882157396018245442000533937297167125,
    // E = .19977340522685852679206802206648840246,
    // F = .22492646533333952701601768799639508076,
    // G = .24261107190140773379964095790325635233,
    // and
    // x_1 = .94288241569547971905635175843185720232,
    // x_2 = .64185334234578130578123554132903188354,
    // x_3 = .23638319966214988028222377349205292599.
    let a_weight = 0.015_827_191_973_480_183;
    let b_weight = 0.094_273_840_218_850_05;
    let c = 0.155_071_987_336_585_4;
    let d = 0.188_821_573_960_182_45;
    let e = 0.199_773_405_226_858_52;
    let f = 0.224_926_465_333_339_51;
    let g = 0.242_611_071_901_407_74;

    let x_1 = 0.942_882_415_695_479_7;
    let x_2 = 0.641_853_342_345_781_3;
    let x_3 = 0.236_383_199_662_149_88;

    let kron13 = a_weight * (gl4_fnevals[0] + gl4_fnevals[1]) * scale
        + b_weight * (func(scale * -x_1 + coscale) + func(scale * x_1 + coscale)) * scale
        + c * (kron7_fnevals[0] + kron7_fnevals[1]) * scale
        + d * (func(scale * -x_2 + coscale) + func(scale * x_2 + coscale)) * scale
        + e * (gl4_fnevals[2] + gl4_fnevals[3]) * scale
        + f * (func(scale * -x_3 + coscale) + func(scale * x_3 + coscale)) * scale
        + g * kron7_fnevals[2] * scale;

    let x = vec![a, b];
    let y = batch_eval(&amp;func, &amp;x);

    gkquad_recursive(&amp;func, a, b, y[0], y[1], kron13)
}

/// A helper function for gaussian_kronrod_quad().
fn gkquad_recursive&lt;F&gt;(f: &amp;F, a: f64, b: f64, fa: f64, fb: f64, iest: f64) -&gt; f64
where
    F: Fn(f64) -&gt; f64,
{
    let h = (b - a) / 2.0;
    let m = (a + b) / 2.0;
    let alpha = f64::sqrt(2.0 / 3.0);
    let beta = 1.0 / f64::sqrt(5.0);

    // Our new evaluation points...
    let mll = m - alpha * h;
    let ml = m - beta * h;
    let mr = m + beta * h;
    let mrr = m + alpha * h;
    let x = vec![mll, ml, m, mr, mrr];
    let y = batch_eval(&amp;f, &amp;x);

    let fmll = y[0];
    let fml = y[1];
    let fm = y[2];
    let fmr = y[3];
    let fmrr = y[4];

    let i2 = (h / 6.0) * (fa + fb + 5.0 * (fml + fmr));
    let i1 =
        (h / 1470.) * (77. * (fa + fb) + 432. * (fmll + fmrr) + 625. * (fml + fmr) + 672. * fm);

    if iest + (i1 - i2) == iest || mll &lt;= a || b &lt;= mrr {
        if m &lt;= a || b &lt;= m {
            // At this point, we have exhausted the machine&apos;s precision.
            // We should handle this somehow...
        }
        i1
    } else {
        // Sum of the integrals on the ranges [a, mll], [mll, ml], [ml, m], [m, mr], [mr, mrr], [mrr, b];
        gkquad_recursive(f, a, mll, fa, fmll, iest)
            + gkquad_recursive(f, mll, ml, fmll, fml, iest)
            + gkquad_recursive(f, ml, m, fml, fm, iest)
            + gkquad_recursive(f, m, mr, fm, fmr, iest)
            + gkquad_recursive(f, mr, mrr, fmr, fmrr, iest)
            + gkquad_recursive(f, mrr, b, fmrr, fb, iest)
    }
}</code></pre><p>NOTE: The function doesn&apos;t initially check whether it ought to evaluate recursively or not, but a simple <code>if-else</code> statement should catch that.</p>]]></content:encoded></item><item><title><![CDATA[Building a Compiler in Rust – Part 1]]></title><description><![CDATA[Translating 70s-style code into bytes with Rust. This guide walks through constructing a compiler for PL/0.]]></description><link>https://howdytx.technology/build-a-compiler-p1/</link><guid isPermaLink="false">66463339fedcc2000182e3a1</guid><category><![CDATA[Rust]]></category><category><![CDATA[Programming]]></category><category><![CDATA[Compilers]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Fri, 17 May 2024 03:13:30 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="building-a-lexer-amp-choosing-a-language" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Building a lexer &amp; choosing a language.</span></h2>
                    <p id="not-too-complicated-right" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Not too complicated, right?</span></p>
                    
                </div>
            </div>
        </div><p>At the end of the day, our computers really only understand ones and zeros, the state of logical gates in a piece of finely-engraved silicon, and the layout of charges in chips of memory. Programs, data, noise &#x2013; they all look the same. Yet, we&apos;re able to write instructions in a text-based programming language, that are somehow turned into the bits the computer speaks natively. How does that happen? With a compiled language, like Pascal, C, or Rust, the compiler does the job of turning the language into processor instructions, which are then assembled into bits and stored in special executable formats. Today, I want to explore the deep and beautiful ways in which a programming language can be translated into machine instructions by building a compiler.</p><h2 id="what-are-we-compiling">What are we compiling?</h2><p>This is a good question to start with. There are many languages out there &#x2013; the major, general-purpose programming languages everyone thinks of, and then less common ones, like <code>gnuplot</code> instructions, or <code>sudo</code> configuration, or other Domain-Specific Languages (DSLs). We could write a program to interpret or compile any Turing-complete language ever invented, but most of them are complicated. Instead, we&apos;ll choose a simple, classic language that was invented specifically for learning compiler techniques with, <a href="https://en.wikipedia.org/wiki/PL/0?ref=howdytx.technology" rel="noreferrer">PL/0</a>. </p><p>PL/0 is an instructional language created by Niklaus Wirth, the same guy who invented Pascal, and contributed so much in the earlier days of computer science. He provided a basic compiler for it in his book <em>Algorithms + Data Structures = Programs</em>, which is a great read if you can find it. He wrote his in Pascal, which is difficult to understand if (like me) you aren&apos;t used to Pascal and its lack of abstractions around string processing. I like <a href="https://briancallahan.net/blog/20210814.html?ref=howdytx.technology" rel="noreferrer">Dr. Brian Callahan&apos;s guide</a> much better &#x2013; it&apos;s written in C, and makes much more sense. I&apos;ll be following his guide for most of this series, and I highly recommend checking it out as well, especially when I glaze over details.</p><p>PL/0 is a simple language. Unless we extend it, it has one data type, <code>VAR</code>, which is an integer. Here is a simple program, stolen from Wikipedia.</p><pre><code class="language-objectpascal">VAR x, squ;

{Square x and load to squ}
PROCEDURE square;
BEGIN
   squ := x * x
END;

BEGIN
   x := 1;
   {Square numbers from 1 to 10}
   WHILE x &lt; 11 DO
   BEGIN
      CALL square;
      x := x + 1
   END
END.</code></pre><p>There are not very many nice features here. I haven&apos;t even included I/O operations, but we&apos;ll deal with that later. </p><p>Our first job is to get this string of text into a string of important tokens. We can leave out whitespace and comments (the bits inside the <code>{}</code>). Now, how do we go about turning a string of text from a file into a string of tokens? We need a lexing program.</p><h2 id="building-a-lexer">Building a Lexer</h2><h3 id="the-mainrs-file">The <code>main.rs</code> file:</h3><p>The first subtask is to make a program that can read a file. Since I want to make a nice, professional-looking program, I&apos;ll use the <a href="https://docs.rs/clap/latest/clap/?ref=howdytx.technology" rel="noreferrer">Clap</a> CLI builder. This will let me run my program like so:</p><pre><code class="language-shell">pl0rs -f path/to/source_code.pl0 -o path/to/target</code></pre><p>Right now, we only need the <code>-f</code> part, for the file we&apos;re reading.</p><pre><code class="language-rust">use std::path::PathBuf;
use std::process::exit;

use clap::{Parser, Subcommand};

use pl0rs::{self, lexer::lex, read_file, COMPILER_VERSION};

// Borrowed from Clap&apos;s boilerplate tutorial...
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
    /// Path to the input file
    #[arg(short, long, value_name = &quot;FILE&quot;)]
    file: Option&lt;PathBuf&gt;,

    /// Turn debugging information on
    #[arg(short, long, action = clap::ArgAction::Count)]
    debug: u8,
}

fn main() {
    let cli = Cli::parse();
    let mut file = String::new();
    let mut state = pl0rs::State::default();

    // Print compiler version, &amp;c.
    println!(&quot;pl0rs -- PL/0 Compiler version {}&quot;, COMPILER_VERSION);
    println!(&quot;(c) Ethan Barry, 2024. GPLv3 licensed.&quot;);

    // Open the file and pass it into the file string.
    // Program can terminate here with an error code.
    if let Some(file_path) = &amp;cli.file {
        if let Ok(file_string) = read_file(file_path) {
            file = file_string;
        } else {
            eprintln!(&quot;Error: No such file found.&quot;);
            exit(1);
        }
    }

    match cli.debug {
        0 =&gt; {
            println!(&quot;Debug mode is off.&quot;);
        }
        1 =&gt; {
            println!(&quot;Debug mode is on.&quot;);
            state.debug = true;
        }
        _ =&gt; {
            println!(&quot;Don&apos;t be crazy. Defaulting to debug mode on.&quot;);
            state.debug = true;
        }
    }

    // Call the other modules.
    match lex(&amp;mut state, &amp;file) {
        Ok(res) =&gt; {
            println!(&quot;Lexer succeeded.&quot;);
        }
        Err(e) =&gt; {
            {
                eprintln!(&quot;{e}&quot;);
                exit(1);
            } // A returned lexer error.
        }
    }
}</code></pre><p>That&apos;s a minimum working example. I also want to talk about project organization for a second. We know that this will be a complex program. It will need to be tested. Unit tests, declared in <code>mod test</code> and annotated with <code>#[test]</code> are not enough to validate an entire compiler. We also need integration tests. An integration test acts like an external application calling your program. It should be able to test all the functionality, by essentially acting as another <code>fn main()</code> in the codebase.</p><p>That&apos;s why you should organize the project like this:</p><pre><code class="language-text">&#x250C; src
&#x251C;&#x2500; main.rs
&#x251C;&#x2500; lib.rs
&#x251C;&#x2500; lexer.rs
&#x2570; tests
Cargo.toml
...</code></pre><p>Your <code>main.rs</code> contains the glue logic that calls the real code in <code>lib.rs</code>. This way, your integration tests, in <code>tests</code>, can also call your library and test it against whatever test battery you create. It&apos;s a more advanced way of organizing the project.</p><h3 id="the-librs-file">The <code>lib.rs</code> file:</h3><p>Now for the library where our compiler&apos;s functionality will live. We need to handle some housekeeping first. Let&apos;s declare a <code>const VERSION</code> so we can print it out when we want. All the real compilers display version numbers! Let&apos;s also declare our first module, the lexer.</p><pre><code class="language-rust">//! File lib.rs
use std::{fs::File, io::Read, path::Path, process::exit};

pub mod lexer;

pub const COMPILER_VERSION: &amp;str = &quot;0.1.0&quot;;

pub struct State {
    pub debug: bool,
    pub line: u32,
}

impl Default for State {
    fn default() -&gt; Self {
        Self {
            debug: false,
            line: 1,
        }
    }
}</code></pre><p>I also created a <code>struct</code> called <code>State</code>. It will store whether we&apos;re in debug mode, and what line we&apos;re on. It&apos;s a good idea to <code>impl Default</code> whenever we create a <code>struct</code> we want to use. I think this trait can also be derived, but this way was more fun.</p><p>Next, here&apos;s a function to read in a file and return it as a string.</p><pre><code class="language-rust">//! File lib.rs
/// Can cause program termination with an error code.
pub fn read_file(filename: &amp;Path) -&gt; Result&lt;String, String&gt; {
    let path = Path::new(filename);

    // TODO: Eliminate unwrap.
    if !path.extension().unwrap_or_default().eq(&quot;pl0&quot;) {
        eprintln!(&quot;Error: File must have a .pl0 extension.&quot;);
        exit(1);
    }

    let mut file = match File::open(path) {
        Ok(file) =&gt; file,
        Err(e) =&gt; return Err(format!(&quot;Couldn&apos;t open file: {e}&quot;)),
    };

    let mut contents = String::new();
    match file.read_to_string(&amp;mut contents) {
        Ok(_) =&gt; Ok(contents),
        Err(e) =&gt; Err(format!(&quot;Couldn&apos;t read file: {e}&quot;)),
    }
}</code></pre><p>I&apos;m enforcing that the file has a <code>.pl0</code> extension, but that isn&apos;t really necessary, just fun. Once we&apos;ve read in the file, we need to represent different tokens somehow. Dr. Callahan used <code>#define</code>s in his C program, but I think an <code>enum</code> will work nicely for Rust. The different types of tokens are these:</p><pre><code class="language-rust">//! File lib.rs
#[derive(Debug, Clone)]
pub enum Token {
    Ident(String),
    Number(i64),
    Const,
    Var,
    Procedure,
    Call,
    Begin,
    End,
    If,
    Then,
    While,
    Do,
    Odd,
    Dot,
    Equal,
    Comma,
    Semicolon,
    Assign,
    Hash,
    LessThan,
    GreaterThan,
    Plus,
    Minus,
    Multiply,
    Divide,
    LParen,
    RParen,
}

impl PartialEq for Token {
    fn eq(&amp;self, other: &amp;Self) -&gt; bool {
        std::mem::discriminant(self) == std::mem::discriminant(other)
    }
}

impl std::fmt::Display for Token {
    // Needs a better format method.
    fn fmt(&amp;self, f: &amp;mut std::fmt::Formatter&lt;&apos;_&gt;) -&gt; std::fmt::Result {
        write!(f, &quot;{:?}&quot;, self)
    }
}</code></pre><p>Each keyword, operator, and symbol has its own unique <code>enum</code> variant. Identifiers and numbers also get one. Here&apos;s where you choose your integer size; I chose <code>i64</code>, which means that I&apos;ll always try to parse a number in PL/0 source code into a 64-bit signed integer.</p><p><em>Brief funny story: I&apos;ve done </em><code>impl Display</code><em> here by using a debug formatter. This is so I don&apos;t have to type </em><code>{:?}</code> <em>every time I want to print a Token. Originally, I had used </em><code>{}</code><em>, which I assumed would just work. However, I kept getting stack overflow errors. I didn&apos;t realize it right away, but by calling </em><code>write!(f, &quot;{}&quot;, self)</code> <em> I was recursively calling </em><code>fmt()</code> <em> and overflowing the stack. Just thought that was entertaining...</em></p><h3 id="the-lexerrs-file">The <code>lexer.rs</code> file:</h3><p>We have all the boilerplate. Now, we need to lex everything into the right sort of token. This will mean going through the file, character by character, and deciding what to do on the fly. An iterator would be nice!</p><p>Our lexer&apos;s primary function will take a string containing our PL/0 code, and a <code>State</code> that we can modify. It should return a <code>Vec&lt;Token&gt;</code>, but that might fail, so we&apos;ll return a <code>Result&lt;Vec&lt;Token&gt;, String&gt;</code> instead.</p><pre><code class="language-rust">//! File lexer.rs

pub fn lex(state: &amp;mut State, file: &amp;str) -&gt; Result&lt;Vec&lt;Token&gt;, String&gt; {
    let mut chars = file.chars().peekable();
    let mut comment = String::new();
    let mut tokens: Vec&lt;Token&gt; = vec![];

    // TODO!

    Ok(tokens)
}</code></pre><p>First, let&apos;s process comments. In PL/0, comments are closed with braces, like this:</p><pre><code class="language-pascal">{this is a comment}</code></pre><p>When we see an opening brace, we&apos;ll skip through all the characters until we find the closing brace that matches it. If there is none, it&apos;s an error. We&apos;ll add this after the <code>TODO!</code> comment.</p><pre><code class="language-rust">&apos;lexer: loop {
    if let Some(c) = chars.peek() {
        if (*c).eq(&amp;&apos;{&apos;) {
            chars.next(); // Consume the opening brace
            &apos;comment: for c in chars.by_ref() {
                if c == &apos;}&apos; {
                    break &apos;comment;
                }
                if c.eq(&amp;&apos;\n&apos;) {
                    state.line += 1;
                }
                comment.push(c);
            }
        }
    } else {
        break &apos;lexer; // No more characters.
    }
}</code></pre><p>There! We simply push all the characters in a comment to the comment string, in case we need them. Also be sure to increment the line count; we&apos;ll need that later.</p><p>The next trick is to discard whitespace between tokens. We can add some code to handle that in the same way we handle comments. After we&apos;ve handled whitespace and comments, everything remaining is syntactically significant. A nested set of <code>if-else</code> statements will handle that. The entire <code>lex()</code> function is below.</p><pre><code class="language-rust">//! File lexer.rs
pub fn lex(state: &amp;mut State, file: &amp;str) -&gt; Result&lt;Vec&lt;Token&gt;, String&gt; {
    let mut chars = file.chars().peekable();
    let mut comment = String::new();
    let mut tokens: Vec&lt;Token&gt; = vec![];

    &apos;lexer: loop {
        if let Some(c) = chars.peek() {
            if (*c).eq(&amp;&apos;{&apos;) {
                chars.next(); // Consume the opening brace
                &apos;comment: for c in chars.by_ref() {
                    if c == &apos;}&apos; {
                        break &apos;comment;
                    }
                    comment.push(c);
                }
            } else if (*c).is_whitespace() {
                if c.eq(&amp;&apos;\n&apos;) {
                    state.line += 1;
                }
                chars.next(); // Consume the whitespace.
            } else if (*c).is_alphabetic() || (*c).eq(&amp;&apos;_&apos;) {
                let token = identifier(&amp;mut chars, state)?;
                tokens.push(token);
            } else if (*c).is_numeric() {
                let token = number(&amp;mut chars, state)?;
                tokens.push(token);
            } else if (*c).eq(&amp;&apos;:&apos;) {
                let token = assignment(&amp;mut chars, state)?;
                tokens.push(token);
            } else {
                let token = match *c {
                    &apos;.&apos; =&gt; Token::Dot,
                    &apos;=&apos; =&gt; Token::Equal,
                    &apos;,&apos; =&gt; Token::Comma,
                    &apos;;&apos; =&gt; Token::Semicolon,
                    &apos;#&apos; =&gt; Token::Hash,
                    &apos;&lt;&apos; =&gt; Token::LessThan,
                    &apos;&gt;&apos; =&gt; Token::GreaterThan,
                    &apos;+&apos; =&gt; Token::Plus,
                    &apos;-&apos; =&gt; Token::Minus,
                    &apos;*&apos; =&gt; Token::Multiply,
                    &apos;/&apos; =&gt; Token::Divide,
                    &apos;(&apos; =&gt; Token::LParen,
                    &apos;)&apos; =&gt; Token::RParen,
                    _ =&gt; {
                        return Err(format!(&quot;Unknown token on line {}&quot;, state.line));
                    }
                };
                tokens.push(token);
                chars.next();
            }
        } else {
            break &apos;lexer; // No more characters
        }
    }

    Ok(tokens)
}</code></pre><p>A diagram might make the code easier to understand. I&apos;ll draw it as a state machine!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/05/Lexer_State_Machine.png" class="kg-image" alt loading="lazy" width="2000" height="1545" srcset="https://howdytx.technology/content/images/size/w600/2024/05/Lexer_State_Machine.png 600w, https://howdytx.technology/content/images/size/w1000/2024/05/Lexer_State_Machine.png 1000w, https://howdytx.technology/content/images/size/w1600/2024/05/Lexer_State_Machine.png 1600w, https://howdytx.technology/content/images/2024/05/Lexer_State_Machine.png 2200w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">State machine diagram of the lexer. ( Made by the author in Inkscape. )</span></figcaption></figure><p>Any of the last four boxes on the right add a token to the <code>Vec&lt;Tokens&gt;</code> that we&apos;re storing the tokenized code in. Also note the <code>assignment()</code> block. It is called when the lexer finds a colon. In the PL/0 grammar, the assignment operator is <code>:=</code>, and the only place a colon can occur is in the assignment operator. So, if we find a colon without an equals sign, it&apos;s an error. Let&apos;s write that method now.</p><pre><code class="language-rust">//! File lexer.rs
pub fn assignment(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    chars.next(); // Consume the &apos;:&apos; character.

    if let Some(c) = chars.peek() {
        if (*c).eq(&amp;&apos;=&apos;) {
            chars.next();
            Ok(Token::Assign)
        } else {
            Err(format!(&quot;Unknown token &apos;:&apos; on line {}&quot;, state.line))
        }
    } else {
        Err(format!(&quot;Unterminated assignment on line {}&quot;, state.line))
    }
}</code></pre><p>This function is pretty straightforward. The <code>if let</code> syntax is a clean way to deal with the iterator. This method advances the iterator right away, because it is only ever called on a <code>&apos;:&apos;</code>. (If it were called somewhere besides a colon, this would be a logic error. You can make a note of that and move on.)</p><h3 id="words-and-numbers">Words and Numbers</h3><p>Now there are just two functions left to implement, <code>number()</code> and <code>identifier()</code>. These both need to take one character at a time, until they encounter whitespace, or something that isn&apos;t legally a number or identifier. Dr. Callahan suggested extending PL/0 to allow breaking up large integers with underscores, like we can do in modern languages. We&apos;ll add that as well.</p><p>Also notice that the function <code>lex()</code> calls <code>identifier()</code> whenever it sees an alphabetic character or underscore. This includes keywords and variable names. It will have to distinguish them, and return the correct Token <code>enum</code> variant.</p><pre><code class="language-rust">//! File lexer.rs
pub fn identifier(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    let mut idt = String::new();

    loop {
        // Push characters onto idt one by one.
        if let Some(c) = chars.peek() {
            if (*c).is_alphanumeric() || (*c).eq(&amp;&apos;_&apos;) {
                idt.push(*c);
                chars.next();
            } else {
                break;
            }
        } else {
            // Was a None.
            return Err(format!(&quot;Unterminated identifier on line {}&quot;, state.line));
        }
    }

    let token = match idt.to_lowercase().as_str() {
        &quot;const&quot; =&gt; Token::Const,
        &quot;var&quot; =&gt; Token::Var,
        &quot;procedure&quot; =&gt; Token::Procedure,
        &quot;call&quot; =&gt; Token::Call,
        &quot;begin&quot; =&gt; Token::Begin,
        &quot;end&quot; =&gt; Token::End,
        &quot;if&quot; =&gt; Token::If,
        &quot;then&quot; =&gt; Token::Then,
        &quot;while&quot; =&gt; Token::While,
        &quot;do&quot; =&gt; Token::Do,
        &quot;odd&quot; =&gt; Token::Odd,
        _ =&gt; Token::Ident(idt),
    };

    Ok(token)
}

pub fn number(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    let mut num = String::new();
    loop {
        if let Some(c) = chars.peek() {
            if (*c).is_numeric() || (*c).eq(&amp;&apos;_&apos;) {
                num.push(*c);
                chars.next();
            } else {
                break;
            }
        } else {
            // Was a None.
            return Err(format!(&quot;Unterminated number on line {}&quot;, state.line));
        }
    }

    if let Ok(res) = num.parse::&lt;i64&gt;() {
        Ok(Token::Number(res))
    } else {
        Err(format!(&quot;Invalid number at line {}&quot;, state.line))
    }
}</code></pre><p>Notice that <code>identifier()</code> allows variables with underscores or numbers after an initial letter or underscore, so <code>x_0</code> and <code>_1000</code> are legal variable names. <code>number()</code> parses the complete number string into an <code>i64</code>, as we decided earlier.</p><p>At the risk of making the article too long for anyone to read, I put the complete <code>lexer.rs</code> file below, as written up to this point.</p><pre><code class="language-rust">//! File lexer.rs (complete)
use std::{iter::Peekable, str::Chars};

use crate::{State, Token};

/// ## Preconditions
///
/// - Must only be called for characters which can begin an identifier.
pub fn identifier(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    let mut idt = String::new();

    loop {
        // Push characters onto idt one by one.
        if let Some(c) = chars.peek() {
            if (*c).is_alphanumeric() || (*c).eq(&amp;&apos;_&apos;) {
                idt.push(*c);
                chars.next();
            } else {
                break;
            }
        } else {
            // Was a None.
            return Err(format!(&quot;Unterminated identifier on line {}&quot;, state.line));
        }
    }

    let token = match idt.to_lowercase().as_str() {
        &quot;const&quot; =&gt; Token::Const,
        &quot;var&quot; =&gt; Token::Var,
        &quot;procedure&quot; =&gt; Token::Procedure,
        &quot;call&quot; =&gt; Token::Call,
        &quot;begin&quot; =&gt; Token::Begin,
        &quot;end&quot; =&gt; Token::End,
        &quot;if&quot; =&gt; Token::If,
        &quot;then&quot; =&gt; Token::Then,
        &quot;while&quot; =&gt; Token::While,
        &quot;do&quot; =&gt; Token::Do,
        &quot;odd&quot; =&gt; Token::Odd,
        _ =&gt; Token::Ident(idt),
    };

    Ok(token)
}

pub fn number(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    let mut num = String::new();
    loop {
        if let Some(c) = chars.peek() {
            if (*c).is_numeric() || (*c).eq(&amp;&apos;_&apos;) {
                num.push(*c);
                chars.next();
            } else {
                break;
            }
        } else {
            // Was a None.
            return Err(format!(&quot;Unterminated number on line {}&quot;, state.line));
        }
    }

    if let Ok(res) = num.parse::&lt;i64&gt;() {
        Ok(Token::Number(res))
    } else {
        Err(format!(&quot;Invalid number at line {}&quot;, state.line))
    }
}

pub fn assignment(chars: &amp;mut Peekable&lt;Chars&lt;&apos;_&gt;&gt;, state: &amp;mut State) -&gt; Result&lt;Token, String&gt; {
    chars.next(); // Consume the &apos;:&apos; character.

    if let Some(c) = chars.peek() {
        if (*c).eq(&amp;&apos;=&apos;) {
            chars.next();
            Ok(Token::Assign)
        } else {
            Err(format!(&quot;Unknown token &apos;:&apos; on line {}&quot;, state.line))
        }
    } else {
        Err(format!(&quot;Unterminated assignment on line {}&quot;, state.line))
    }
}

pub fn lex(state: &amp;mut State, file: &amp;str) -&gt; Result&lt;Vec&lt;Token&gt;, String&gt; {
    let mut chars = file.chars().peekable();
    let mut comment = String::new();
    let mut tokens: Vec&lt;Token&gt; = vec![];

    &apos;lexer: loop {
        if let Some(c) = chars.peek() {
            if (*c).eq(&amp;&apos;{&apos;) {
                chars.next(); // Consume the opening brace
                &apos;comment: for c in chars.by_ref() {
                    if c == &apos;}&apos; {
                        break &apos;comment;
                    }
                    if c.eq(&amp;&apos;\n&apos;) {
                        state.line += 1;
                    }
                    comment.push(c);
                }
            } else if (*c).is_whitespace() {
                if c.eq(&amp;&apos;\n&apos;) {
                    state.line += 1;
                }
                chars.next(); // Consume the whitespace.
            } else if (*c).is_alphabetic() || (*c).eq(&amp;&apos;_&apos;) {
                let token = identifier(&amp;mut chars, state)?;
                tokens.push(token);
            } else if (*c).is_numeric() {
                let token = number(&amp;mut chars, state)?;
                tokens.push(token);
            } else if (*c).eq(&amp;&apos;:&apos;) {
                let token = assignment(&amp;mut chars, state)?;
                tokens.push(token);
            } else {
                let token = match *c {
                    &apos;.&apos; =&gt; Token::Dot,
                    &apos;=&apos; =&gt; Token::Equal,
                    &apos;,&apos; =&gt; Token::Comma,
                    &apos;;&apos; =&gt; Token::Semicolon,
                    &apos;#&apos; =&gt; Token::Hash,
                    &apos;&lt;&apos; =&gt; Token::LessThan,
                    &apos;&gt;&apos; =&gt; Token::GreaterThan,
                    &apos;+&apos; =&gt; Token::Plus,
                    &apos;-&apos; =&gt; Token::Minus,
                    &apos;*&apos; =&gt; Token::Multiply,
                    &apos;/&apos; =&gt; Token::Divide,
                    &apos;(&apos; =&gt; Token::LParen,
                    &apos;)&apos; =&gt; Token::RParen,
                    _ =&gt; {
                        return Err(format!(&quot;Unknown token on line {}&quot;, state.line));
                    }
                };
                tokens.push(token);
                chars.next();
            }
        } else {
            break &apos;lexer; // No more characters
        }
    }

    Ok(tokens)
}</code></pre><p>We have a fully functional lexer for our compiler, that tokenizes and understands PL/0! Congratulations! Our next steps come in the next post in this series, where we&apos;ll parse the <code>Vec&lt;Token&gt;</code> that our lexer spits out. </p><p>As always, thank you for reading! If you have suggestions or comments, please write me at <a href="mailto:ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>. Have a great day!</p>]]></content:encoded></item><item><title><![CDATA[Lagrange Interpolation]]></title><description><![CDATA[Avoiding math by doing different math.]]></description><link>https://howdytx.technology/lagrange-interpolation/</link><guid isPermaLink="false">660efd74fedcc2000182e2c0</guid><category><![CDATA[Math]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Numerics]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Sat, 16 Mar 2024 16:50:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="or-how-to-avoid-doing-math" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Or, how to avoid doing math...</span></h2>
                    <p id="by-doing-different-math" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">...by doing different math!</span></p>
                    
                </div>
            </div>
        </div><p>Interpolation is a very common problem. You need to interpolate any time you have:</p><ul><li>A table of values, in larger increments than you&apos;d like,</li><li>A set of points on some unknown function,</li><li>Known values some time apart, and you&apos;d like to know what&apos;s in between.</li></ul><p>Actually, these are all the same problem. Let&apos;s explore some solutions!</p><h2 id="bad-interpolation">Bad Interpolation</h2><p>There are a lot of techniques for interpolation. 90% of them are guaranteed to be bad, but I think it&apos;s a good idea to show why.</p><p>In real life, when I&apos;m trying to interpolate something (maybe on the occasions I mess around with a cookbook) I try to &quot;eyeball&quot; it. For the amount of salt in a fractionally-scaled recipe, that&apos;s okay. (There is no such thing as too much salt. Fight me.) But for practical applications, we need to do better.</p><p>Back in The Old Days&#x2122;, people had to consult log tables and/or slide rules for values of functions. This still happens today in astronomy, where orbital values come in tables called ephemerides, or almanacs, like <a href="https://aa.usno.navy.mil/publications/index?ref=howdytx.technology" rel="noreferrer">these</a> published by the United States Naval Observatory. If you want something between the given values, you need to interpolate.</p><h3 id="linear-interpolation">Linear Interpolation</h3><p>The simplest (formal) method is to fit the two points nearest your x-value to a line. If we know \(sin(x)\) at two points, say \(x = 0\) &amp; \(x = 2\), then we might interpolate it like this:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/04/sine_interpolation.png" class="kg-image" alt="Plot of sin(x) and a linear interpolation from 0 to 2." loading="lazy" width="640" height="480" srcset="https://howdytx.technology/content/images/size/w600/2024/04/sine_interpolation.png 600w, https://howdytx.technology/content/images/2024/04/sine_interpolation.png 640w"><figcaption><span style="white-space: pre-wrap;">Plot of sin(x) and a linear interpolation from 0 to 2.</span></figcaption></figure><p>...which is objectively terrible. It could be better if we had a smaller increment than 0 to 2, but linear interpolation is inaccurate unless the thing it&apos;s interpolating is fairly linear itself. The upside is that it&apos;s easy to compute.</p><h3 id="smoother-interpolation-with-cosine">Smooth(er) Interpolation With Cosine</h3><p>We can get a smoother curve by using weights on the interpolation function. We need something that produces a curve anywhere we like, so let&apos;s choose cosine. Now, given two points, we&apos;ll say: \[y_i \approx y_1 (1-\frac{1}{2}(1-cos(\pi \frac{x - x_1}{x_1-x_2})) + y_2 (\frac{1}{2}(1-cos(\pi \frac{x - x_1}{x_1-x_2}))\]</p><p>That&apos;s a mess. The \(\frac{x - x_1}{x_1-x_2}\) terms are our weight. When \(x\) is equal to \(x_1\), the term is zero, and all the weight is on \(y_2\). Conversely when \(x\) equals \(x_2\), the weight is one, and it&apos;s all on \(y_1\). Here&apos;s our visual example with the cosine interpolation added.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/04/cosine_interpolation.png" class="kg-image" alt="Plot of sin(x), our linear interpolation, and a cosine-smoothed interpolation, all from 0 to 2." loading="lazy" width="1280" height="960" srcset="https://howdytx.technology/content/images/size/w600/2024/04/cosine_interpolation.png 600w, https://howdytx.technology/content/images/size/w1000/2024/04/cosine_interpolation.png 1000w, https://howdytx.technology/content/images/2024/04/cosine_interpolation.png 1280w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Plot of sin(x), our linear interpolation, and a cosine-smoothed interpolation, all from 0 to 2.</span></figcaption></figure><p>Notice that all this has done is smooth our linear function. It&apos;s still not precise. It would make a nice curve between multiple points, but let&apos;s try for something better.</p><h2 id="lagrange-polynomials-and-lagrangian-interpolation">Lagrange Polynomials and Lagrangian Interpolation</h2><p>Let&apos;s be more ambitious. Say we have a set of \(n\) points (you decide how many) and we want to fit a polynomial to them. There will be many polynomials of degree \(&gt; n\) that go through them, but only one of degree \(&lt; n\). Usually, this polynomial&apos;s degree is \(n-1\). If the points happen to lie on a lower-degree polynomial, then the degree \(n-1\) polynomial&apos;s leading coefficients are zero.</p><p>Given our set of points \[(x_1, y_1), (x_2, y_2), ..., (x_i, y_i), ..., (x_n, y_n)\] the polynomial we want is this: \[y = \sum_{i=1}^n y_iL_i(x)\] where \(L_i(x)\) is the \(i\)th Lagrange polynomial, given by: \[L_i(x) = \prod_{j=1,j\ne i}^n\frac{x-x_j}{x_i-x_j}\]</p><p>In other words, the first Lagrange polynomial is: \[L_1(x) = \frac{(x-x_2)(x-x_3)...(x-x_n)}{(x_1-x_2)(x_1-x_3)...(x_1-x_n)}\]</p><p>We have a polynomial that goes through all the points, and it is also the polynomial of least degree that does so. (That&apos;s important for maximum accuracy.) The linked textbook walks through this topic in more detail, but I&apos;ll jump straight to my code.</p><p>To get a computer to do this for us, we&apos;ll first need to pull in our table of values, which is a vector of points in Computer-Science-ese, and evaluate the \(i\)th Lagrange polynomial at the \(x\)-value we want to interpolate, for all \(i\) in \([0,n]\). This just amounts to a couple of for-loops.</p><p>I used a janky iterator to exclude \(i\) in the internal loop. (Recall the provision \(j\ne i\) in our Lagrange polynomial definition.) I&apos;m sure there&apos;s a better way to do this, but that&apos;s all I could come up with at the time...</p><pre><code class="language-rust">fn lagrangian_interpolation(table: Table, xval: f64) -&gt; f64 {
    let n = table.len();
    let mut sum = 0.0;

    for i in 0..n {
        if let Some(Point(x_i, y_i)) = table.pt_at(i) {
            // Evaluate the ith Lagrange poly&apos;n. at xval and add it to sum.
            let mut product = 1.0;

            // Iterator grabs all but i.
            for j in (0..n)
                .enumerate()
                .filter(|&amp;(pos, _)| (pos != i))
                .map(|(_, e)| e)
            {
                let x_j = table.pt_at(j).unwrap().0;
                product *= (xval - x_j) / (x_i - x_j);
            } // product is now the value of L_i(xval).

            sum += y_i * product;
        } else {
            break;
        }
    }

    sum
}
</code></pre>
<p>I set up my main function to print out a tab-separated list of points, and redirected this to a file. Then, I used gnuplot to plot these points in yellow, so we have a comparison of all our methods.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://howdytx.technology/content/images/2024/04/lagrangian_interpolation.png" class="kg-image" alt="Same graph, but with our Lagrange interpolated values shown as yellow dots." loading="lazy" width="1280" height="960" srcset="https://howdytx.technology/content/images/size/w600/2024/04/lagrangian_interpolation.png 600w, https://howdytx.technology/content/images/size/w1000/2024/04/lagrangian_interpolation.png 1000w, https://howdytx.technology/content/images/2024/04/lagrangian_interpolation.png 1280w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Same graph, but with our Lagrange interpolated values shown as yellow dots.</span></figcaption></figure><p>Notice that the yellow tracks the actual function in blue very well, until about 1.5 radians. I ran this test with a table of four values, and began interpolating points with roughly \(x = \frac{\pi}{6}\), in increments of \(0.01\), for 1000 iterations. It&apos;s extrapolating past my last tabulated value of \((1.5707963, 1.0)\), or \((\frac{\pi}{2}, 1)\), and doing an acceptable job for a little while.</p><p>The reader is welcome to try fixing the table so the interpolation is more accurate over the interval. All the Rust and gnuplot source code are in my repo <a href="https://github.com/ethanbarry/lagrangian_interpolation?ref=howdytx.technology" rel="noreferrer">here</a>.</p><p>This technique is fairly fast, efficient, and is useful in Gaussian quadrature, as well as other modern applications. I hope you find it interesting, if not useful. Either way, let me know what you thought on GitHub, LinkedIn, or by email to <a href="mailto:ethan.barry@howdytx.technology" rel="noreferrer">ethan.barry@howdytx.technology</a>!</p><hr><h3 id="references">References</h3><p>Paul Bourke&apos;s classic 1999 post. His blog is pure gold; do yourself a favor and bookmark it.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://paulbourke.net/miscellaneous/interpolation/?ref=howdytx.technology"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Interpolation methods</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://paulbourke.net/favicon.ico" alt></div></div><div class="kg-bookmark-thumbnail"><img src="https://paulbourke.net/miscellaneous/interpolation/linear.gif" alt></div></a></figure><p>Numerical Methods Guy, 2008:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://blog.autarkaw.com/2008/06/14/higher-order-interpolation-is-a-bad-idea/?ref=howdytx.technology"><div class="kg-bookmark-content"><div class="kg-bookmark-title">High order interpolation is a bad idea? &#x2013; Numerical Methods Guy</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://autarkaw.com/favicon.ico" alt><span class="kg-bookmark-author">Numerical Methods Guy Numerical Methods for the STEM Undergraduate</span><span class="kg-bookmark-publisher">autarkaw</span></div></div><div class="kg-bookmark-thumbnail"><img src="http://nm.mathforcollege.com/blog/runge1.jpg" alt></div></a></figure><p>This textbook on Celestial Mechanics, where I first learned about the Lagrange interpolation algorithm:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://phys.libretexts.org/Bookshelves/Astronomy__Cosmology/Celestial_Mechanics_(Tatum)/01%3A_Numerical_Methods/1.11%3A_Fitting_a_Polynomial_to_a_Set_of_Points_-_Lagrange_Polynomials_and_Lagrange_Interpolation?ref=howdytx.technology"><div class="kg-bookmark-content"><div class="kg-bookmark-title">1.11: Fitting a Polynomial to a Set of Points - Lagrange Polynomials and Lagrange Interpolation</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://a.mtstatic.com/@public/production/site_4539/1474932284-apple-touch-icon.png" alt><span class="kg-bookmark-author">Libretexts</span><span class="kg-bookmark-publisher">Libretexts</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://a.mtstatic.com/@public/production/site_4539/1641605670-social-share.png" alt></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Simpson's Rule & More]]></title><description><![CDATA[Many problems in calculus textbooks are contrived. So how do we solve ones from the "real world?"]]></description><link>https://howdytx.technology/simpsons-rule-more/</link><guid isPermaLink="false">660ef78afedcc2000182e299</guid><category><![CDATA[Math]]></category><category><![CDATA[Rust]]></category><category><![CDATA[Numerics]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Sat, 24 Feb 2024 21:18:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide " style="background-color: #dd6144;" data-background-color="#dd6144">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="integral-algorithms-for-the-21st-century" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Integral Algorithms for the 21st Century</span></h2>
                    <p id="arent-they-mostly-derivative-work" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Aren&apos;t they mostly derivative work?</span></p>
                    
                </div>
            </div>
        </div><p>Many problems in calculus textbooks are contrived. In fact, most of them are. In reality, the sorts of integrals people like engineers and applied mathematicians see are not (practically) solvable analytically. You can&apos;t use the tricks from Calculus II to antidifferentiate the integrand, because it&apos;s simply too complicated. So what do we do?</p><h2 id="the-quest-for-quadrature">The Quest for Quadrature</h2><p>When integrals can&apos;t be antidifferentiated, or when it&apos;s too time-consuming to do so, the area under the curve can be approximated by a computer. These numerical, rather than analytical, methods are called &quot;quadrature.&quot; (There is an algorithm to either symbolically integrate a function, or else show it cannot be expressed in elementary functions, but this is far beyond this post&apos;s scope!)</p><p>Perhaps the simplest quadrature algorithm is to draw a line between the function&apos;s value at the endpoints and calculate the area under it, using simple geometry. This would be both A) &quot;interpolation to a linear function,&quot; and B) very inaccurate. But, as always, we can make smaller slices.</p><h3 id="trapezoidal-quadrature">Trapezoidal Quadrature</h3><p>Suppose we take the interval \([a,b]\) and slice it into many smaller pieces, drawing a line between the function values at each. This would give us a series of trapezoids under the curve. It seems like this would nicely approximate the curve, but it turns out that the trapezoidal method is nearly always worse than the technique we originally learned early in calculus for estimating area with sums of rectangles!</p><h3 id="simpsons-rule">Simpson&apos;s Rule</h3><p>So, if we have a gently curved integrand which is too complicated to find an antiderivative for, like this, \(\int_a^b f(x),dx\), and we want to integrate it, then let&apos;s try interpolating it to something we can calculate. We&apos;ll evaluate the function three times, once at \(a\), then at \(b\), and finally at the midpoint.</p><p>This curve can be seen as three points on a piece-wise quadratic. Instead of interpolating to a linear function, we&apos;ve interpolated to a quadratic, using one extra function evaluation. And the area under this quadratic is approximately: \[\frac{1}{3}(f(a)+4f(c)+f(b))\] where \(c\) is the midpoint of \(a\) and \(b\). Then, to gain accuracy, we can split the interval into \(n\) small sections, and interpolate for each one of those, so that:</p><p>\[\int_a^b f(x),dx \approx \sum_{1\leq i\leq n} \frac{x_{i+1} - x_i }{6} (f(x_i) + 4f(\frac{x_i + x_{i+1}}{2}) + f(x_{i+1})) \]</p><p>All we need is a function that takes a number of intervals to evaluate (the precision) and the bounds. Since I want to pass in any mathematical operation, I&apos;ll also take a closure, which is a way of passing a function as an argument to another function. (Yes, functions are data types too!) Here&apos;s my Rust implementation:</p><pre><code class="language-rust">fn int_simpson&lt;F&gt;(a: f64, b: f64, n: i32, integrand: F) -&gt; f64
where
    F: Fn(f64) -&gt; f64,
{
    // We want to sum from a to b, in n subintervals, where the width delta_x is (a - b) / n.
    // Each subinterval is [a, a+delta_x] up to b.
    let delta_x = (b - a) / n as f64;
    let mut result = 0.0_f64;
    for i in 1..=n {
        result += delta_x
            * (integrand(a + (i as f64 - 1_f64) * delta_x)
                + 4_f64 * integrand(a - delta_x / 2_f64 + i as f64 * delta_x)
                + integrand(a + i as f64 * delta_x))
            / 6_f64;
    }
    result
}
</code></pre>
<p>The complete program can be found <a href="https://github.com/ethanbarry/simpson-rule?ref=howdytx.technology" rel="noreferrer">here</a>, along with an example of using it, and even asserting that the floating-point result is accurate to a certain precision!</p><h3 id="other-methods">Other Methods</h3><p>I think it&apos;s interesting that we can see the rectangle rule, trapezoid rule, and Simpson&apos;s rule all have something in common. They&apos;re interpolating to polynomials (zeroeth, first, and second degrees, respectively) and estimating. There are certainly better methods available, especially adaptive quadratures, for functions with large high-order derivatives, but this is a quick-and-dirty result that achieves enough accuracy for most use cases. I hope you enjoyed!</p><p>Footnote: I&apos;ve added LaTeX formatting to this post using the excellent KaTeX JS package. Simply add it to your site header, and it will typeset any LaTeX markup it sees. Instructions are <a href="https://www.naut.ca/blog/2019/04/01/quickly-add-latex-math-rendering-to-a-ghost-blog/?ref=howdytx.technology" rel="noreferrer">here</a>.</p>]]></content:encoded></item><item><title><![CDATA[It Ain't Your Grandpappy's Java...]]></title><description><![CDATA[Modern Java is... nice? When did that happen?]]></description><link>https://howdytx.technology/it-aint-your-grandpappys-java/</link><guid isPermaLink="false">660ef450fedcc2000182e265</guid><category><![CDATA[Java]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Sat, 10 Feb 2024 10:27:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide kg-style-accent" data-background-color="accent">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="recent-java-releases-bring-a-lot-of-qol-improvements" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Recent Java releases bring a lot of QoL improvements.</span></h2>
                    <p id="here-are-a-few-of-the-biggest" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Here are a few of the biggest...</span></p>
                    
                </div>
            </div>
        </div><p>Java is the de facto instructional language of many universities. It&apos;s widespread, it runs on most platforms, it makes a good case study in OOP concepts, and there are a lot of teachers available.</p><p>But in many cases, the Java that&apos;s taught in the classroom isn&apos;t much like production Java. We learn the oldest syntax, and the oldest design patterns, that accomplish the task. It makes typing Java feel like drudgery compared to a more modern language like Rust or Go. Seriously, who wants to type this mess:</p><pre><code class="language-java">MySpecialClassName myClass = new MySpecialClassName();
</code></pre>
<p>to instantiate a variable?</p><h3 id="the-var-keyword">The <code>var</code> Keyword</h3><p>In more modern languages, we have type inference. The compiler can tell what a type a variable holds based on what&apos;s assigned to it. But wait, Java actually has this too! Instead we can write this:</p><pre><code class="language-java">var myClass = new MySpecialClassName();
</code></pre>
<p>which is much more streamlined. <code>var</code> is a special &quot;reserved type name&quot; that was added in Java 10, to make declarations easier to write. So why don&apos;t we learn this in university? Personally, the Java courses I&apos;ve taken have been Java 7 compatible, or older. Java 7 was released in 2011. A lot has changed since then.</p><h3 id="the-optional-type">The <code>Optional</code> Type</h3><p>In Rust, there&apos;s a special enum included in the compiler&apos;s prelude, called Option. It has two variants, Some() and None. The convention is to use it when a function may or may not return something, such as a query to a database.</p><p>Java added a similar concept with the Optional&lt;?&gt; in Java 8 (released in 2014). It&apos;s a box that might hold a value, or a null pointer. The biggest advantage is that by making this return type explicit, developers have to handle the possibility of a null pointer when it might be returned from a method. Null-checking is simplified. This:</p><pre><code class="language-java">Apple apple = mightBeNull(&quot;granny smith&quot;);

if (apple != null) {
    System.out.println(apple.toString());
} else {
    System.out.println(&quot;apple was null&quot;);
}
</code></pre>
<p>becomes this (if we use our fancy new type inference):</p><pre><code class="language-java">Optional&lt;Apple&gt; optApple = mightBeNull(&quot;granny smith&quot;);

var appleVariety = optApple.orElse(&quot;No apple in this box...&quot;);

System.out.println(appleVariety); // This is safe now!
</code></pre>
<h3 id="record-classes">Record Classes</h3><p>A common pattern in Java is using an object to hold related data, usually as it&apos;s being moved from a source to a consumer. If you had a database of apples, you might represent each apple as a class, like this:</p><pre><code class="language-java">public class Apple {
    private String variety;
    private float pricePerPound;
    
    public String getVariety() {
        return this.variety;
    }
    
    public float getPrice() {
        return this.pricePerPound;
    }
    
    public Apple(String v, float p) {
        this.variety = v;
        this.pricePerPound = p;
    }
    
    @Override
    public String toString() {
        return &quot;Apple(variety=&quot; + this.getVariety() + &quot;, price=&quot; + this.getPrice();
    }
}
</code></pre>
<p>That&apos;s a lot of code for one apple! Java 14 added a solution in the form of the record class. With modern Java, our Apple is just:</p><pre><code class="language-java">public record AppleRecord(String variety, float pricePerPound) {}
</code></pre>
<p>That&apos;s literally it.</p><p>It implements getters automatically; just call <code>AppleRecord.variety()</code> to get the variety, for example. By default, the fields are immutable, so a record is instantiated like this:</p><pre><code class="language-java">var apple = new AppleRecord(&quot;pink lady&quot;, 0.20);
</code></pre>
<p>If you need custom logic, you can override these default methods in the record&apos;s block. Easy!</p><h3 id="conclusion">Conclusion</h3><p>So why aren&apos;t we being taught these concepts? Is it the result of a one-size-fits-all approach to CS education? Are the instructors even familiar with these later developments in the Java ecosystem? I don&apos;t know.</p><p>What I do know is that being able to think in terms of Optionals, and reduce boilerplate code, will make Java feel like a whole new language for me!</p>]]></content:encoded></item><item><title><![CDATA[Dyck Words & Catalan Numbers]]></title><description><![CDATA[How can we generate all the Dyck words? And more importantly, how can we do it in Rust?]]></description><link>https://howdytx.technology/dyck-words/</link><guid isPermaLink="false">660ef263fedcc2000182e23e</guid><category><![CDATA[Rust]]></category><category><![CDATA[Combinatorics]]></category><category><![CDATA[Math]]></category><category><![CDATA[Programming]]></category><dc:creator><![CDATA[Ethan Barry]]></dc:creator><pubDate>Wed, 07 Feb 2024 21:02:00 GMT</pubDate><content:encoded><![CDATA[<div class="kg-card kg-header-card kg-v2 kg-width-wide " style="background-color: #dd6144;" data-background-color="#dd6144">
            
            <div class="kg-header-card-content">
                
                <div class="kg-header-card-text kg-align-center">
                    <h2 id="computer-science-math" class="kg-header-card-heading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">Computer Science + Math</span></h2>
                    <p id="-awesome" class="kg-header-card-subheading" style="color: #FFFFFF;" data-text-color="#FFFFFF"><span style="white-space: pre-wrap;">= Awesome</span></p>
                    
                </div>
            </div>
        </div><p>I recently watched a Numberphile video on the Catalan series, which happens to count lot of different things, from partitions of sets, to divisions of polygons, to unique binary trees of a certain order. The video is fascinating and well worth a watch.</p><p>One other thing the Catalan numbers count is the number of possible Dyck words of a given semi-length. A Dyck word is a word in a binary (having two elements) alphabet, where no prefix of the word has more of the second element than the first. That&apos;s the complicated definition. The simple definition is a balanced set of parentheses, like so: &quot;()()(())&quot; or &quot;((()))()&quot;. This should jump out as interesting to any developer - we use parentheses all day!</p><p>So, the Catalan numbers count the Dyck words of a given semi-length. For example, there are 42 Dyck words of semi-length 5, since the fifth Catalan number is 42. But how can we generate them all? And more importantly, how can we do it..... in Rust?</p><p>It turns out that defining the Catalan numbers and Dyck words in terms of recursion is easy. But with recursion, there&apos;s a limit to how far our program can go. Eventually, the call stack won&apos;t be able to hold all our recursive function calls, and our program will terminate with a stack overflow. Even if we use the heap with more advanced features, we will slowly eat into memory and run up against the computer&apos;s physical limits. (In my case, this is 24 GiB of DDR3 in a mobile workstation from 2013.)</p><p>We need a better algorithm than the recursive solution. We need a perfect algorithm.</p><p>...and there is one! It is entirely possible to convert recursive definitions and functions into iterative ones, and someone (Dr. Knuth, it seems) has already done so for this particular problem. After a bit of digging, I was able to find <a href="https://doi.org/10.48550/arXiv.1602.06426?ref=howdytx.technology" rel="noreferrer">a paper</a> on the subject. [EDIT: I was missing this link for a while after I had to rebuild this site, but it&apos;s been fixed. My apologies to the author!]</p><p>The algorithm goes as close as possible to the metal by representing opening parentheses as a 1 bit, and closing parentheses as a 0 bit. In the abstract you can see the algorithm in C-like pseudo-code. It&apos;s simply bitwise integer math. Fast, efficient, loop-less, and branch-less. The only trick is that it requires the &quot;previous&quot; Dyck word to act upon.</p><p>You can generate the &quot;next&quot; Dyck word in the sequence by flipping pairs around. Taking the Dyck word of the form &quot;()()()()()()&quot; or &quot;101010101010&quot; to be the least, and the word of form &quot;(((((())))))&quot; or &quot;111111000000&quot; to be the greatest, we can run this algorithm on its output until we reach the greatest Dyck word of the given semi-length. The integer passed in to the algorithm must represent a valid Dyck word, or it&apos;s a precondition violation.</p><p>The full source of my program is here, but I&apos;ll reproduce the Rust port of the algorithm below.</p><pre><code class="language-rust">fn next_dyck_word_bin(w: u64) -&gt; u128 {
    // Calculate a, potentially using two&apos;s complement for negation.
    let a = w &amp; (!w + 1);

    // Calculate b directly.
    let b = w + a;

    // Calculate c using bitwise XOR.
    let c = w ^ b;

    // Shift c right by 2, ensuring unsigned division.
    let c = (c as u128 / a as u128) &gt;&gt; 2; // Cast to u128 for division.

    // Add 1 to c, handling potential overflow.
    let c = c.wrapping_add(1);

    // Apply mask and bitwise OR with b.
    let mask = 0xaaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa_aaaa; // I think this is long enough...

    // Return the resulting Dyck word as a u128.
    ((c * c - 1) &amp; mask) | b as u128
}
</code></pre>
<p>I&apos;ve run the program for semi-length 20, whose Catalan number is 6,564,120,420. As you can see, the series grows quickly. It ran for 6.5 hours before I terminated it; the output file had reached ~200 GiB and over 4 billion of the 6.5 billion Dyck words, represented as ones and zeroes. But in that time, my memory usage never wavered, and my CPU stayed locked at 100%. It was very interesting to watch in reality what O(1) means - it&apos;s an invincible algorithm.</p><p>A couple improvements to the rest of the program have been suggested to me; I&apos;ll implement them soon. Next, I want to work on some numerical integration techniques, like Simpson&apos;s method. This was an exciting peek into the world of combinatorics and theoretical computer science. I&apos;m excited to see more!</p>]]></content:encoded></item></channel></rss>