<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Computist Journal: 🧠 The Science of Computation]]></title><description><![CDATA[Introductory posts about algorithms, data structures, concepts, paradigms, and other CS stuff, always for a general audience.]]></description><link>https://blog.apiad.net/s/computation</link><image><url>https://substackcdn.com/image/fetch/$s_!qNGT!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F582c72c0-c120-4ea8-ae6b-376a025250bb_1024x1024.png</url><title>The Computist Journal: 🧠 The Science of Computation</title><link>https://blog.apiad.net/s/computation</link></image><generator>Substack</generator><lastBuildDate>Sun, 19 Apr 2026 11:50:50 GMT</lastBuildDate><atom:link href="https://blog.apiad.net/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Alejandro Piad Morffis]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[apiad@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[apiad@substack.com]]></itunes:email><itunes:name><![CDATA[Alejandro Piad Morffis]]></itunes:name></itunes:owner><itunes:author><![CDATA[Alejandro Piad Morffis]]></itunes:author><googleplay:owner><![CDATA[apiad@substack.com]]></googleplay:owner><googleplay:email><![CDATA[apiad@substack.com]]></googleplay:email><googleplay:author><![CDATA[Alejandro Piad Morffis]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Basics of Search]]></title><description><![CDATA[From Chapter 1 of The Algorithm Codex]]></description><link>https://blog.apiad.net/p/the-basics-of-search</link><guid isPermaLink="false">https://blog.apiad.net/p/the-basics-of-search</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Tue, 27 Jan 2026 15:32:20 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p><em>This article is a draft of Chapter 1 of <strong>The Algorithm Codex</strong>. You can read the entire Part I (chapters 1 through 6) <a href="https://matcom.github.io/codex">online</a> for free (forever). If you want to support this initiative, feel free to <a href="https://store.apiad.net/l/codex">grab the official PDF</a>.</em></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080" width="4096" height="2730" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2730,&quot;width&quot;:4096,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;woman walking on sand dunes during daytime&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="woman walking on sand dunes during daytime" title="woman walking on sand dunes during daytime" srcset="https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1505244783088-5a36f166e5b5?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw2fHxzZWFyY2hpbmd8ZW58MHx8fHwxNzY4OTMxMTA1fDA&amp;ixlib=rb-4.1.0&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@katekerdi">Katerina Kerdi</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Searching is arguably the most important problem in Computer Science. In a very simplistic way, searching is at the core of critical applications like databases, and is the cornerstone of how the internet works.</p><p>However, beyond this simple, superficial view of searching as an end in itself, you can also view search as means for general-purpose problem solving. When you are, for example, playing chess, what your brain is doing is, in a very fundamental way, <em>searching</em> for the optimal move&#8211;the only that most likely leads to winning.</p><p>In this sense, you can view almost all of Computer Science problems as search problems. In fact, a large part of this book will be devoted to search, in one way or another.</p><p>In this first chapter, we will look at the most explicit form of search: where we are explicitly given a set or collection of items, and asked to find one specific item.</p><p>We will start with the simplest, and most expensive kind of search, and progress towards increasingly more refined algorithms that exploit characteristics of the input items to minimize the time required to find the desired item, or determine if it&#8217;s not there at all.</p><h2><strong>Linear Search</strong></h2><p>Let&#8217;s start by analyzing the simplest algorithm that does something non-trivial: linear search. Most of these algorithms work on the simplest data structure that we will see, the sequence.</p><p>A sequence (<code>Sequence</code> class) is an abstract data type that represents a collection of items with no inherent structure, other than each element has an index.</p><pre><code><code>from typing import Sequence</code></code></pre><p>Linear search is the most basic form of search. We have a sequence of elements, and we must determine whether one specific element is among them. Since we cannot assume anything at all from the sequence, our only option is to check them all.</p><pre><code><code>def find[T](x:T, items: Sequence[T]) -&gt; bool:
    for y in items:
        if x == y:
            return True

    return False</code></code></pre><p>Our first test will be a sanity check for simple cases:</p><pre><code><code>from codex.search.linear import find

def test_simple_list():
    assert find(1, [1,2,3]) is True
    assert find(2, [1,2,3]) is True
    assert find(3, [1,2,3]) is True
    assert find(4, [1,2,3]) is False</code></code></pre><h3><strong>Analyzing Linear Search</strong></h3><p>Once we have an implementation, we must subject it to the three-step analysis established in our foundations.</p><h4>Is it correct?</h4><p>The property of <strong>correctness</strong> ensures that for any valid input, the algorithm produces the expected output. For linear search, we can verify this through three increasingly formal lenses:</p><ul><li><p><strong>The Exhaustive Argument</strong>: Suppose an element x exists in the sequence. By definition, there is some index i such that <code>items[i] == x</code>. Since the algorithm performs an equality test over every single index in the sequence without exception, it is logically impossible to miss the item if it is there.</p></li><li><p><strong>The Inductive Argument</strong>: We can reason about the algorithm&#8217;s correctness across different input sizes. For a sequence of length 0, the loop never executes, and the algorithm correctly returns <code>False</code>. Assume the algorithm works for a sequence of length n. For a sequence of length n+1, the target x is either in the first n elements&#8212;where the inductive hypothesis ensures we find it&#8212;or it is the n+1-th element, which we check in the final iteration. If it is in neither, the algorithm correctly concludes it is not present.</p></li><li><p><strong>The Loop Invariant</strong>: We can define a formal invariant for the <code>for</code> loop: <em>At the start of iteration i, the element x has not been found in the first i&#8722;1 elements of the sequence.</em> By the time the loop completes at iteration n, if the function hasn&#8217;t returned <code>True</code>, we know with certainty that x is not in the first n elements, which constitutes the entire sequence.</p></li></ul><h4>How efficient is it?</h4><p>We analyze linear search using the <strong>RAM model</strong>, assuming each comparison and iteration step has a unitary cost.</p><ul><li><p><strong>Time Complexity</strong>: In the worst-case scenario (the item is at the very end or not present at all), we must perform n comparisons for a sequence of size n. This gives us a growth rate of O(n), or <strong>linear time</strong>.</p></li><li><p><strong>Space Complexity</strong>: The algorithm only requires a constant amount of extra memory to store the loop variable and the target, regardless of the input size, resulting in O(1) <strong>space complexity</strong>.</p></li></ul><h4>Is it optimal?</h4><p>Intuitively, linear search must be <strong>optimal for unstructured data</strong>. If we know <em>nothing</em> about the order or distribution of the elements, we are mathematically forced to look at every single item at least once to be certain x is not there. Any algorithm that skipped an element could be &#8220;fooled&#8221; if that specific element happened to be the one we were looking for. Thus, for a generic sequence, O(n) is the best possible lower bound.</p><p>To prove this more formally, we employ an <strong>adversarial argument</strong>, a powerful technique in complexity theory where we imagine a game between our algorithm and a malicious adversary.</p><ul><li><p><strong>The Adversary&#8217;s Strategy</strong>: Suppose an algorithm claims to find an element x (or prove its absence) by examining fewer than n elements&#8212;say, n&#8722;1 elements. The adversary waits for the algorithm to finish its n&#8722;1 checks.</p></li><li><p><strong>The &#8220;Trap&#8221;</strong>: Because there is one element the algorithm did not inspect, the adversary is free to define that specific element as x if the algorithm concludes &#8220;False,&#8221; or as something other than x if the algorithm concludes &#8220;True&#8221; without having seen it.</p></li><li><p><strong>The Conclusion</strong>: Since the adversary can always change the unexamined element to make the algorithm&#8217;s answer wrong, any correct algorithm <em>must</em> inspect every element in the worst case.</p></li></ul><p>This proves that the lower bound for searching an unstructured sequence is &#937;(n). Linear search, which operates in O(n), meets this lower bound exactly, making it a <strong>tightly optimal</strong> solution for the problem as defined. Unless we possess more information about the data&#8217;s structure&#8212;the central theme of the next chapter&#8212;we simply cannot do better.</p><h2><strong>Indexing and Counting</strong></h2><p>The <code>find</code> method is good to know if an element exists in a sequence, but it doesn&#8217;t tell us <em>where</em>. We can easily extend it to return an <em>index</em>. We thus define the <code>index</code> method, with the following condition: if <code>index(x,l) == i</code> then <code>l[i] == x</code>. That is, <code>index</code> returns the <strong>first</strong> index where we can find a given element <code>x</code>.</p><pre><code><code>def index[T](x: T, items: Sequence[T]) -&gt; int | None:
    for i,y in enumerate(items):
        if x == y:
            return i

    return None</code></code></pre><p>When the item is not present in the sequence, we return <code>None</code>. We could raise an exception instead, but that would force a lot of defensive programming.</p><p>Let&#8217;s write some tests!</p><pre><code><code>from codex.search.linear import index

def test_index():
    assert index(1, [1,2,3]) == 0
    assert index(2, [1,2,3]) == 1
    assert index(3, [1,2,3]) == 2
    assert index(4, [1,2,3]) is None</code></code></pre><p>As a final step in the linear search paradigm, let&#8217;s consider the problem of finding not the first, but <em>all</em> occurrences of a given item. We&#8217;ll call this function <code>count</code>. It will return the number of occurrences of some item <code>x</code> in a sequence.</p><pre><code><code>def count[T](x: T, items: Sequence[T]) -&gt; int:
    c = 0

    for y in items:
        if x == y:
            c += 1

    return c</code></code></pre><p>Let&#8217;s write some simple tests for this method.</p><pre><code><code>from codex.search.linear import count

def test_index():
    assert count(1, [1,2,3]) == 1
    assert count(2, [1,2,2]) == 2
    assert count(4, [1,2,3]) == 0</code></code></pre><h3><strong>Analysis</strong></h3><p>We won&#8217;t dwell too much in this section since the analysis is very similar to linear search&#8211;these are just specialized versions of it. Once more, we have O(n) algorithms (with O(1) memory cost) for a problem that is provable &#937;(n). Thus, given our assumptions (that there is no intrinsic structure to the elements order), we have optimal algorithms.</p><h2><strong>Min and Max</strong></h2><p>Let&#8217;s now move to a slightly different problem. Instead of finding one specific element, we want to find the element that ranks minimum or maximum. Consider a sequence of numbers in an arbitrary order. We define the minimum (maximum) element as the element <code>x</code> such as <code>x &lt;= y</code> (<code>x &gt;= y</code>) for all <code>y</code> in the sequence.</p><p>Now, instead of numbers, consider some arbitrary total ordering function <code>f</code>, such that <code>f(x,y) &lt;= 0</code> if and only if <code>x &lt;= y</code>. This allows us to extend the notion of minimum and maximum to arbitrary data types.</p><p>Let&#8217;s formalize this notion as a Python type alias. We will define an <code>Ordering</code> as a function that has this signature:</p><pre><code><code>from typing import Callable

type Ordering[T] = Callable[[T,T], int]</code></code></pre><p>Now, to make things simple for the simplest cases, let&#8217;s define a default ordering function that just delegates to the items own <code>&lt;=</code> implementation. This way we don&#8217;t have to reinvent the wheel with numbers, strings, and all other natively comparable items.</p><pre><code><code>def default_order(x, y):
    if x &lt; y:
        return -1
    elif x == y:
        return 0
    else:
        return 1</code></code></pre><p>Let&#8217;s write the <code>minimum</code> method using this convention. Since we have no knowledge of the structure of the sequence other than it supports partial ordering, we have to test all possible items, like before. But now, instead of returning as soon as we find the correct item, we simply store the minimum item we&#8217;ve seen so far, and return at the end of the <code>for</code> loop. This guarantees we have seen all the items, and thus the minimum among them must be the one we have marked.</p><pre><code><code>from codex.types import Ordering, default_order

def minimum[T](items: Sequence[T], f: Ordering[T] = default_order) -&gt; T:
    m = items[0]

    for x in items:
        if f(x,m) &lt;= 0:
            m = x

    return m</code></code></pre><p>The <code>minimum</code> method can fail only if the <code>items</code> sequence is empty. In the same manner, we can implement <code>maximum</code>. But instead of coding another method with the same functionality, which is not very DRY, we can leverage the fact that we are passing an ordering function that we can manipulate.</p><p>Consider an arbitrary ordering function <code>f</code> such <code>f(x,y) &lt;= 0</code>. This means by definition that <code>x &lt;= y</code>. Now we want to define another function <code>g</code> such that <code>g(y,x) &lt;= 0</code>, that is, it <em>inverts</em> the result of <code>f</code>. We can do this very simply by swapping the inputs in <code>f</code>.</p><pre><code><code>def maximum[T](items: Sequence[T], f: Ordering[T] = default_order) -&gt; T:
    return minimum(items, lambda x,y: f(y,x))</code></code></pre><p>We can easily code a couple of test methods for this new functionality.</p><pre><code><code>from codex.search.linear import minimum, maximum

def test_minmax():
    items = [4,2,6,5,7,1,0]

    assert minimum(items) == 0
    assert maximum(items) == 7</code></code></pre><p>The correctness, cost, and optimality analysis is very similar in these cases as well.</p><h2><strong>Conclusion</strong></h2><p>Linear search is a powerful paradigm precisely because it is universal. Whether we are checking for the existence of an item, finding its index, or identifying the minimum or maximum element in a collection, the exhaustive approach provides absolute certainty. No matter the nature of the data, if we test every single element and skim through every possibility, the problem will be solved.</p><p>The primary drawback of this certainty is the cost: some search spaces are simply too vast to be traversed one item at a time. To achieve better performance, we must move beyond the assumption of an unstructured sequence. We need to know more about the search space and impose some level of structure.</p><p>In our next chapter, we will explore the most straightforward structure we can impose: <strong>order</strong>. We will see how knowing the relative position of items allows us to implement what is arguably <em>the most efficient and beautiful algorithm ever designed</em>.</p><p>But that&#8217;s a story for another Tuesday.</p><blockquote><p><em>Remember you can read the <a href="https://matcom.github.io/codex">full draft online</a> (currently Part 1) or get a <a href="https://store.apiad.net/l/codex">beautifully typed PDF</a> if you want to support the project.</em></p></blockquote>]]></content:encoded></item><item><title><![CDATA[The Most Beautiful Algorithms Ever Designed]]></title><description><![CDATA[A very opinionated short list.]]></description><link>https://blog.apiad.net/p/the-most-beautiful-algorithms-ever</link><guid isPermaLink="false">https://blog.apiad.net/p/the-most-beautiful-algorithms-ever</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Mon, 10 Feb 2025 12:03:23 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="6000" height="4000" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4000,&quot;width&quot;:6000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;black and white computer keyboard&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="black and white computer keyboard" title="black and white computer keyboard" srcset="https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1586776977607-310e9c725c37?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1MXx8bGVnb3xlbnwwfHx8fDE3MzkxNTIxNTd8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="true">Ken Suarez</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Donald Knuth, the father of algorithm design and analysis and one of the most impactful, insightful, and influential people in Computer Science, said science is what we understand well enough to explain to a computer, and art is everything else we do. In his view, computer programming is a form of art, and he is undoubtedly a masterful artist.</p><p>Whether you subscribe to this broad notion of "art" or not, you won't deny there are a handful of ideas in Computer Science that are so elegant, creative, innovative, powerful, or just downright beautiful that they at least blur the boundary between science and art.</p><p>In this post, I want to kick off a new series exploring the idea that some algorithms are inherently beautiful, regardless of their technical details. I will suggest what I consider the most beautiful algorithms ever designed and give you a short rationale for their selection. Then, in future posts, I will discuss each of these in detail and, hopefully, convince you that they are, indeed, beautiful.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.apiad.net/subscribe?"><span>Subscribe now</span></a></p><h2>What makes an algorithm beautiful</h2><p>Many believe, myself included, that beauty is in the eye of the beholder. Thus, deciding what the most beautiful algorithms ever are is a highly personal and subjective endeavour. Still, I want to justify my personal criteria for selecting some algorithms among others. You may agree to some extent with these points or disagree entirely, but I hope you'll at least understand where I'm coming from when I say some algorithms are beautiful.</p><p>First and foremost, I value elegance. Anyone can solve a complicated problem with a similarly complicated solution, full of special cases and tricks. But there is beauty in finding a simple, clear, elegant solution that happens to be as effective or more than anything else you can think of.</p><p>Second, I value cleverness. Simple ideas, yes, but also powerful ideas that exploit some hidden insight or reveal something unique about the problem they're solving. Bonus points if they involve clever mathematics.</p><p>Finally, I also consider the impact of these algorithms. Many of the most beautiful algorithms are broadly applicable and unlock entire branches of knowledge that were previously hidden.</p><p>However, there are also algorithms so unique and weird that they deserve special mention, if only because they show how far the human intellect can go to find solutions to interesting problems. I have a few of these.</p><h2>The List of Beautiful Algorithms</h2><p>Based on the above criteria, I created a long list of candidate algorithms. Then, I narrowed it down to 16 because it is a beautiful but still manageable number. Of course, this limitation is totally arbitrary, but so is everything else in this article.</p><p>When deciding what to include, I also prioritized diversity. For example, I left out many beautiful graph algorithms, not necessarily because the other algorithms in this list are more beautiful. We could fill the whole list with clever ideas from graph theory, and I preferred to go wide rather than deep here.</p><p>All of these algorithms have some unique, clever insight that makes them work. All of them are paradigmatic of a particular technique for algorithm design. In general, I think they cover a broad spectrum of the type of reasoning involved in crafting algorithms, and I hope they'll give you a good taste of what it means to be creative in computer science.</p><p>So, without further ado, here is my list of the most beautiful algorithms ever designed. Except for the first one, this list is in no particular order.</p><h3>Binary Search</h3><p>If there is an algorithm that should be number one in every list of beautiful algorithms, that is Binary Search. It is the simplest, most clever algorithm ever designed. It deals with the most straightforward version of the most important problem in computer science: search. And it does so in the most marvellous and efficient possible way.</p><p>Binary Search is the first serious algorithm you will probably ever learn in a CS major, and the first one that does something truly clever: by optimally exploiting the structure of the data, Binary Search manages to find any element in a very, very large collection in the blink of an eye. It is so fast that if you had to search the whole universe (all &nbsp;10^80 or so particles in it), you would need no more than 300 operations&#8212;probably much less than a millisecond in any modern computer.</p><p>To achieve this, Binary Search requires only one key assumption: the data must be sorted. If that's the case, Binary Search is perfect. It prunes the search space in a way that can be mathematically proven optimally efficient&#8212;in the sense that it makes the most efficient use of the information available in the ordering of the search space. It is impossible to be any faster when all you can rely on is the order of elements.</p><p>Binary Search teaches us something profound about the nature of search and problem-solving in general: it teaches us that structure matters a lot. If you can organize the search space in a meaningful way, you can search through it in a breeze. In a sense, this is the most crucial insight in computer science: all computer science problems are ultimately search problems, and all clever solutions to search problems are, in a sense, finding ways to organize the search space for effective pruning.</p><h3>QuickSort</h3><p>If search is the most important problem in CS, then sorting is probably the most well-studied one. Among the many flavours of sorting, the simplest incarnation is sorting a finite list of numbers (or comparable items in general). And here, QuickSort is undoubtedly the king of the pack.</p><p>QuickSort is not only among the fastest general-purpose sorting algorithms&#8212;its name alone says so&#8212;but it is also probably the most elegant. It cleverly uses randomization to ensure that, on average, we make the optimal selection that leads to the fastest possible sorting strategy.</p><p>Quicksort is the simplest example of a clever use of randomization aimed not at producing an approximate result but rather at making an algorithm robust to all possible inputs. The algorithm's balance of speed and simplicity epitomizes beauty in design and demonstrates the harmony between theoretical elegance and practical application.</p><h3>A* Search</h3><p>A* is an extension to the most beautiful graph algorithm&#8212;Dijkstra&#8217;s shortest path&#8212;to incorporate domain knowledge as a heuristic function. A* achieves extraordinary efficiency by balancing the cost to reach a node (what we know for sure) with a heuristic estimate of the cost to reach the goal (what we can guess). This synergy allows it to explore pathways intelligently, often finding optimal solutions with significantly fewer computations than uninformed methods.</p><p>Its adaptability makes A* valuable in theoretical contexts and real-world applications, such as route planning in navigation systems and AI for games, where understanding and optimizing paths is critical.</p><p>This algorithm beautifully balances exploration and exploitation, always finding the shortest path while minimizing cost. It is a prime example of the combination of formal and heuristic thinking.</p><h3>RSA</h3><p>RSA is a paradigmatic algorithm in public-key cryptography. It is the first algorithm to achieve something that intuitively seems paradoxical: sending a message through a public channel to another party that is impossible for anyone except them to decipher, even though everyone else knows all the details of the communication protocol and can see all messages.</p><p>RSA relies on the difficulty of factoring prime numbers, which for a very long time was thought to be a pure mathematical pursuit devoid of any practical applications. But then cryptography came with a simple but very powerful insight: that some functions are easy to compute but almost impossible to invert&#8212;aptly called one-way functions.</p><p>RSA was the first algorithm to show how one could build truly unhackable systems using clever math (at least before quantum computing was a thing). Nowadays, stronger cryptographic frameworks work even under the threat of ubiquitous and cheap quantum computing. But all of them owe their birth to the unique insights unlocked by RSA.</p><h3>Fast Fourier Transform</h3><p>The Fourier transform is undoubtedly the most important operation in signal processing. It allows the decomposition of any signal into its individual frequency components, and it has uncountable applications, from compression to pattern recognition to synthesis.</p><p>However, for a very long time, it was considered an intrinsically expensive operation, applicable only to shorter sequences. The FFT is a revolutionary algorithm that transforms signals from their original domain to the frequency domain, allowing for efficient data analysis and processing. It's hard to oversell its importance; for many, it's the single most impactful algorithm ever designed.</p><p>FFT is instrumental in numerous applications, including digital signal processing, image analysis, and solving partial differential equations. Its profound impact on both mathematics and engineering underscores its elegance, showcasing how computational efficiency can radically enhance data interpretation and manipulation.</p><h3>K-means</h3><p>K-means is a straightforward but powerful clustering algorithm that partitions data into distinct groups. It answers how to classify different objects when you know almost nothing about them. The key insight is that similar objects should be bundled together and separated from other bundles of similar objects.</p><p>Despite its simplicity, K-means can provide insights into the underlying structure of complex information. When K-means is not enough (because the data is too complex), we often resort to methods that, deep down, are basically a transformation of the data followed by a K-means-like approach.</p><h3>KMP</h3><p>KMP, or the Knuth-Morris-Pratt algorithm, is a highly efficient string-searching method that finds the occurrences of a pattern within a text in linear time. The clever idea in KMP is that past searches, even failed ones, provide information about future searches. By preprocessing the pattern to create a partial match table, KMP optimally skips unnecessary comparisons, enhancing the searching process.</p><p>This clever design mitigates the performance issues seen in naive approaches, making it particularly suitable for applications involving large datasets such as text editing, data parsing, and bioinformatics.</p><h3>Minimax</h3><p>Minimax is a fundamental algorithm used in decision-making and game theory, particularly in zero-sum games. It systematically evaluates possible moves by minimizing the possible loss in a worst-case scenario. Minimax answers the question of what one should do to behave optimally in a sequence of decisions, assuming everyone else is also behaving optimally. This strategic approach not only aids in deriving the optimal move for a player but also prevents adverse outcomes against an opponent&#8217;s best strategy.</p><p>Despite its power, Minimax stands out for its simplicity. It is the backbone of many AI implementations in competitive gaming contexts. Although it is no longer the algorithm of choice for practical implementations of optimal AI players, its theoretical properties still inform the design of every decision-making algorithm in adversarial environments.</p><h3>Monte Carlo methods</h3><p>Monte Carlo methods are a family of extremely powerful statistical techniques used to understand and quantify uncertainty in prediction and forecasting models. The purpose is to find some optimal solution, e.g., an optimal strategy in a sequence of decisions that involve uncertainty or inherent randomness. </p><p>Monte Carlo exploits the intuitive idea of random sampling but with a clever twist: as you obtain more information about some specific outcome, the uncertainty about it decreases. By balancing the expected potential of each outcome with its uncertainty, Monte Carlo efficiently finds the best solutions while minimizing wasted effort by exploring unpromising ones.</p><p>It is hard to overstate the importance of Monte Carlo. Its many variants are widely applied anywhere from finance and engineering to computer science, AI, and physical sciences, allowing analysts to model scenarios that would be infeasible to compute deterministically. Its versatility and capacity for simulating the unpredictable make it an invaluable tool for decision-making.</p><h3>Genetic Algorithms</h3><p>Genetic Algorithms (GA) are a family of general-purpose optimization strategies inspired by the principles of natural selection and genetics. They employ mechanisms such as selection, crossover, and mutation to evolve solutions over time. This adaptive search technique is incredibly effective for optimization problems, exploring a vast solution space through iterative improvements.</p><p>GAs are used everywhere we find complex optimization problems: in engineering, economics, or artificial intelligence, just to mention a few cases. Their ability to emulate evolutionary processes reveals a profound connection between biological principles and computational strategies, underscoring their elegance and utility.</p><h3>Raytracing</h3><p>Raytracing is the quintessential computer graphics algorithm. It's a straightforward approximation of the rendering equation that can simulate how light interacts with different objects to create photorealistic images. Raytracing is a recursive algorithm that follows light rays as they bounce through a virtual scene and are reflected, refracted, or absorbed.</p><p>Every time you see a CGI effect in a Hollywood movie, whether live-action or animated, Raytracing is working behind the scenes. Modern rendering algorithms are significantly more complex but ultimately based on the same principles.</p><h3>SVD</h3><p>SVD, or Singular Value Decomposition, is easily the most important linear algebra algorithm for data representation and analysis. At its core, SVD is about finding an optimal representation of the values in a matrix that preserves as much information as possible. When used on real data, SVD reveals intrinsic structures that enable processes like noise reduction and feature extraction.</p><p>This method is critical in machine learning applications like image classification and natural language processing. Its ability to simplify complex datasets highlights its significance, demonstrating how advanced mathematical techniques can lead to practical solutions in various applications.</p><h3>Deflate</h3><p>Deflate is a widely used compression algorithm that reduces data size to optimize storage and transmission. It cleverly combines the two most paradigmatic approaches to data compression: LZ77 (pattern-based) and Huffman (information-theoretic) coding.</p><p>Deflate is the underlying algorithm for many widely used file formats, including ZIP files and PNG images, where maintaining data integrity during compression is vital. The algorithm's ability to balance efficiency and compression ratio makes it a valuable tool in applications ranging from software distribution to data archiving.</p><h3>HyperLogLog</h3><p>HyperLogLog is the kind of algorithm that looks like magic. It solves what seems like an unsurmountable problem with a genuinely clever idea. The purpose of HyperLogLog is to allow very accurate estimates of the total number of items in a very, very large dataset when items are added asynchronously in real time. Think about counting all likes in a hugely viral YouTube video.</p><p>Using hash functions and a clever data summarising technique, HyperLogLog maintains a minimal memory footprint while providing accurate estimates of unique elements. Anywhere you see massively distributed databases, you can probably find HyperLogLog or a variant of it underneath the most basic counting operations.</p><h3>PageRank</h3><p>PageRank is the algorithm that propelled Google to dominate the online search market. It assigns a numerical score to each page, reflecting its importance based on the number and quality of links pointing to it. The quirk is that the Internet is huge, so effectively computing this value for all web pages is unfeasible.</p><p>PageRank builds a probabilistic model that estimates the likelihood of a user landing on a particular page. It uses clever numerical approximation techniques to avoid processing the entire Internet graph every time a new web page is added or removed. Beyond search, PageRank is useful for estimating the importance of individual nodes in any type of network, such as social media or knowledge graphs, so it is also widely used in research.</p><h3>Backpropagation</h3><p>Backpropagation is probably the most important algorithm of the AI revolution. It is the algorithm that allows the training of artificial neural networks efficiently by computing gradients of the loss function with respect to the model's weights and propagating errors back through the network layers.</p><p>Its discovery in the 80s allowed for the first time to train arbitrarily deep neural networks, which are behind most, if not all, modern AI applications, including image recognition, natural language understanding and generation, and even reinforcement learning.</p><h2>Closing remarks</h2><p>And there you go. Again, keep in mind this is just my personal selection, and many of you can and most likely will disagree with me on some or maybe all of them--well, except Binary Search, that's a hill I'm willing to die on!</p><p>In future posts, I will explore each of these algorithms, explaining not only how they work in the most intuitive terms possible but also highlighting what makes them stand out as some of the most beautiful ideas ever conceived in computer science.</p><p>Until then, I would love to hear your thoughts on this topic. Do you think algorithms, and abstract ideas in general, can be beautiful? Why, or why not? And, if you answer yes, then what do you consider the most beautiful algorithms ever designed?</p>]]></content:encoded></item><item><title><![CDATA[The Power of Abstraction]]></title><description><![CDATA[Or how to think like a Computer Scientist.]]></description><link>https://blog.apiad.net/p/the-power-of-abstraction</link><guid isPermaLink="false">https://blog.apiad.net/p/the-power-of-abstraction</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Mon, 18 Nov 2024 12:02:17 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="3708" height="2848" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2848,&quot;width&quot;:3708,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;shallow focus lens photography of LEGO toys&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="shallow focus lens photography of LEGO toys" title="shallow focus lens photography of LEGO toys" srcset="https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1517012068311-53ed5975e234?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw5fHxicmlja3N8ZW58MHx8fHwxNzMxNzk3MzQ5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="true">Adi Suryanata</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Abstraction is the fundamental ability that powers the way computer scientists think through and solve problems. It is the most important tool in the computer scientist's arsenal and often the hardest skill to master.</p><p>It is also a very powerful tool for general-purpose problem-solving. The right abstraction can often unlock unforeseen solutions to otherwise intractable problems. In some rare cases, it even allows for fundamentally novel insights only possible by thinking at the right level of abstraction.</p><p>In this article, I will explain abstraction in the context of solving problems, why it is such a powerful tool, and finally, give a concrete tip on how to improve at it.</p><p>This article is part of a series on computational thinking called <em>How to Think like a Computer Scientist</em>. In this series, I explore techniques from the computer scientist&#8217;s toolset and how they can be applied by anyone to solve problems in any domain.</p><p>If you want to learn more, subscribe for free to get future articles directly in your inbox.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.apiad.net/subscribe?"><span>Subscribe now</span></a></p><h2>Abstraction in action</h2><p>Abstraction is the process of taking a problem, situation, or concept in general, removing all irrelevant details, and leaving a simplified, more general version that captures what is truly essential to the thing being abstracted.</p><p>Abstraction is a form of purposeful simplification&#8212;but not one that stems from laziness or a lack of capacity. It's a meaningful simplification that makes a problem easier to solve but also more general and, thus, more relevant.</p><p>What is relevant or not about any given concept or situation is very contextual. Depending on the type of analysis you want, the same details may or may not be important.</p><p>That is, the why determines the what.</p><p>To see this in action, let's begin with a typical example from a typical computer science class.</p><h3>An example problem</h3><p>Suppose you want to solve the problem of getting as fast as possible from home to work. How could we solve this?</p><p>We first need to understand two things: what we are exactly asking for and what our decision space is, that is, what we can do.</p><p>For example, this problem is very different if you use public transportation or a personal vehicle. That is, the means by which you can move is an important detail, as it will determine your decision space. Can you travel through any street, and stop anywhere? Or do you need to pick from a predesigned set of routes and stop at one of the predetermined bus stations?</p><p>Likewise, the problem changes if we want to minimize total travelling time, fuel cost, time spent waiting at red lights, or the total number of swears thrown at cyclists.</p><p>Suppose you pick a goal: minimize total time spent on the road. Furthermore, assume you have a personal vehicle that can, in principle, travel anywhere in the city.</p><p>This is already an exercise in abstraction because we are deciding, for example, that the level of risk of a given road is irrelevant. We want the fastest route, not the safest. We could have done the opposite or somehow tried to find something in between.</p><p>The point is that deciding what matters immediately makes some otherwise important details irrelevant to this particular instance of the problem.</p><h3>Making the problem tractable</h3><p>Are we ready to solve the problem? Well, not yet. There are still a thousand factors that can determine how fast you can move around the city: traffic, semaphore lights, pedestrians, quality of the road... And worse, all of this changes daily, perhaps even every second! If we want to have a chance to tackle this problem at all, we'll have to make some further simplifications. </p><p>So, let's assume we can model each road segment as a straight line between intersections, with an average time cost associated. That is, we throw away all the details of a given road except for the average time it takes to traverse it. It doesn't matter how many lanes the road has or how bumpy it is. Also, it doesn't matter which time of day or year we happen to be.</p><p>This is a huge simplification, but one that makes the problem tractable with a very efficient computational algorithm&#8212;Dijkstra's algorithm, to be precise.</p><p>The details of the solution don't matter for the purpose of this article. What matters is that by simplifying this initially seemingly unsurmountable problem in a meaningful way, we obtain a tractable problem that we can solve with clever math.</p><h3>Back to the real world</h3><p>Now comes the real question: How well does the answer to the artificial, simplified, abstract problem we ended up solving apply to the real-world problem we started with?</p><p>The answer, of course, is that it depends. It depends mostly on how important the details we left out were. Every abstraction is a simplification, and thus, any solution to an abstract problem is, at best, an approximate solution to a real problem.</p><p>But approximations are all we can have in practice. All real-life problems are infinitely detailed if you take everything into consideration. If you want an exact answer to a real-life problem, you may need to consider the physics of the entire universe!</p><p>So, the answer to how good the approximation is, is this: as good as your abstraction is at capturing what is truly essential to the problem and throwing away what doesn't matter.</p><p>In this particular case, we'll have a pretty good solution, assuming the average times we assign to each road are really characteristic of said road and not just random values. But there is something even more valuable in what we've done, which is why abstraction is such a powerful tool.</p><p>Let's take a look at the bigger picture.</p><h2>Why abstraction is so powerful</h2><p>The power of abstraction can be seen in at least three different levels.</p><h3>Abstraction as simplification</h3><p>We've already seen the first level: abstraction makes problems easier to solve. Since abstracting is simplifying&#8212;as we are, by definition, removing details&#8212;we end up solving a problem that is, in some sense, smaller.</p><p>In our path-finding example, we simplified things a lot by deciding we didn't care for the width of the roads, the elevation of the terrain, the pavement quality, the weather, and many other details that would make the original problem impossible to solve.</p><p>In this simplified version of the problem, we can actually do some math and come up with a sensible solution. Perhaps, as in this case, we can even prove we have an optimal solution (to the simplified problem, that is). Thus, abstraction can make hard problems tractable or at least a bit easier.</p><h3>Abstraction as generalization</h3><p>But the second level is even more profound. By abstracting away the things that made our example problem related to cars, roads, and pedestrians&#8212;since, ultimately, those things weren't essential&#8212;we actually ended up solving a more general problem: finding a minimum-cost route in a graph.</p><p>In doing so, we not only solved our mundane go-to-work problem but also solved all the problems of going from anywhere to anywhere else with minimum cost, as long as we only cared about the cost of each connection. And since we didn't define cost in any particular way&#8212;just some number that must be minimized&#8212;we can apply this solution to time, money, fuel, and any other magnitude we care about!</p><p>Now, instead of a car in a city, think of a network of airports worldwide where you want to reach a destination by paying the minimum price. The abstract version of that problem is the same as this one if the cost of each route is the ticket price.</p><p>Likewise, we can think of minimizing transmission time in a computer network or even maximizing the probability of a message reaching a destination. All of these are instances of the minimum-cost path-finding problem we just solved! </p><p>Thus, since an abstraction is also a generalization, in another sense, you end up solving a bigger problem than you originally had and get almost for free the solution to a potentially infinite number of similar problems.</p><h3>Abstraction as conceptualization</h3><p>Finally, there is a third level, but you must trust me here because it's hard to give you a simple example. The thing is, by abstracting problems, we can sometimes find answers to questions that weren't even conceivable in the concrete problems.</p><p>This works because abstraction is also a form of concept creation: you create new concepts and relations that unlock new ways of thinking about things. These new concepts, in turn, let you discover new truths that were invisible before.</p><p>Some of the most important ideas in computability theory, such as the existence of specific, non-trivial, and relevant problems that cannot be solved at all, are only possible because we have very abstract notions for the concepts of algorithm, computer, and problem.</p><p>So, if abstraction is such a powerful tool, how can one get better at it?</p><h2>Mastering abstraction</h2><p>The short answer is that there is no shortcut, no easy formula. You get better at problem-solving in any domain by solving a lot of problems in that domain.</p><p>However, I can give you a concrete tip here. It's going to sound like a plug, but hear me out.</p><p>Abstraction is a very powerful tool for solving real-life problems in any domain. But there is one particular domain where it shines: computer programming.</p><p>The reason is that computer programming is, by definition, an exercise in abstraction. Digital computers are almost incapable of dealing with the fine-grained nature of real-life problems. Programming languages require very precise, clear instructions and definitions. So, any solution to any problem using a computer is a solution to an abstract problem.</p><p>If you want to improve at coming up with good abstractions, whatever you work on, you can start by learning to code. Getting any level of expertise in coding will force you to learn to abstract problems as a side effect.</p><p>In a sense, learning to code is like going to the gym, but for the mind. </p><p>Some people are professional athletes. Some even compete at the Olympic level in weightlifting. Some go to the gym for fun or just to show off. But almost anyone, regardless of their daily job, could benefit from a healthier body, stronger muscles, and more agility.</p><p>Likewise, some people code for work or fun. But almost anyone would benefit from thinking better, and being better at abstract thinking is one of the best ways to improve your general problem-solving skills.</p><p>This would be just about the right time to promote my programming book or course, but I won't. Truth is, you don't need me for that. Search online, pick the top 3 or 4 results, try them out, and choose the one that best fits your learning style and pace.</p><p>Now, don't get me wrong. I've said before most learning resources out there suck, but that is about learning to code at a professional level. Just like professional athletes need state-of-the-art equipment and world-class trainers, but if all you want is to get a bit healthier, buying a couple of dumbbells or even just doing half a dozen push-ups every day gets you most of the way there.</p><p>So there you have it. Learn to code. Doesn't matter which language or development stack. Just grab a coding tutorial and get used to doing a couple of programming exercises every week. That alone will make you a much better thinker in time.</p><h2>Closing remarks</h2><p>In a previous article, I described the main principles that guide my educational ethos. One of these principles is <em>show, then tell</em>. The basic premise is that explaining a complex idea is best achieved by first showing things and then explaining how they work.</p><p>Some of you asked me for examples of these principles. This article is one example of show, then tell. First, I showed you how abstraction works in a concrete example and then explained the general concept.</p><p>Actually, this article is a meta-example of show, then tell. First, I showed you how show-then-tell works, and now I'm telling you about it. Hope you enjoyed it ;)</p><p>Going back to the main topic, this article is part of a series I'm writing on how to bring the tools of computational thinking into your daily life. If you want to learn to think like a computer scientist, stick around. I'll be sharing a lot more in future articles.</p>]]></content:encoded></item><item><title><![CDATA[Why everyone should learn to code]]></title><link>https://blog.apiad.net/p/why-everyone-should-learn-to-code</link><guid isPermaLink="false">https://blog.apiad.net/p/why-everyone-should-learn-to-code</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Fri, 25 Oct 2024 10:31:48 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="5184" height="3888" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3888,&quot;width&quot;:5184,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;a group of wooden toys sitting on top of a table&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="a group of wooden toys sitting on top of a table" title="a group of wooden toys sitting on top of a table" srcset="https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1637144113512-0fb2b860c10f?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1M3x8cGllY2VzfGVufDB8fHx8MTcyOTc5ODQwM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="true">Dan Cristian P&#259;dure&#539;</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>You should learn to code.</p><p>Yes, you! No, I don&#8217;t know who you are or what interests you, but I know you can and should learn to code. There are many obvious and not-so-obvious reasons why learning to code is one of the best intellectual investments you can make in yourself.</p><p>The most obvious reason is that coding is a high-paying skill, and being good at it pretty much guarantees you can find a good job at any of the million software companies hiring like crazy out there. </p><p>Yes, I&#8217;m sure you&#8217;ve heard many stories of developers struggling with coding interviews and getting rejected dozens of times. And sure, even some of the best coders out there can fail at a given time for a myriad of reasons, including bad luck.</p><p>But the thing no one tells you is how few of the people applying for a coding interview today can actually code. And it&#8217;s not their fault. Many have learned superficial coding practices from dubious YouTube instructors or cheap online blogs. But learning to code, in the sense I&#8217;m using the term, implies an entirely different level of understanding.</p><p>To be fair, there are also plenty of cases where the interviewer doesn&#8217;t understand what a good programmer looks like. Some coding interviews focus way too much on programming language trivia or algorithm design challenges, which are, at best, imperfect proxies for measuring good coding skills.</p><p>In any case, learning to code well is a very marketable skill. If you want a job in the tech industry, being a reasonably good programmer will get you halfway there.</p><p>But even if you don&#8217;t want a job in the software industry, there is a very good reason why learning to code is one of the best intellectual investments anyone can make today. The reason is that <em>coding teaches you to think in a completely new way</em>, making you extremely good at solving problems in all domains, even without a computer.</p><p>But to explain why, let me first tell you what coding is really about.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2><strong>What is coding about</strong></h2><p>Coding is part science, part engineering, and part art. It is a science because it requires understanding and applying well-established, formally defined principles and techniques to solve complex problems. It is engineering because it requires the ability to design and build systems with complicated trade-offs. It is art because it requires&#8212;and boosts&#8212;creativity and imagination to create beautiful solutions to challenging problems.</p><p>Beautiful, right? But, in practice, what the hell does this mean? At a surface level, coding seems similar to any other technical skill, like, I don&#8217;t know, using advanced industrial machinery and tools. In a sense, coding is about using computers to do stuff, right? Why isn&#8217;t this just the same as using, say, a hammer and some nails to build a house?</p><p>For starters, yes, the computer is a kind of tool, but it is a completely different kind of tool. Most tools extend our physical capabilities or help us overcome our physical limitations. They make us stronger, faster, more precise. </p><p>The computer, on the other hand, is a tool to <em>extend our minds</em>. Computers help our brains do stuff they cannot do easily by themselves. They help us overcome our <em>cognitive</em> limitations.</p><p>But programming is far less about computers than you think. The great Edsger Dijkstra is often quoted claiming that computer science is as much about computers as astronomy is about telescopes. Computers are just a tool&#8212;an incredibly powerful tool&#8212;but the important part is not the tool you use, but what you do with it.</p><p>Programmers use computers to solve problems.</p><p>This is the deeper reason why learning to code is a different type of skill&#8212;a more general skill than it initially seems. <em>Coding is general-purpose problem-solving</em>. In fact, there is no problem that can be solved at all that cannot be solved with a computer&#8212;this is&nbsp;the Church-Turing thesis. Learning to code is, ultimately, learning to solve problems.</p><p>Why? Coding relies on one fundamental ability called&nbsp;<em>abstraction</em>, which is the process of taking a problem, situation, or concept in general and stripping it down to its core defining features,&nbsp;forgetting everything that is irrelevant or useless for the concrete purpose you have at hand.</p><p>And the thing is, abstraction is the most useful cognitive ability in the modern world. It is at the core of problem-solving. Any sufficiently complex problem requires you to think at several levels of abstraction and switch between them constantly. In fact, the ability to think at the right level of abstraction at any given point in the process of solving a concrete problem is probably the most critical ability to master to become a really good programmer.</p><p>Let me draw a cheap analogy here. Consider driving a car from home to work. Many things happen inside your car, including a bunch of physical and chemical processes, that are fundamental for the car to work correctly. But thinking about the combustion process going inside your engine is useless for reaching your destination&#8212;if your car is working correctly, at least. Actually, worrying about your engine's chemical reactions while driving arguably makes you a worse driver, not a better one.</p><p>Instead, when driving in the city, you often need to deal with three different levels of abstraction. The lowest level is just to make the car move: shifting gears in due time, pressing the pedals, etc. The middle level is about not crashing: avoiding incoming traffic, staying in your lane, etc. The higher level is about navigation: picking the right path to reach your destination most efficiently.</p><p>When people learn to drive, they often learn to think at the lowest level of abstraction first. They struggle to make the car move. But once they master this level, it becomes almost automatic, and they can start to think in terms of what other cars are doing and how to negotiate the road. And finally, they are able to navigate around town seemingly without effort, while casually talking about, I don&#8217;t know, programming maybe.</p><p>Similarly, in computer programming, you will often deal with three simultaneous levels of abstraction.</p><p>First, we have the code level. At this level, all you care about is expressing the solution to a problem in a language that a computer can understand. Computers are very dumb machines, you see. For all their power, you need to talk to them in very, very precise terms using a programming language. This may seem daunting at first, because it requires a very strict use of syntactic rules, but almost everyone can learn to write and read computer code, just like almost everyone can learn to accelerate, break, and turn. This is the easier task.</p><p>The second level is the algorithm level. At this level, you care about actually solving a problem by designing what is called an&nbsp;<em>algorithm</em>. In short, an algorithm is a very precise set of instructions that is guaranteed to provide a solution for a given problem. Coming up with the best algorithm for a problem is a pretty advanced skill, one that is almost always left for college-level advanced programming courses. But fear not, is one skill that can be mastered with enough practice.</p><p>The third level is the system level. At this level, you think about the design of a complex system made out of multiple interacting components, often hundreds of tiny algorithms working together to solve a big problem. Also, in this level, you have to think about the end user of your code, either a human on the other side of the display or a computer on the other side of the planet. Systems thinking is probably the hardest skill in this combo, but it can also be mastered in due time, and it is tremendously useful even outside computer programming.</p><p>In larger organizations, people tend to specialize in roles that focus most on one level of abstraction. For example, software architects might spend most of their time thinking about the system as a whole and far less about low level details. Still, the ability to move through abstraction layers is there.</p><p>So, learning to code will teach you to think at several levels of abstraction simultaneously: to decompose problems into parts, solve each in the best possible way, and then make those parts work together to become a solution to the original problem. It will teach you to think rigorously about why some potential solution doesn&#8217;t actually work and to detect subtle reasoning flaws in code&#8212;and, by extension, in other people&#8217;s behaviours as well as your own.</p><p>In short, coding makes you a better thinker. And thinking better is arguably the best recipe for success in general life, all other things being equal.</p><h2><strong>Why learning to code (well) is hard</strong></h2><p>But if learning to code is such a great cognitive investment and automatically makes everyone better at solving real-life problems, why are so many computer programmers out there not&#8230; being great at life?</p><p>Just like learning to drive, most people will master the lowest level first. They will learn how to express known solutions to known problems in computer lingua. They will learn to <em>write working code</em>.</p><p>But then, most people stay here. They can make the car move, but they can&#8217;t navigate to their destination, nor can they plan the best route and avoid the morning traffic. And the reason they don&#8217;t advance more is, often, because they don&#8217;t even know there is something else to be learned.</p><p>You see, most resources to learn how to program out there will actually just teach you how to write code. They will not teach you how to think about problems in the way good programmers do, so you can come up with clever solutions to these problems. There are books on this, too, of course. But most are college textbooks or advanced technical books that aren&#8217;t marketed at or even written for the first-time learner.</p><p>On the other hand, you will find a lot of books on how to do software engineering, and how to design systems that are reliable, maintainable, and a bunch of other fancy adjectives. But these are most often, I kid you not, written as if for people who already know this stuff. Much like college-level math books&#8212;that you often need to already know the math to even be able to read the book&#8212;the majority of books on software engineering are written by software engineers for software engineers, and they are talking among themselves, repeating the same mantras they already agree on.</p><p>Don&#8217;t get me wrong, there are good resources out there. But there are vastly, vastly more bad resources that won&#8217;t get you very far down the road that really matters: learning to think like a computer programmer. We already said this requires thinking at different levels of abstraction, and most learning resources never touch more than one of these levels.</p><p>But beyond the lack of good holistic learning resources, the deeper reason why learning to code is hard is precisely because it requires that you rewire your brain to think in a different, novel, more abstract and rigorous way. And your brain doesn&#8217;t want to do that. </p><p>Your brain evolved to keep you alive&#8212;actually, to transmit your genes&#8212;and for that, it needs to focus on mastering only two skills: getting food and getting laid. All else is secondary.</p><p>So, you have to trick your brain into believing that this is a critical skill to acquire. And that takes a lot of time and a lot of patience. No one learns to code well in 24 days or two months or even a full college semester. And, more importantly, <em>no one learns to code by watching others code</em>. That is a small part of learning, but you have to do the chores.</p><p>Coding is much more an acquired skill than learned knowledge. There is some knowledge involved, for sure. There are algorithms you can memorize. There is syntax and semantics and rules. There are design patterns and reusable ideas. But more than all of that, coding is the <em>process</em> of taking a complex problem, breaking it down into manageable parts, and then explain in the most precise possible language how to solve each of those parts, and how to put them together again.</p><p>That is, coding is about <em>doing</em> stuff much more than it is about <em>knowing</em> stuff. And there is only one way to learn how to <em>do</em> something: practice, lots of practice. And most people who think they can code out there simply haven&#8217;t put enough time into it.</p><h2>But what about AI?</h2><p>Yes, the elephant in the room! Will AI make coding skills irrelevant? Aren&#8217;t programmers coding themselves out of job? </p><p>Good that you ask. I&#8217;ve written many times before about why the current language modelling paradigm is, on the one hand, incapable of true reasoning and, on the other hand, unlikely to replace programmers anytime soon. So let me just repeat a few arguments here for the sake of completion.</p><p>First, code generators are indeed powerful tools that any professional programmer would do well to learn how to integrate effectively into their workflow. They can automate some of the most boring tasks and provide some much-needed unblockers from time to time.</p><p>However, code generators, at least those based on large language models, are inherently unreliable. So anyone using them to solve a given coding problem without a deep understanding of the problem and the proposed solution is shooting themself in the foot. AI-generated code can and will have errors, often subtle ones, that you need to be sufficiently experienced to catch.</p><p>On the other hand, language models struggle to deal with context. They often have a very limited context size compared to a reasonably large software project. But even if context size wasn&#8217;t a limitation, LLMs are known to arbitrarily ignore relevant parts of context and overfocus on irrelevant parts. They fail to grasp the big picture when things become complex enough.</p><p>In the end, this means that you can trust LLMs to generate small chunks of code that you can easily verify and understand, and that are relatively atomic and independent of the rest of the system.</p><p>They can definitely help at the code level&#8212;e.g., so you don&#8217;t need to remember or even search how that specific method or endpoint is invoked. They can help a little bit in the algorithm level, especially for applying relatively well-known strategies that you might have forgotten or not heard about. But they are almost useless at the system level.</p><p>The reason is that, the higher the level of abstraction, the more context matters. When you&#8217;re thinking about the whole architecture of your application, you need to understand how it all fits together, and even tiny details can be decisive for system-wide design choices. </p><p>So far, LLMs are incapable of such high-level reasoning. They can provide abstract, standard advice on software architecture, but the cannot reason that deeply about your specific application context and propose truly useful, novel, and accurate solutions for system-level design. And it seems we need a paradigm shift to overcome this limitation.</p><p>Thus, the better you are at coding&#8212;the better you are at thinking at the highest levels of abstraction&#8212;the more you can get out of an AI code generator. LLMs don&#8217;t make bad programmers better. In fact, they make them worse.</p><h2><strong>How should you learn to code</strong></h2><p>Finally, let me address the question of how. What follows is a very personal opinion&#8212;based on years of experience, but an opinion nonetheless.</p><p>There are two schools of thought about how to learn to code. The first one is the foundations-first school. In this school, you start by learning the syntax of a programming language and then learn how to write successively more complex programs in that language. This is the more traditional bottom-up approach, and it is often the design in college-level programming courses in engineering or computer science majors.</p><p>The upside with this approach is you get very strong foundations. After a full college year learning this way, you&#8217;re ready to tackle some reasonably complex coding problems. The downside is it takes a long time before you can do anything exciting that you can showcase. You spent most of your time solving abstract problems rather than building useful apps.</p><p>The second approach is championed by the applications-first school of thought. It is the complete opposite approach. You are thrown into a fully working application&#8212;often a rather simple one, but still far more complex than a single algorithm&#8212;and you get a high-level explanation of how the whole things work, as well as some deep dives into the important parts. This top-down approach is most common in online tutorials, bootcamps, and videos.</p><p>The upside is, of course, the pragmatism. You learn something immediately useful that you can replicate and maybe tweak for your own use case. And you get to see a lot of (hopefully) well-written code. However, if you only learn like this, you can end up with lots of disconnected ideas and no sense of the big picture. And more importantly, you don&#8217;t get a chance to develop the skill to think on your own and come up with your own ideas.</p><p>It probably won&#8217;t sound too bold or innovative to claim that I think the right way is a combination of these two. Of course it is! But the devil is in the details. </p><p>Good programming pedagogy is more than just doing algorithms one day and applications another. It&#8217;s not just an heterogenous mix. It requires a thoughful merge of these two approaches in a way that you are doing both things in unison: you&#8217;re thinking at the high level and coding at the low level simultaneously.</p><p>In my programming classes, I try to do precisely this: I create a fully working application&#8212;often a small demo, but something that has a concrete purpose and is designed for a real, human user. </p><p>We first spend some time thinking at a very high level about how such a system could be designed and discussing possible architectures. Then I crack open the code and show the parts that involve new content: maybe it&#8217;s a new instruction, a design pattern, or an algorithm. </p><p>At this point, I go back and forth between showing actual code and working on abstract ideas on the blackboard. This is time to think about why the code works, and to generalize these concrete ideas to more abstract patterns that can be learned.</p><p>Finally, I will challenge the students to make changes to the code. Some changes are superficial and only there for the coding level, so they get to practice with the new syntax. Other exercises tackle adding functionality or modifying methods to do extra stuff. These require the ability to think at a higher abstraction and understand what&#8217;s going on under the hood. </p><p>This is the best way I&#8217;ve found to get students to think about their code at several levels of abstraction simultaneously. If you&#8217;re interested in seeing this process in action, let me know in the comments. If there is enough interest, I may come back with some beginner-level tutorials using this approach.</p>]]></content:encoded></item><item><title><![CDATA[The Missing Introduction to Formal Language Theory]]></title><description><![CDATA[A new series on the foundations of Computer Science and the science behind Compilers]]></description><link>https://blog.apiad.net/p/the-missing-introduction-to-formal</link><guid isPermaLink="false">https://blog.apiad.net/p/the-missing-introduction-to-formal</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Tue, 16 Jul 2024 11:02:38 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="4272" height="2848" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:2848,&quot;width&quot;:4272,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;alphabet learning toy on gray apparel&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="alphabet learning toy on gray apparel" title="alphabet learning toy on gray apparel" srcset="https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1539632346654-dd4c3cffad8c?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw0fHxncmFtbWFyfGVufDB8fHx8MTcyMTA5MzEzNXww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="true">Ryan Wallace</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Next semester, I&#8217;ll teach the introductory course in Compilers again, after a couple years, in the CS major at the University of Havana. It was an excellent opportunity to dust my notes on formal languages, parsers, analyzers, code generators, etc. Going over the course material, I decided I needed to rewrite most lecture notes because my understanding of the fundamental issues in formal languages has dramatically changed since I last taught this course.</p><p>So, as I prepare for the upcoming course, I&#8217;ll be sharing with you some of the most intriguing and mindblowing ideas from one of the areas of Computer Science with some of the most profound results. We will begin with a very intuitive introduction to formal language theory and build our way up to understand how compilers, text editors, virtual machines, and all the associated components work.</p><p>Buckle up!</p><h2><strong>What is a (formal) language?</strong></h2><p>Intuitively, a language is just a collection of correct sentences. In natural languages (Spanish, English, etc,), each sentence is made up of words, which have some intrinsic meaning, and there are rules that describe which sequences of words are valid.</p><p>Some of these rules, which we often call &#8220;syntactic&#8221; are just about the structure of words and sentences, and not their meaning&#8211;like how nouns and adjectives must match in gender and number or how verbs connect to adverbs and other modifiers. Other rules, which we call &#8220;semantic&#8221;, deal with the valid meanings of collections of words&#8211;the reason why the sentence &#8220;the salad was happy&#8221; is perfectly valid syntactically but makes no sense. In linguistics, the set of rules that determine which sentences are valid is called a &#8220;grammar&#8221;.</p><p>In formal language theory, we want to make all these notions as precise as possible in mathematical terms. To achieve this, we will have to make some simplifications which will ultimately imply that natural languages fall outside the scope of what formal language theory can fully study. But these simplifications will enable us to define a very robust notion of language for which we can make pretty strong theoretical claims.</p><p>So let&#8217;s build this definition from the ground up, starting with our notion of words, or, formally, symbols:</p><blockquote><p><strong>Definition 1.1 (Symbol)</strong> A symbol is an atomic element with an intrinsic meaning.</p></blockquote><p>Examples of symbols in abstract languages might be single letters like <code>a</code>, <code>b</code> or <code>c</code>. In programming languages, a symbol might be a variable name, a number, or a keyword like <code>for</code> or <code>class</code>. The next step is to define sentences:</p><blockquote><p><strong>Definition 1.2 (Sentence)</strong> A sentence (alternatively called a <em>string</em>) is a finite sequence of symbols.</p></blockquote><p>An example of a sentence formed with the symbols <code>a</code> and <code>b</code> is <code>abba</code>. In a programming language like C# or Python, a sentence can be anything from a single expression to a full program.</p><p>One special string is the <em>empty string</em>, which has zero symbols and will often bite us in proofs. It is often denoted as &#120598;.</p><p>We are almost ready to define a language. But before, we need to define a &#8220;vocabulary&#8221;, which is just a collection of valid symbols.</p><blockquote><p><strong>Definition 1.3 (Vocabulary)</strong> A vocabulary &#119881; is a finite set of symbols.</p></blockquote><p>An example of a vocabulary is { &#119886;,&#119887;,&#119888; }, which contains three symbols. In a programming language like Python, a sensible vocabulary would be something like <code>{for,while,def,class,&#8230;}</code> containing all keywords, but also symbols like <code>+</code>, <code>.</code>, etc.</p><blockquote><p><strong>What about identifiers?</strong></p><p>If you think about our definition of vocabulary for a little bit, you&#8217;ll notice we defined it as <em>finite</em> set of symbols. At the same time, I&#8217;m claiming that things like variable and function names, and all identifiers in general, will end up being part of the vocabulary in programming languages. However, there are infinitely many valid identifiers, so&#8230; how does that work?</p><p>The solution to this problem is that we will actually deal with <em>two</em> different languages, on two different levels. We will define a first language for the <em>tokens</em>, which just determines what types of identifiers, numbers, etc., are valid. Then the actual programming language will be defined based on the <em>types</em> of tokens available. So, all numbers are the same token, all identifiers are another token, and so on.</p></blockquote><p>Given a concrete vocabulary, we can then define a language as a (possibly infinite) subset of all the sentences that can be formed with the symbols from that vocabulary.</p><blockquote><p><strong>Definition 1.4 (Language)</strong> Given a vocabulary &#119881;, a language &#119871; is a set of sentences with symbols taken from &#119881;.</p></blockquote><p>Let&#8217;s see some examples.</p><h2><strong>Examples of languages</strong></h2><p>To illustrate how rich languages can be, let&#8217;s define a simple vocabulary with just two symbols, &#119881;={ &#119886;,&#119887; }, and see how many interesting languages we can come up with.</p><p>The simplest possible language in any vocabulary is the singleton language whose only sentence is formed by a single symbol from the vocabulary. For example, &#119871;&#119886; = { &#119886; } or &#119871;&#119887; = { &#119887; }. This is, of course, rather useless, so let&#8217;s keep up.</p><p>We can also define what&#8217;s called a <em>finite</em> language, which is just a collection of a few (or perhaps many) specific strings. For example,</p><p>&#119871;1 = { &#119887;&#119886;&#119887;, &#119886;&#119887;&#119887;&#119886;, &#119886;&#119887;&#119886;&#119887;&#119886;, &#119887;&#119886;&#119887;&#119887;&#119886; }</p><blockquote><p>Since languages are sets, there is no intrinsic order to the sentences in a language. For visualization purposes, we will often sort sentences in a language in shortest-to-largest and then lexicographic order, assuming there is a natural order for the symbols. But this is just one arbitrary way of doing it.</p></blockquote><p>Now, we can enter the realm of <em>infinite</em> languages. Even when the vocabulary is finite, and each sentence is also a finite sequence of symbols, we can have infinitely many different sentences in a language. If you need to convince yourself of this claim, think about the language of natural numbers: every natural number is a finite sequence of, at most, 10 different digits, and yet, we have infinitely many natural numbers because we always take a number and add a digit at the end to make a new one.</p><p>Similarly, we can have infinite languages simply by concatenating symbols from the vocabulary <em>ad infinitum</em>. The most straightforward infinite language we can make from an arbitrary vocabulary &#119881; is called the <em>universe</em> language, and it&#8217;s just the collection of all possible strings one can form with symbols from &#119881;.</p><blockquote><p><strong>Definition 1.5 (Universe language)</strong> Given a vocabulary &#119881;, the universe language, denoted &#119881;&#8727; is the set of all possible strings that can be formed with symbols from &#119881;.</p></blockquote><p>An extensional representation of a finite portion of &#119881;&#8727; would be:</p><p>&#119881;&#8727; = { &#120598;, &#119886;, &#119887;, &#119886;&#119886;, &#119886;&#119887;, &#119887;&#119886;, &#119887;&#119887;, &#119886;&#119886;&#119886;, &#119886;&#119886;&#119887;, &#119886;&#119887;&#119886;, &#119886;&#119887;&#119887;, &#119887;&#119886;&#119886;, &#119887;&#119886;&#119887;, &#119887;&#119887;&#119886;, &#119887;&#119887;&#119887;, ... }</p><p>We can now easily see that an alternative definition of language could be any subset of the universe language of a given vocabulary &#119881;.</p><p>Now, let&#8217;s take it up a notch. We can come up with a gazillion languages just involving &#119886; and &#119887;, by concocting different relationships between the symbols. For this, we will need some way to describe the languages that don&#8217;t require listing all the elements&#8211;as they are infinitely many. We can do it with natural language, of course, but in the long run, it will pay to be slightly more formal when describing infinite languages.</p><p>For example, let &#119871;2 be the language of strings over the alphabet &#119881; = { &#119886;, &#119887; } with the exact same number of &#119886; and &#119887;.</p><p>&#119871;2 = { &#120598;, &#119886;&#119887;, &#119886;&#119886;&#119887;&#119887;, &#119886;&#119887;&#119886;&#119887;, &#119887;&#119886;&#119887;&#119886;, &#119887;&#119886;&#119886;&#119887;, &#119886;&#119887;&#119887;&#119886;, ... }</p><p>We can define it with a bit of math syntax sugar as follows:</p><p>&#119871;2 = { &#120596; &#8712; { &#119886;,&#119887; }&#8727; | #(&#119886;,&#120596;) = #(&#119887;,&#120596;) }</p><p>Let&#8217;s unpack this definition. We start by saying, &#120596; &#8712; { &#119886;,&#119887; }&#8727;, which literally parses as &#8220;strings &#120596; in the universe language of the vocabulary { &#119886;,&#119887; },&#8221; but is just standard jargon to say &#8220;string made out of &#119886; and &#119887;. Then we add the conditional part #(&#119886;,&#120596;) = #(&#119887;,&#120596;), which should be pretty straightforward: we are using the #(&lt;symbol&gt;,&lt;string&gt;) notation to denote the function that counts a given symbol in a string.</p><p>&#119871;2 is slightly more interesting than &#119881;&#8727; because it introduces the notion that <em>a formal language is equivalent to some computation</em>. This insight is the fundamental idea that links formal languages and computability theory, and we will formalize this idea in the next section. But first, let&#8217;s see other, even more interesting languages, to solidify this intuition that <em>languages equal computation</em>.</p><p>Let&#8217;s define &#119871;3 as the language of all strings in &#119881;&#8727; where the number of &#119886; is a prime factor of the number of &#119887;. Intuitively, working with this language&#8212;e.g., finding valid strings&#8211;will require us to solve prime factoring, as any question about &#119871; that has different answers for string in &#119871; than for strings not in &#119871; will necessarily go through what it means for a number to be a prime factor of another.</p><p>But it gets better. We can define the language of all strings made out of &#119886; and &#119887; such that, when interpreting &#119886; as 0 and &#119887; as 1, the resulting binary number has any property we want. We can thus codify all problems in number theory as problems in formal language theory.</p><p>And, as you can probably understand already, we can easily codify <em>any</em> mathematical problem, not just number theory. Ultimately, we can define a language as the set of strings that are valid input/ouput pairs for any specific problem we can come up with. Let&#8217;s make this intuition formal.</p><h2><strong>Recognizing a language</strong></h2><p>The central problem in formal language theory is called <em>the word problem</em>. Intuitively, it is about determining whether a given string is part of a language. Formally:</p><blockquote><p><strong>Definition 1.6 (The Word Problem)</strong> Given a language &#119871; on some vocabulary &#119881;, the word problem is defined as devising a procedure that, for any string &#120596; &#8712; &#119881;&#8727;, determines where &#120596; &#8712; &#119871;.</p></blockquote><p>Notice that we didn&#8217;t define the word problem simply as &#8220;given a language &#119871; and a string &#120596;, is &#120596; &#8712; &#119871;&#8221;. Why? Because we might be able to answer that question correctly <em>only</em> for some &#120596;, but not all. Instead, the word problem is coming up with an algorithm that answers for <em>all</em> possible strings &#120596;&#8212;technically, a <em>procedure</em>, which is not exactly the same.</p><p>The word problem is the most important question in formal language theory, and one of the central problems in computer science in general. So much so, that we actually classify languages (and by extension, all computer science problems) according to how easy or hard it is to solve their related word problem.</p><p>In the next few chapters, we will review different <em>classes</em> of languages that have certain common characteristics which make them, in a sense, equally complex. But first, let&#8217;s see what it would take to solve the word problem in our example languages.</p><p>Solving the word problem in any finite language is trivial. You only need to iterate through all of the strings in the language. The word problem becomes way more interesting when we have infinite languages. In these cases, we need to define a <em>recognizer mechanism</em>, that is, some sort of computational algorithm or procedure, to determine whether any particular string is part of the language.</p><p>For example, language &#119871;2 has a very simple solution to the word problem. The following Python program gets the job done:</p><pre><code><code>def l2(s):
    a,b = 0,0

    for c in s:
        if c == "a":
            a += 1
        else:
            b += 1
    return a == b</code></code></pre><p>A fundamental question in formal language theory is not only coming up with a solution to the word problem for a given language but, actually, coming up with the <em>simplest</em> solution&#8211;for a very specific definition of <em>simple</em>: how much do you need to remember. In other words: <em>what kind of algorithms can solve the word problem for what kind of languages?</em></p><p>For example, we can solve &#119871;2 with &#119874;(&#119899;) memory. That is, we need to remember something proportional to how many &#119886;&#8217;s and &#119887;&#8217;s are in the string. And we cannot solve it with anything less than that, as we will prove a couple chapters down the road.</p><p>Now, let&#8217;s turn to the opposite problem of generating strings from a given language and wonder what, if any, is the connection between these two.</p><h2><strong>Generating a language</strong></h2><p>Suppose you want to generate all strings from a language like &#119871;2. To make things simpler, let&#8217;s redefine it as &#119871;2&#8242;, the language of strings over {&#119886;,&#119887;} with the same number of &#119886;&#8217;s and &#119887;&#8217; but where all &#119886;&#8217;s come before all &#119887;&#8217;s. This means &#119886;&#119886;&#119887;&#119887; is a valid string in &#119871;, but not &#119886;&#119887;&#119887;&#119886;. This language is also called &#119886;&#119899;&#119887;&#119899;, that is, &#119899; symbols &#119886; followed by &#119899; symbols &#119887;.</p><p>Here is a simple Python method that generates infinitely many strings from &#119871;2&#8242;:</p><pre><code><code>def generate_l2():
    s = ""

    while True:
        yield s
        s = "a" + s + "b"</code></code></pre><p>Let&#8217;s unpack this. We start with the empty string &#120598;, defined in code as <code>s = ""</code>. Then, we enter an infinite cycle where we yield the current string, and then attach an &#119886; to the front and a &#119887; to the back. Take a moment to convince yourself that <em>any</em> string in the form &#119886;&#119899;&#119887;&#119899; is eventually generated by this method and, furthermore, <em>only</em> those strings are generated by the method.</p><p>This method is actually pretty neat because it not only generates (eventually) all of &#119886;^&#119899; &#119887;^&#119899;; it does so in increasing length order. It isn&#8217;t immediately obvious why this is such a good thing but here&#8217;s a bold claim: if you have a generating method for any language &#119871;, then you have a recognizing method too.</p><p>Wait, what!? Yep, you heard it right. And actually, it goes both ways. If you have a recognizing algorithm, you also have a generating one. Let&#8217;s make this our first theorem in formal language theory.</p><blockquote><p><strong>Theorem 1.1</strong> Let &#119871; be a formal language. There exists an algorithm &#119860; for generating all strings in &#119871; (in increasing length order) if and only if there also exists another algorithm &#119860;&#8242; for solving its word problem.</p></blockquote><p><em>Proof</em>. To prove this, let&#8217;s first understand what the theorem is saying. If we have an algorithm &#119860; that generates all strings in a language, we can also come up with another algorithm &#119860;&#8242; (presumably using &#119860;) that solves the word problem, and vice-versa.</p><p>To prove this type of theorems, the most usual approach is to assume you have &#119860; (or &#119860;&#8242;) as some kind of abstract, black-box algorithm, and try to construct the other. Let&#8217;s do it from generation to recognition first, as the other way around will be fairly easy once this is done.</p><p>&#8658; Suppose we have an algorithm &#119860; that generates all strings in &#119871;, and we are given an arbitrary string &#120596;. Let &#119899;=|&#120596;| be the length of &#120596;. We just need to run &#119860; until we either see &#120596;, in which case the answer is true (&#120596; &#8712; &#119871;) or until we see one string with length greater than &#119899;, in which case the answer is false (&#120596; &#8713; &#119871;). Since &#119860; generates strings in increasing length order, one of these must happen in a finite time for any &#120596;.</p><p>Now, let&#8217;s do it the other way around.</p><p>&#8656; Suppose we have an algorithm &#119860;&#8242; that solves the word problem from &#119871;. Then we do the following. Define &#119871;&#8727; as the universe language associated with &#119871;. We can very easily code a generating algorithm &#119860;&#8727; for &#119871;&#8727; in increasing length order, simply by permuting all symbols. Now, run &#119860;&#8727; and, for each string &#120596; generated, run &#119860;&#8242;(&#120596;). If the output is true, then yield &#120596;. Otherwise, skip it.</p><p>So there you have it. Generating (in increasing order) and recognizing are two faces of the same problem. Cool, right? But why does this matter? For starters, it gives us a tremendously powerful connection between two sub-branches of formal language theory that we will explore in the following chapters.</p><h2><strong>Moving on</strong></h2><p>We are just scratching the surface of what formal language theory can do, and we have already touched upon several areas of computer science.</p><p>We have defined a super general notion (language) that is ultimately as profound and powerful as the very notion of algorithm. We have identified a central problem in formal language theory (the word problem) that is as deep as the very question of what problems can be solved, <em>at all</em>, with a computer. We connected two fundamental problems in languages (recognizing and generating) and discovered they are but two sides of the same coin. And we left hanging the question of which languages can be solved with which types of algorithms, which is ultimately a question about complexity theory. Phew!</p><p>In the following few articles, we will continue exploring the world of formal languages. We will dive into the different classes of languages according to the complexity of their generating and recognizing algorithms. We will find many intriguing unsolvable problems that have deep connections with other areas in computer science, from the most practical to the most esoteric. When we finish this dive, we will have a much more solid understanding of what computers can ultimately do. And then, will turn to programming languages and apply all these ideas to solving the more practical problem of building a compiler.</p>]]></content:encoded></item><item><title><![CDATA[The Hardest Problem]]></title><description><![CDATA[The most important theoretical question in Computer Science asks about the existence of truly hard problems, that can't be solved efficiently regardless of how powerful is your tech.]]></description><link>https://blog.apiad.net/p/the-hardest-problem</link><guid isPermaLink="false">https://blog.apiad.net/p/the-hardest-problem</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Thu, 25 Jan 2024 11:00:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EOnL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>This article is part of a chapter on <em>Computational Complexity</em> in my upcoming book <strong>The Science of Computation.</strong> You can read all the details here:</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;0c92b386-d161-43c4-aba5-21634cf75288&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Book Teaser - The Science of Computation&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:6970039,&quot;name&quot;:&quot;Alejandro Piad Morffis&quot;,&quot;bio&quot;:&quot;Democratizing knowledge one post at a time. I talk about Computer Science, AI, Education, Philosophy, you know, mostly harmless stuff.\nBuilding a community of tech writers on Substack.\nAnd now also venturing into creative writing.&quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26aafc21-b149-4bf0-9382-e0ae3636e23a_640x640.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-01-20T20:18:45.138Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9b6d56c-6a04-479f-b76f-6bd5f9b121df_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.apiad.net/p/book-teaser-the-science-of-computation&quot;,&quot;section_name&quot;:&quot;&#129504; Computer Science&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:140745794,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:26,&quot;comment_count&quot;:20,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Mostly Harmless Ideas&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b621db-62a6-452b-b433-ccc0f5c4f0b3_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>And you can support the book by preordering your digital, DRM-free copy, with early and frequent updates, including all future editions.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://tppay.me/lrmc6hnj&quot;,&quot;text&quot;:&quot;Get early access - $10&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://tppay.me/lrmc6hnj"><span>Get early access - $10</span></a></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EOnL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EOnL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EOnL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EOnL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!EOnL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36dce3e3-42ae-45d8-9eac-b6eaab0de85e_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What is a Hard (Computational) Problem?</h2><p>There are many problems in computer science for which, even though they seem complicated at first, if we think hard enough, we can come up with clever algorithms that solve them pretty fast.</p><p>A very good example is the shortest path problem. This is basically the problem of finding the shortest path between two given points in any type of network. For example, you have a map with millions of places and intersections in your city, and you have to go between one point at one extreme of the map and another at the other end of the map.</p><p>Our cleverest algorithms, on average, have to analyze very few options to get you the shortest path. They are very fast. This is what powers your GPS route planner, for example.</p><p>However, other problems can sometimes be very similar to the first type, but no matter how hard we think, we cannot find any clever algorithm that always works.</p><p>The quintessential example of this is the traveling salesman problem. Consider a similar setting: you have a city and a bunch of places you need to visit in one tour. The question is, what is the best possible tour &#8212;the one that takes the least time or travels the least distance?</p><p>This problem seems very similar to the shortest path problem, but if you solve it by starting at one point and traveling to the closest next location iteratively, you can end up with a cycle that is several times worse than the best possible cycle.</p><p>There are approximate solutions that you can try in very constrained settings. Still, in the general case, no one has ever developed a clever algorithm that solves this problem any faster than checking all possible cycles.</p><p>And the thing is, all possible cycles are a huge number.</p><p>If you have 20 cities, all possible tours amount to something close to 20 factorial, which is &#8230; (checks numbers) &#8230; well, huge. Not only that, if you have a computer today that can solve the problem for, let's say, 20 cities in one second, then 22 cities will take nearly 8 minutes, 25 cities will take 73 days, and 30 cities will take you&#8230; 3 and a half million years!</p><p>This is an exponential solution, and they become bad really fast. But for many problems, like the traveling salesman, we have nothing better &#8212;that always works.</p><h2>Easy versus hard problems</h2><p>The first type of problem, like the shortest path, are called P-problems &#8212;technically, <em>polynomial time complexity</em>, but don&#8217;t worry about that. P basically means <strong>problems that are easy to solve.</strong></p><p>Now, for the second type of problem, we don't really know whether they are P-problems, but there is a subset of these that has an intriguing characteristic.</p><p>If I ask you to find me a cycle with, say, less than 100 km in total, that will be extremely hard. However, if I tell you, &#8220;here is a cycle that takes less than 100 km&#8221; you can easily verify it &#8212;just add up the length of each road.</p><p>These types of problems are called NP problems &#8212;technically, <em>non-deterministic polynomial time complexity</em>, but again, forget about that. NP basically means <strong>problems that are easy to verify.</strong></p><p>So, the most fundamental question in computer science, P versus NP, ultimately is the following:</p><div><hr></div><p><strong>P vs NP:</strong> <em>Are all problems that are easy to verify also easy to solve? Or are there problems that are intrinsically harder to solve than to verify?</em></p><div><hr></div><p>Intuitively, for many, it seems it must be the latter. Think about what it would mean to easily solve any problem that is also easy to verify. In a sense, it would be as if recognizing a masterpiece would be the same difficulty as creating the masterpiece in the first place. <em>Being a great critic would be the same as being a great artist.</em></p><p>This seems false, but intuitions in math and computer science are often wrong. We cannot use this kind of analogy to reach any sort of informed conclusion.</p><h2>Are there really hard problems?</h2><p>However, theoretical reasons hint at the possibility that P is indeed distinct from NP &#8212;that there are some truly, fundamentally difficult problems. The strongest one is the existence of so-called NP-complete problems. Problems, like the traveling salesman, so difficult to solve efficiently that if you could solve one of them, you would solve all the other NP problems at the same time.</p><p>When we say a problem is difficult, we mean that it is exponentially easier to verify a solution's correctness than it is to find the solution in the first place. This concept is crucial because, for most problems in computer science, such as sorting, searching for elements in an array, or solving equations, the effort required to solve the problem is roughly the same as the effort needed to verify the solution.</p><p>In technical terms, the advantage of verifying over solving is only polynomially easier, not exponentially. However, there are certain problems, like the traveling salesman problem, for which we have been unable to find a fast and efficient algorithm &#8211; only exponential ones. Nevertheless, these solutions are very easy to verify.</p><p>The heart of the P versus NP debate lies in whether these inherently difficult problems truly exist. Do problems exist that are far more challenging to solve than to verify? To answer this question fully, we would need to find a problem for which a polynomial time algorithm <em>cannot exist</em>.</p><p>P vs NP remains an unsolved question, and although it has seen a lot of progress, it appears to hint at the need for a new kind of mathematics. Our current mathematical methods lack the power to tackle these challenging meta-questions. However, we do have the next best thing &#8212;a wealth of empirical and theoretical evidence suggesting that, indeed, many of these problems may be unsolvable efficiently.</p><p>One of the simplest forms of empirical evidence is the vast number of problems for which we lack a polynomial time algorithm to solve them. However, this evidence is not very strong, as it could simply mean we aren&#8217;t smart enough to find those algorithms.</p><p>What we need is a more principled way of answering this question. When mathematicians are faced with an existential problem &#8212;in the sense of, does there exist an object with these properties, not in the sense of, you know, God is dead and all&#8212;what they do is try and find extreme cases that can represent the whole spectrum of objects to analyze.</p><p>In this case, we are dealing with finding problems that are difficult to solve. So it makes sense to ask, &#8220;What is the most difficult problem possible?&#8221; A problem so hard that if we crack it, we crack them all.</p><p>That&#8217;s the idea behind NP-completeness. Let&#8217;s focus on these super tricky problems &#8211; the toughest ones in this field. If there are problems so tough that solving just one of them would also solve all the others, that would seriously challenge the idea of P equals NP.</p><p>These really tough problems are called <strong>NP-complete</strong> problems, a concept defined by Stephen Cook in the 1970s. An NP-complete problem is basically a problem that is NP &#8212;that is, easy to verify&#8212;, and a solution to it in polynomial time would also give us a solution to any other problem in NP. So, in a way, these are the only problems we need to look at. If we solve one of these, we've proven P equals NP. And if we can't solve just one, we've proven P not equal to NP.</p><p>In short, we just need to focus on NP-complete problems. So, the main question then becomes: Are there problems so complex that they are essentially equivalent to all other problems?</p><p>Obviously, the hardest problems wouldn't revolve around everyday topics like finding paths in maps, sorting numbers, or solving equations. No, these problems should be much more abstract, so that they could encompass numerous other problems in their definition.</p><h2>One problem to rule them all</h2><p>Cook's idea was to create a problem centered around problem-solving itself. For instance, how about <em>simulating a computer</em>? That would be an incredibly abstract problem. To make it even more challenging, they could turn this computer simulation into a decision problem &#8212;keep in mind that NP problems are decision problems.</p><p>One way to define this problem is to imagine having an electronic circuit that computes some logical formula &#8212;this is all computers do at their core, as all computable arithmetic can be reduced to logic. Let's take the simplest logical circuit, a completely stateless one, and ask: Is there any input that will make this circuit output True? If so, we call the circuit <em>satisfiable</em>. Otherwise, it is deemed <em>unsatisfiable</em>.</p><p>Hence, given an arbitrary logical circuit, the task of determining if it's satisfiable or not is called circuit satisfiability, or <strong>Circuit-SAT</strong> for short.</p><p>In 1970, Stephen Cook proved that Circuit-SAT is as hard or harder than all other NP problems. If you can solve circuit satisfiability, you can solve any other problem in NP. This means you can solve the traveling salesman problem and the knapsack problem, but also sorting, searching, and basically any easily verifiable problem.</p><p>The proof of this idea is quite involved and complex, and not something I can fully explain in this post, so I'll save that for a more detailed discussion later. But basically, since logical circuits are extremely expressive and powerful, and can compute almost everything, any decision problem in computer science can be transformed into a logical circuit that simulates it solution. Cook&#8217;s proof actually involves constructing a circuit for an abstract NP problem, so it&#8217;s pretty technical. But the intuition is that these things are basically computers, so you&#8217;re just simulating any possible (decision) algorithm.</p><p>And voil&#225;! This proves the existence of at least one NP-complete problem, meaning there is one problem in NP that is as difficult as all problems in NP. Stephen Cook's work in 1971 essentially kick-started the entire field of computational complexity and defined the most important question in computer science: P versus NP.</p><p>The story, however, doesn't just end there. Circuit-SAT is great, but it is too much of an abstract problem. Just one year later, Richard Karp came along and demonstrated that 21 well-known and very concrete computer science problems were also NP-complete problems. These problems included the traveling salesman problem, the knapsack problem, various scheduling problems, and many graph coloring problems. In short, there turned out to be a whole bunch of problems that fell under this category, not just some abstract circuit simulation task.</p><p>These NP-complete problems aren't just theoretical issues, either. They are practical problems that we encounter regularly in logistics, optimization, and scheduling. After Karp proved his 21 original NP-complete problems, a wave of people started proving that nearly any problem in computer science involving combinatorics could be classified as NP-complete. As a result, there are now over 4,000 papers proving different NP-complete problems, ranging from determining the best move in Tetris to folding proteins.</p><p>This compelling evidence has led many computer scientists to believe that P != NP and that there are, indeed, problems that are fundamentally harder to solve, not just because we lack some understanding about them but because, by their very nature, they just cannot be solved efficiently.</p><h2>What does this mean?</h2><p>If it turns out that if P != NP, then there are some fundamental limits to how fast a computer can solve the majority of the most important problems in logistics, planning, simulation, etc. While we have many heuristics to solve either some cases perfectly or most cases approximately, all these problems may ultimately be unsolvable quickly.</p><p>Not even a superadvanced alien &#8212;or computer&#8212; could be exponentially faster than us. Thus, P vs NP might be our best weapon to stop a self-improving AGI from reaching superhuman capacity. Even gods can&#8217;t escape complexity theory.</p>]]></content:encoded></item><item><title><![CDATA[The Answer to All Questions]]></title><description><![CDATA[How the quest to answer all mathematical questions became the origin story for a new science.]]></description><link>https://blog.apiad.net/p/the-answer-to-all-questions</link><guid isPermaLink="false">https://blog.apiad.net/p/the-answer-to-all-questions</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Tue, 23 Jan 2024 17:02:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ISW-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>This article is part of my upcoming book <strong>The Science of Computation</strong>. You can check all the details about in the following post.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;83a5c4f5-9d9a-441c-b3a0-972150b7b4aa&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Book Teaser - The Science of Computation&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:6970039,&quot;name&quot;:&quot;Alejandro Piad Morffis&quot;,&quot;bio&quot;:&quot;Democratizing knowledge one post at a time. I talk about Computer Science, AI, Education, Philosophy, you know, mostly harmless stuff.\nBuilding a community of tech writers on Substack.\nAnd now also venturing into creative writing.&quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26aafc21-b149-4bf0-9382-e0ae3636e23a_640x640.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-01-20T20:18:45.138Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9b6d56c-6a04-479f-b76f-6bd5f9b121df_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.apiad.net/p/book-teaser-the-science-of-computation&quot;,&quot;section_name&quot;:&quot;&#129504; Computer Science&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:140745794,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:23,&quot;comment_count&quot;:20,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Mostly Harmless Ideas&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b621db-62a6-452b-b433-ccc0f5c4f0b3_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>You can also support the book by preordering your digital copy, getting early and frequent updates forever.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://tppay.me/lrmc6hnj&quot;,&quot;text&quot;:&quot;Preorder the book - $10&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://tppay.me/lrmc6hnj"><span>Preorder the book - $10</span></a></p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ISW-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ISW-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ISW-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ISW-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!ISW-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5e359351-84bb-4a72-afdf-aea30cf6f576_1024x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>What is an algorithm?</h2><p>In 1930, Alan Turing aimed to answer this question once and for all. At that time, computers as we know them today did not exist. However, the term "computer" was already used, referring to individuals, primarily women, who would perform computations.</p><p>These human computers, often instructed by physicists or mathematicians, were responsible for solving calculation problems. Once the problem was devised and all the reasoning and creativity were complete, these women would receive a piece of paper containing precise instructions for the computation.</p><p>Their sole duty was to follow these instructions meticulously. They would manipulate the input numbers, essentially performing the step-by-step process that modern computers carry out. By adhering to the instructions, they would ultimately arrive at the desired answer, even if they didn&#8217;t understand the underlying math or physics involved.</p><p>Now, Turing is a logician living in the early 20th century, and all logicians back then sought to address a crucial question that dominated mathematical research at the time. This question pondered the existence of limitations in mathematics.</p><p>Can purely computational, logical reasoning solve every problem? Are there certain questions that lie beyond the realm of what pure logic can answer? Such limitations were hinted at by logicians like G&#246;del, Russell, and Hilbert. However, Turing approached this problem from a different perspective: computational processing instead of pure logical demonstration.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>The Turing machine</h2><p>Turing's initial idea was to formalize and abstract the concept of a computer. He began by contemplating the nature of human computers. These human computers used a sheet of paper, often divided into cells, on which they wrote various symbols, including numbers. Turing realized the two-dimensional aspect of the paper is not essential. It could be simplified into a one-dimensional tape of cells on which symbols could be placed, deleted, or added at any given moment.</p><p>He then observed that these individuals followed instructions, focusing only on one specific instruction at any given time. There was no need to consider multiple instructions concurrently, as they were performed sequentially. Additionally, these instructions were finite and entirely predetermined for a given problem. Regardless of the length of the numbers being multiplied, for example, the instructions for multiplication are always the same.</p><p>From these observations, Turing conceived the idea of a computation machine, which he referred to as an "alpha-machine." He imagined this contraption as a state machine with fixed states connected by transitions. These transitions dictated actions based on the observed symbol and current state. For example, if the observed symbol was a 3 and the machine was in state 7, the instruction would specify changing the number to a 4 and transitioning to state 11.</p><p>Despite its simplicity, this concept encapsulates the fundamental principle of following instructions and utilizing an external memory, such as a tape, to store intermediate computations. By uniting these concepts, Turing laid the foundation for the conception of a computation machine &#8212;an abstract device capable of performing any type of computation.</p><p>The alpha-machine, now known as a <strong>Turing machine</strong>, is an abstract representation of a concrete algorithm. For instance, there can be a Turing machine designed explicitly for multiplying two numbers, a Turing machine for computing the derivative of a function, or even a Turing machine for translating from Spanish to English &#8212;as hard as that may seem. Each machine is a distinct algorithm akin to a specific program in Python or C++.</p><h2>The universal computer</h2><p>But Turing took a further step, introducing the concept of a <em>universal machine</em>. This is where the brilliance of his idea shines. Turing deduced that a Turing machine's description can be considered a form of data as well. We can take the states and transitions of a Turing machine and convert them into a long sequence of numbers, which can then be inputted into the tape of another Turing machine.</p><p>A universal Turing machine is designed to receive the description of any concrete Turing machine, along with its respective inputs, on its input tape. The universal Turing machine then simulates the precise actions of the specific Turing machine, replicating its behavior with the given input. Turing demonstrated this could be done, thus inventing the modern concept of a general-purpose computer.</p><p>And that&#8217;s how Alan Turing almost single-handedly invented the science of Computation &#8212;the theoretical field that explores the limits of computation and its practical implementation, now somewhat confusingly called &#8220;Computer Science.&#8221;</p><p>Remarkably, Turing machines, despite their abstract nature, serve as the practical blueprints for modern computers. In modern computers, a microprocessor contains a fixed set of instructions, while random access memory provides us with a virtually unbounded tape &#8212;though not technically infinite. Hence, the concept of a universal Turing machine aligns closely with a modern computer.</p><p>However, the story does not conclude here. You see, Turing had two fundamental questions in mind. First, he sought to determine the essence of an algorithm and how we can formalize the concept of computation. That&#8217;s the Turing Machine we just talked about. But, most importantly, he targeted the most crucial question regarding the limitations of mathematics and computation at the beginning of the 20th century.</p><h2>The quest to answer all questions</h2><p>During this time, mathematicians were engaged in a significant undertaking to resolve mathematics altogether. They aimed to address all the remaining critical open questions in the field. A prominent mathematician named David Hilbert compiled a list of 20 questions that he regarded as the most pivotal in mathematics. While many questions on the list pertained to specific areas of mathematics, at least two questions dealt with the fundamental limits of the discipline itself.</p><p>The first question asked to <strong>prove the completeness and consistency of mathematics</strong>. This meant establishing that <strong>all truths can be proven</strong> and that mathematics has <strong>no internal contradictions</strong>.</p><p>Initially, most mathematicians believed this to be true. However, Kurt G&#246;del's incompleteness theorem dealt a major blow to this belief. G&#246;del demonstrated that in any sufficiently strong mathematical system, there are always truths that cannot be proven within that system. To prove them, looking outside the system and introducing new axioms was necessary. This revelation undermined the mathematicians' quest to solve mathematics definitively.</p><p>Yet, one fundamental question remained, and it was also widely expected to be possible. This question examined whether, for all provable truths, there existed a completely mechanized procedure&#8212;an algorithm&#8212;that could find and deliver a proof within a finite amount of time. In simpler terms, it asked if <strong>computers could prove all provable theorems</strong>.</p><p>Surprisingly, the answer also turned out negative. There are problems in math and computer science that have clear answers&#8212;either true or false&#8212;yet cannot be solved algorithmically. These are known as <strong>undecidable problems</strong>: no algorithm can determine the truth or falsehood of these problems for all instances. And that is not a limitation of current technology. <em>It&#8217;s a fundamental limitation of the very notion of algorithm</em>.</p><h2>Undecidable problems</h2><p>There are two arguments to understand why computer science must have undecidable problems, using two of the most powerful in logic. The first is a diagonalization argument, very similar to Cantor&#8217;s original proof that the natural numbers are less than the real numbers. If you haven&#8217;t seen it, check out Jos&#233; J. Rodr&#237;guez&#8217;s <a href="https://jjdev.substack.com/p/when-the-shortest-path-is-the-diagonal">article on Cantor&#8217;s diagonalization</a>.</p><p>Essentially, any problem in computer science can be seen as a function that takes some input and produces some output. For example, the problem of adding two numbers can be represented as a function that takes two numbers and produces their sum. The question then becomes whether there are functions that cannot be solved by any theoretical machine or algorithm.</p><p>Now, here&#8217;s the kicker. The number of possible problems, or functions, is uncountable, while the number of Turing machines is countable. We can list them all by enumerating all binary strings and determining which ones correspond to well-formed Turing machines, in the same way in which we can enumerate all Python programs simply by enumerating all possible strings and running the Python interpreter on each one.</p><p>So, the number of problems corresponds to the cardinality of real numbers, while the number of programs corresponds to natural numbers. Consequently, there must be infinitely many mathematical problems that cannot be solved by an algorithm.</p><p>However, even if this is true, it is conceivable that we may not care about most of these unsolvable problems. They might be unusual or random functions that we do not find significant because for almost every problem we can think of, we can devise an algorithm to solve it. So, while there may be many solvable problems, their importance is subjective. Turing thus aimed to find one specific problem that was both important and unsolvable, and for that, he used the second most powerful tool in the logician&#8217;s arsenal.</p><p>Consider a Turing machine and a specific input. The Turing machine can either run indefinitely in a loop or eventually halt. If the machine halts after a certain number of steps when given that input, we can determine this after a finite amount of time. However, if the machine never halts, we might never be able to tell whether it will halt. It may always be that it has not yet stopped but will do so at some point in the future. Therefore, running a Turing machine that never halts on a given input cannot tell us that it will not halt.</p><p>Turing's question, then, is whether it is possible to determine, by examining only the code and input of a Turing machine, whether it will halt or not, <em>without actually running the machine</em>. This is known as the <strong>halting problem</strong>.</p><p>To establish the undecidability of the halting problem, Turing employs a negated self-reference, a powerful method pioneered by <a href="https://en.wikipedia.org/wiki/Barber_paradox">Bertrand Russell with his barber&#8217;s paradox</a>. The formal proof is somewhat involved, but the basic idea is pretty straightforward.</p><p>Following Russell's template, Turing presents a thought experiment assuming the existence of a &#8220;magical&#8221; Turing machine that can determine if any other Turing machine will halt without executing it. To show this is impossible, Turing pulls a Russell and creates a new Turing machine, using that magical halting machine, that halts when another arbitrary Turing machine doesn&#8217;t. By running the new machine on itself, Turing builds an explicit contradiction: <em>the machine must halt if and only if it doesn't halt</em>. This contradiction proves that the existence of the magical Turing machine for the halting problem is inherently self-contradictory and, therefore, impossible.</p><h2>What does this mean?</h2><p>What is the significance of the halting problem? For starters, with this result, Turing not only kickstarted computer science but also established its core limitations on day one: the existence of well-defined problems that cannot be solved by algorithms.</p><p>However, although the halting problem may seem abstract, it can be interpreted practically as a fundamental limitation of the kind of software we can build. When writing complex code, we often want a compiler, or linter, to determine if our code is error-free before executing it. For instance, a modern compiler for a statically typed programming language can detect and notify developers of potential type errors before runtime, like using undefined variables or calling unexisting methods.</p><p>Ideally, we would want a super smart compiler that could answer questions like: Will this program ever result in a null reference error? Is there a possibility of infinite recursion? Can this program cause an index-out-of-range exception? Unfortunately, these questions all trace back to the fundamental nature of the halting problem; they are, in general, undecidable.</p><p>Therefore, the undecidability of the halting problem implies that most of the problems we could expect compilers to solve are fundamentally unsolvable. Consequently, automated program verification &#8212;the process wherein programs are checked for intended functionality by other programs&#8212; is generally undoable. We must find heuristics and approximate solutions to particular cases because no single algorithm will work on all possible such problems.</p><p>This limitation extends to the realm of artificial intelligence as well. These findings tell us that there are fundamental tasks computers will never be able to accomplish. Maybe this means AGI is impossible, but maybe it doesn&#8217;t. Perhaps humans are also fundamentally limited in this same way. Many believe human brains are just very powerful computers, and if we are ultimately something beyond fancy Turing machines, <em>we might never be able to know</em>.</p><p>But that&#8217;s a story for another Tuesday.</p>]]></content:encoded></item><item><title><![CDATA[Supervised vs Reinforcement Learning]]></title><description><![CDATA[Some quick notes on when and how to use each of the two main Machine Learning paradigms.]]></description><link>https://blog.apiad.net/p/tech-tuesday-supervised-vs-reinforcement</link><guid isPermaLink="false">https://blog.apiad.net/p/tech-tuesday-supervised-vs-reinforcement</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Tue, 14 Nov 2023 11:01:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!u6O6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u6O6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u6O6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u6O6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1815772,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!u6O6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 424w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 848w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!u6O6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2ad3f30-a13a-4fb9-bf79-520f51496fd9_1024x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Supervised Learning</em> and <em>Reinforcement Learning</em> are the two main paradigms in machine learning, both involving learning from experience but in fundamentally different ways. </p><p>Supervised learning is comparable to imitation, where learning takes place through demonstrations of solving a given task. This type of learning is commonly used for tasks such as text classification, image classification, and audio transcription, as well as in training large language and diffusion models.</p><p>The basic concept of supervised learning is to utilize expert demonstrations of a task to train a machine learning system to map the input space, such as pixels in an image, to the desired output space, like a label indicating the presence or absence of lung cancer in annotated X-ray images.</p><p>In contrast, reinforcement learning involves learning through trial and error. It is often applied in robotics, self-driving cars, and any scenario requiring a sequence of actions where a plan is executed before assessing the outcome. This approach is utilized when direct access to expert demonstrations is unavailable, such as in tasks like walking or driving a car, where the method used by humans is not precisely understood or easily communicated to an AI. </p><p>Moreover, reinforcement learning is preferred when evaluating the results of a task is much more straightforward than actually solving it; for instance, it is easier to determine if a car crashed or not, than to drive the car, or to ascertain if a robot moved forward or fell over, than instructing the robot on movement.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>When deciding between supervised learning and reinforcement learning, the feasibility of direct demonstration by experts becomes a crucial factor. Supervised learning is more suitable when experts can directly demonstrate the task, providing a clear framework for learning. In contrast, reinforcement learning is better suited for tasks where the direct demonstration is difficult, but the evaluation is feasible.</p><p>This distinction can be best understood in terms of <em>direct and inverse problems</em>, common in computer science. The <strong>direct problem</strong> is the task you want to solve, from input to output, while the <strong>inverse problem</strong> involves going from the output to the input. </p><p>For example, in image classification, the direct problem is categorizing images: that is, given an input image, provide an output text that describes it &#8211;either a simple label or a full natural language description. The inverse problem is thus image generation based on a given label or description.</p><p>Since the direct problem is easier &#8212;or at least not harder&#8212; to solve than the inverse, in this case, it is more feasible to find experts to annotate images and provide accurate labels, making supervised learning the preferable approach.</p><p>Consider the example of self-driven cars, where the direct problem involves navigating complex scenarios, while the inverse problem is simulating those scenarios to determine if the car reaches its destination. While both problems are complex, the inverse problem is relatively easier &#8212;we just have to build a realistic video game. In this case, even though making an accurate car simulator is no small feat, it is still way more manageable than collecting hundreds of thousands of hours of experts driving cars in many different locations.</p><p>Thus, when the direct and inverse problems exhibit similar complexity, supervised learning is typically preferred. However, if the inverse problem is significantly easier than the direct problem, reinforcement learning becomes a more viable option.</p><p>If it&#8217;s unclear beforehand which problem is easier, you can consider two heuristics. The first heuristic involves examining the availability of data on expert performance that you can access: books, papers, tutorials, video demonstrations, etc. If such data is readily available, supervised learning may be a viable option. Otherwise, you may need to hire experts for annotation or build a simulation.</p><p>The second heuristic involves observing how humans learn to perform similar tasks. Is it through formal education or intensive practice? The former &#8212;e.g., medical diagnosis&#8212;indicates that humans learn via imitation, suggesting that supervised learning is feasible. In the other case, humans learn via trial and error, like in sports, thus suggesting that reinforcement learning is more suitable.</p><p>Now, while this heuristic provides valuable insight into the problem, it may not be universally applicable. For instance, traditional board games like chess have historically been tackled using supervised learning, but the most recent models for games&#8212;such as AlphaGo and AlphaStar&#8212; have shown that reinforcement learning is even more effective.</p><p>If you can do either, then consider the advantages of each method. With sufficient data, supervised learning can yield faster initial results, as learning from clear examples of good behavior is more efficient. However, this approach often reaches a limit at the human expert level. On the other hand, reinforcement learning has no upper limit and can achieve superhuman performance if the simulation is sufficiently accurate. Therefore, a hybrid solution that starts with supervised learning and transitions to reinforcement learning may effectively push performance to the highest level possible.</p><p><em>Reinforcement Learning with Human Feedback</em> (RLHF) is an interesting middle ground between Supervised Learning and pure Reinforcement Learning. In RLHF, like in pure RL, an agent interacts with an environment and learns from trial and error. But unlike pure reinforcement, where the simulation determines the feedback for each action, here we let human experts evaluate the agent's performance and learn from their feedback. Thus, we learn the best feedback function in supervised mode and then learn the optimal behavior in reinforcement mode.</p><p>In any case, there are no hard rules when deciding whether to use supervision or reinforcement, only some heuristics. As in all disciplines, when faced with a novel problem, scientists and engineers must either draw from experience in similar problems or try different things and see what works. And this is just supervised and reinforcement learning at display. It&#8217;s pretty meta, isn&#8217;t it?</p>]]></content:encoded></item><item><title><![CDATA[A Universal Language for Reasoning]]></title><description><![CDATA[Leibniz's dream and the search for a universal language of thoughts]]></description><link>https://blog.apiad.net/p/origins-cs-1</link><guid isPermaLink="false">https://blog.apiad.net/p/origins-cs-1</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Thu, 09 Nov 2023 11:56:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Probably the greatest idea in all of Computer Science is the definition of &#8220;computation&#8221;. This foundational step enabled everything else in our field to fall into place. It started with a dream of one of the greatest mathematicians, philosophers, and scientists of all time and very likely the first computer scientist, Gottfried Leibniz, and concluded with the seminal work of Alan Turing, the most important mathematician of the 20th century.</em></p><p><em>This is <strong>Origins of CS</strong>, a series exploring the foundational ideas in Computer Science, the long story of humanity&#8217;s search for the ultimate machine, a machine to solve all problems; the kind of machine we today call a &#8220;computer&#8221;.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qBsj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qBsj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qBsj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:349623,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qBsj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!qBsj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcc4b4656-d584-482e-9240-4821dbd0ba89_1024x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Humanity&#8217;s ingenuity extends far back into the foggy ages of the agricultural revolution and probably even farther back. Since the dawn of homo sapiens, our species has always been interested in predicting the future. Tracking the seasons, planning crops, estimating an enemy&#8217;s forces, and building cities, all of these tasks require significantly complex computations that often need to be reasonably accurate to be helpful.</p><p>For this reason, ancient civilizations developed all sorts of computational devices to keep track of complex phenomena such as planetary motion. The most famous case is the <a href="https://en.wikipedia.org/wiki/Antikythera_mechanism">Antikythera mechanism</a>, a two-thousand-and-some-old device used to predict eclipses regarded as the first known analog computer. The <a href="https://en.wikipedia.org/wiki/Zairja">zairja</a> is another example from around 1000 CE, a device used to make astrological predictions, much like a simplified language model (only half-jokingly here).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UNuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UNuf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 424w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 848w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UNuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg" width="390" height="347.8378378378378" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:924,&quot;width&quot;:1036,&quot;resizeWidth&quot;:390,&quot;bytes&quot;:211953,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UNuf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 424w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 848w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!UNuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F822f83fa-da76-4dfe-836e-0e7d37832f62_1036x924.jpeg 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The Antikythera mechanism. <a href="https://commons.wikimedia.org/w/index.php?curid=469865">Taken from Wikipedia, CC BY 2.5</a></figcaption></figure></div><p>This is a trend we see developing well into the Middle Ages and the Renaissance: constructing machines that perform some sort of calculation, whose final realization &#8212;before the arrival of electrical computers&#8212; is <a href="https://en.wikipedia.org/wiki/Charles_Babbage">Charles Babbage&#8217;s differential and analytical engines</a>. But this is a story for another day.</p><p>In this post, I want to begin exploring the ideas that lead to the notion of &#8220;algorithm&#8221; or computational process, regardless of their physical realization. This is the first entry of <em>Origin of CS</em>, the story of the origins of Computer Science.</p><blockquote><p><em>Note: A previous version of this post was read by my very first few subscribers. I&#8217;m updating and resharing this post today with you, as part of a new series I&#8217;m starting.</em></p></blockquote><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p>The modern history of Computer Science can be said to begin with <a href="https://en.wikipedia.org/wiki/Gottfried_Wilhelm_Leibniz">Gottfried Leibniz</a>, one of the most famous mathematicians of all time. Leibniz worked on so many fronts that it is hard to overestimate his impact. He made major contributions to math, philosophy, laws, history, ethics, and politics. He is probably best known for co-inventing, or co-discovering, calculus along with Isaac Newton. Most of our modern calculus notation, including the integral and differential symbols, is heavily inspired by Leibniz&#8217;s original notation. Leibniz is widely regarded as the last universal genius, but in this article, I want to focus on his larger dream about what mathematics could be.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YMrw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YMrw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YMrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg" width="405" height="500.1715265866209" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:583,&quot;resizeWidth&quot;:405,&quot;bytes&quot;:62879,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YMrw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 424w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 848w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!YMrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbbc6a12-55d0-481c-b020-5685bf1af423_583x720.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Leibniz&#8217;s portrait, by Christoph Bernhard Francke - <a href="https://commons.wikimedia.org/w/index.php?curid=53159699">Herzog Anton Ulrich-Museum, online, Public Domain</a>.</figcaption></figure></div><p>Leibniz was amazed by how much notation could simplify a complex mathematical problem. Take a look at the following example:</p><blockquote><p><em>&#8220;Bob and Alice are brothers. Bob is 5 years older than Alice. Two years ago, his age was twice as hers. How old are they?&#8221;</em></p></blockquote><p>Before Algebra was invented, the only way to work through this problem was to think hard, or maybe try a few lucky guesses. But with algebraic notation, you just write some equations like the following and then apply some straightforward rules to obtain an answer.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{eqnarray}\nb &amp; = &amp; a+5 \\\\\nb-2 &amp; = &amp; 2(a-2) \\\\\n&amp;  &amp;\\\\\na+5-2 &amp; = &amp; 2a-4 \\\\\na+3 &amp; = &amp; 2a - 4 \\\\\n3+4 &amp; = &amp; 2a-a \\\\\n&amp;  &amp;\\\\\na &amp; = &amp; 7 \\\\\nb &amp; = &amp; 12 \\\\\n\\end{eqnarray}&quot;,&quot;id&quot;:&quot;ZLIHRWQEMI&quot;}" data-component-name="LatexBlockToDOM"></div><p>Any high-school math student can solve this kind of problem today, and most don&#8217;t really have the slightest idea of what they&#8217;re doing. They just apply the rules, and voila, the answer comes out. The point is not about this problem in particular but about the fact that using the right notation &#8212;algebraic notation, in this case&#8212; and applying a set of prescribed rules &#8212;an algorithm&#8212; you can just plug in some data, and the math seems to work by itself, pretty much guaranteeing a correct answer.</p><p>In cases like this, <em>you</em> are the computer, following a set of instructions devised by some smart &#8220;programmers&#8221; that require no creativity or intelligence, just to painstakingly apply every step correctly.</p><p>Leibniz saw this and thought: &#8220;<em>What if we can devise a language, like algebra or calculus, but instead of manipulating known and unknown magnitudes, it takes known and unknown truth statements in general?</em>&#8221; </p><p>In his dream, you would write equations relating known truths with some statements you don&#8217;t know, and by the pure syntactic manipulation of symbols, you could arrive at the truth of those statements.</p><p>Leibniz called it <em><a href="https://en.wikipedia.org/wiki/Characteristica_universalis">Characteristica Universalis</a>. </em>He imagined it to be a universal language for expressing human knowledge, independently of any particular language or cultural constraint, and applicable to all areas of human thought. If this language existed, it would be just a matter of building a large physical device &#8212;like a giant windmill, he might have imagined&#8212; to be able to cram into it all of the current human knowledge, let it run, and it would output new theorems about math, philosophy, laws, ethics, etc. In short, Leibniz was asking for an <em>algebra of thoughts</em>, which we today call <strong>logic</strong>. </p><p>He wasn&#8217;t the first to consider the possibility of automating reasoning, though. Having a language that can produce true statements reliably is a major trend in Western philosophy, starting with Aristotle's syllogisms and continuing through the works of Descartes, Newton, Kant, and basically every single rationalist that has ever lived. Around four centuries earlier, philosopher <a href="https://en.wikipedia.org/wiki/Ramon_Llull">Ramon Llull</a> had a similar but narrower idea which he dubbed the <em>Ars Magna</em>, a logical system devised to prove statements about, among other things, God and the Creation.</p><p>However, Leibniz is the first to go as far as to consider that all human thought could be systematized in a mathematical language and, even further, to dare dream about building a machine that could apply a set of rules and derive new knowledge automatically. For this reason, he is widely regarded as the first computer scientist in an age where Computer Science wasn&#8217;t even an idea.</p><p>Leibniz's dream echoes some of the most fundamental ideas in modern Computer Science. He imagined, for example, that prime numbers could play a major part in formalizing thought, an idea that is eerily prescient of <a href="https://en.wikipedia.org/wiki/G%C3%B6del_numbering">G&#246;del&#8217;s numbering</a>. But what I find most resonant with modern Computer Science is the <em>equivalence between a formal language and a computational device</em>, which ultimately becomes the central notion of computability theory, a topic we will explore in future issues.</p><p>Unfortunately, most of Leibniz's work in this regard remained unpublished until the beginning of the 20th century, when most of the developments in logic needed to fulfill his dream were well on their way, pioneered by logicians like Gottlob Frege, Georg Cantor, Bertrand Russell, and ending in the final realization of a computational model by Alan Turing.</p><p>But that&#8217;s a story for another day :)</p>]]></content:encoded></item><item><title><![CDATA[Thinking like a Computer Scientist - Rigor and Formality]]></title><description><![CDATA[Analyzing the role of two key qualities of sound, logical thinking, and how they can help you improve your reasoning and argumentation skills.]]></description><link>https://blog.apiad.net/p/rigor-and-formality</link><guid isPermaLink="false">https://blog.apiad.net/p/rigor-and-formality</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Mon, 16 Oct 2023 11:52:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!teK5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!teK5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!teK5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 424w, https://substackcdn.com/image/fetch/$s_!teK5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 848w, https://substackcdn.com/image/fetch/$s_!teK5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 1272w, https://substackcdn.com/image/fetch/$s_!teK5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!teK5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png" width="1024" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1114042,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!teK5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 424w, https://substackcdn.com/image/fetch/$s_!teK5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 848w, https://substackcdn.com/image/fetch/$s_!teK5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 1272w, https://substackcdn.com/image/fetch/$s_!teK5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0681b602-f414-4eba-8930-f974e5e1ec4c_1024x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>A rabbit coming out of a hat.</em> &#8212; generated with SDXL via <a href="https://monsterapi.ai">MonsterAPI</a>.</figcaption></figure></div><p>As a teacher, I always need to emphasize the importance of core foundational computer science courses such as logic and discrete math to my students because sometimes they can lose track of the forest by focusing too much on the trees. These courses do not necessarily provide <em>concrete</em> skills or knowledge that can be applied directly. Instead, they help develop <em>fundamental</em> reasoning skills that are applicable everywhere.</p><p>For example, in discrete math, students will make proofs about theorems in number theory, combinatorics, computability, and graph theory. While some of these concepts are useful for computer scientists, the most important takeaway from these courses is the ability to think rigorously and formally. The theorems can be found in books, but the critical thinking skills developed in these courses are invaluable.</p><p>In my discrete math course, I tell my students there are two critical components to producing a solid mathematical demonstration: rigor and formality. These two are orthogonal. You can achieve rigor without being overly formal or formality without being rigorous. When it comes to mathematical thinking, these two elements interplay to make your reasoning and argumentation clear and sound.</p><p>In this article, we will break down what it means to be rigorous and what it means to be formal. Then, we will examine the relationship between rigor and formality and argue why rigor is typically more crucial than formality.</p><p>This is the first of a series of articles I want to write on critical reasoning skills for undergrad students. I will mostly write from the context of math and computer science, but I think these ideas are valuable everywhere a sound and logical argumentation is desirable.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h2>Rigor and formality</h2><p>Rigor and formality are two orthogonal qualities of clear argumentation. In short, formality refers to <em>form</em>, while rigor refers to <em>content</em> &#8212;alternatively, we can say formality refers to <em>syntax</em> while rigor refers to <em>semantics</em>. Good arguments, like mathematical proofs, are both rigorous and formal. That is, they are solid in both content and form.</p><p>First, let&#8217;s examine these two qualities, and then we&#8217;ll analyze how they interplay in critical reasoning.</p><h3>What is formality</h3><p>In general, formality involves strictly adhering to specific rules of etiquette. In mathematics and computer science, this etiquette is a formal language. This means that what you say is highly restricted, as you must use specific symbols and follow specific syntactic rules with precise meaning.</p><p>In mathematical terms, formality means sticking to mathematical notation. Mathematical notation involves using symbols to refer to different objects. For instance, if you want to talk about a number with a particular property, you give it a name like &#8220;x&#8221; or &#8220;y&#8221;. You might also use subscripts to refer to a set of numbers with the same property or use more complicated symbols with specific quirks in their allowed syntax.</p><p>By naming things consistently, you ensure that anyone following your proof understands precisely what you're discussing. This is better than saying, "Remember I told you there were three numbers; just take the second one and multiply it by the third" because it removes ambiguity.</p><p>The benefit of formality is that anyone will understand precisely what you are saying based on the syntax. The advantage of clear syntax is that it removes all friction from decoding what you're talking about. Anyone reading your proof will know exactly which objects you're referring to and what you're trying to say about them. This means that understanding the proof becomes a matter of understanding the semantics and logical validity of the proof rather than figuring out what you're talking about.</p><h3>What is rigor</h3><p>In general, rigor refers to the thoroughness and coherence of an argumentation. When reasoning is rigorous, each step follows logically from the previous step without any hidden assumptions or presuppositions. There are no non-trivial premises that one must agree on before following the reasoning.</p><p>In mathematical terms, rigor comes from strictly following well-known rules of reasoning without taking unjustified leaps. This involves clearly stating your premises and backing up every claim with the necessary support. All claims must be either a logical consequence of the premises or previously stated claims. This builds a chain of reasoning such that any conclusion can be traced back to the premises via logical reasoning.</p><p>Thus, if the reasoning is rigorous, it should be self-evident to anyone following it that if you accept the premises, you must also accept the conclusion. However, this does not necessarily mean you will agree with the premises. The concept of rigor provides validity to your premise, argument, and conclusion. It ensures that your thinking is correct and that the truth you have uncovered is true based on your premises.</p><p>The advantage of being rigorous is that it ensures your conclusions are sound &#8212;that is, they are necessarily true, given the premises. Rigor also helps focus the discussion on the core of the argument rather than irrelevant elements like who&#8217;s doing the argument. If someone argues against a rigorous argumentation, they must either reject the premises or show a flawed logical step somewhere. This helps to uncover red-herring and other fallacies people use to divert a discussion in their favor without providing solid arguments.</p><h3>The interplay between rigor and formality</h3><p><em>It is possible to have rigorous argumentation without formality.</em></p><p>Academic papers often present rigorous argumentation that is not overly formal. Philosophical essays, for example, demonstrate this when the writer is clear, logical, and precise. They define their topic and make careful, logical connections between premises. They justify each statement they make, even if it initially seems trivial. This is most evident in modern analytical philosophy, which attempts to be logical and rational but is prevalent in all good philosophical arguments.</p><p>Similarly, natural science research can also demonstrate rigorous yet not overly formal argumentation. In experimental sciences such as physics, chemistry, and biology, well-thought-out experiments are conducted with detailed setups. The hypotheses and goals of the experiment are clearly stated, and data is analyzed to draw conclusions. Scientists rigorously distill their conclusions from the data to ensure the experiments support them. While scientific papers may use semi-formal notation, such as algebra or statistics, and graphs and tables, they are not as formal as a fully-fledged mathematical proof. </p><p><em>The opposite is also true; you can be exceedingly formal but lack all rigor.</em> </p><p>Being overly formal in your writing or argumentation does not necessarily guarantee accuracy. For instance, you will have incorrect conclusions if you work on a math or geometry proof and rely on an unexisting theorem without following proper logical steps. Even if you use precise terminology and notation, your argumentation may still be flawed and fail to follow previous steps logically.</p><p>Formal but not rigorous argumentations can appear by accident or by malicious manipulation. A typical example is college students, who learn to grasp the syntax of proofs but struggle with their semantics, thus producing invalid proofs that still appear mathematically sound because all the notation is flawless.</p><p>On the other hand, sometimes, people trying to convince you of something untrue will use various tactics, including an appeal to formality, to make their argument seem more credible. By using many definitions, symbols, and formulas, they may try to trick you into believing their reasoning is correct. </p><p>This may be accidental, but it can also happen intentionally when researchers try to make their assumptions and conclusions seem more reliable by embedding them in a formal framework.</p><p>In political discussions, clever people often use rhetorical language to try and persuade you of their &#8220;truth&#8221;. They might use formal and complex language, mention scientific or technical concepts, and quote well-known personalities to lend themselves credibility. However, much of what they say is meaningless or plain wrong. Quoting some dead philosopher doesn&#8217;t make your argument necessarily any more accurate, but many fall prey to this illusion.</p><p>Finally, this practice is also pervasive in pseudosciences, which try to appear scientific but do not follow a genuinely scientific approach. They use formal language, define terms, and create complex taxonomies, ontologies, and theories but lack rigor.</p><p>By now, it should be clear that while having rigor without formality can sometimes make understanding difficult, having formality without rigor is a complete disaster. Therefore, it is crucial to <strong>prioritize rigor over formality</strong>, not only in mathematical thinking but also in reasoning in general.</p><div class="pullquote"><p>First, make it rigorous, and then make it formal.</p></div><h2>How to think rigorously and formally</h2><p>The final question I want to address is how to approach writing, thinking, or communicating rigorously and formally. When teaching my students, I advise them to approach this kind of writing &#8212;e.g., for mathematical proofs&#8212; in three layers.</p><p>The first layer is <strong>intuition</strong>: understanding why something is true. By building intuition and seeing connections between different parts of the issue, you can become convinced of the truth of your argument. For example, a mathematical proof uncovers hidden relationships that may initially seem complicated. However, with a solid intuition, these relations become self-evident. The intuition layer is where you reach a deep understanding of why something is true.</p><p>Next, you add <strong>rigor</strong> to your intuition. This involves making your ideas as detailed and coherent as possible, checking every step, and making explicit all intermediate steps that logically follow from previous claims. You should avoid relying on non-trivial assumptions that aren't explicitly stated. </p><p>By adding rigor, you may realize that your initial intuition was incorrect. If you're wrong, you should be able to identify where the issue lies. For instance, you may discover that you cannot justify a particular jump between claims. In such a case, you should try to find an opposite proof that shows whether your initial idea was mistaken.</p><p>However, if you succeed in making your proof as rigorous as possible, it should be convincing even though it is written in natural language without any formality. Nonetheless, the argument may still be confusing, as it's written in your language and not in a universal language understood by all professionals in your discipline. There may also be some ambiguity in how something is interpreted. For example, if you say &#8220;the last number&#8221;, it may be unclear who precisely the last number refers to. </p><p>Finally, you can rewrite your argument using a stricter, more <strong>formal</strong> notation. In math, this involves defining every concept you mention, giving them a name, and using variables for referring to objects in your proof. When referring to something previously mentioned, use the name given to it instead of repeating its definition. For example, instead of saying, &#8220;That number we just saw&#8221;, say, &#8220;Let <em>n</em> be the first number that has property <em>p,&#8221;</em> and use <em>n</em> in subsequent references.</p><p>Formality will also help you identify flaws in your argumentation. If you find it difficult to formalize, your proof sketch is poorly laid out. The formality layer is like a programming language that ensures your proof is sound. If it parses and compiles correctly, it is likely to be true &#8212;provided you did the rigorous work first.</p><h3>An illustrative example</h3><p>Let me finish with a simple example to illustrate the process of going from intuitive to rigorous to formal argumentation. I will examine the classical proof for the infinite nature of prime numbers. This is one of the fundamental theorems in arithmetic and has a beautiful proof often used to introduce students to the art of mathematical proof-making.</p><p>Here&#8217;s an intuitive idea of why this must be false.</p><blockquote><p>All numbers are either prime or divisible by some smaller prime(s). If there were finitely many primes, we could build a large number that is not divisible by any of them, multiplying them all together and adding one. But this larger number has to either be prime or have prime factors we didn&#8217;t consider.</p></blockquote><p>Now, let&#8217;s make that rigorous.</p><blockquote><p>Let&#8217;s start by assuming the opposite of what we want to prove. Let&#8217;s say there are only finitely many prime numbers. We could list them all out, like this: the first prime number, the second prime number, the third prime number, and so on, until we reach the last prime number. </p><p>Now, let&#8217;s create a new number. To do this, we multiply all the prime numbers in our list together and then add one to the result. This gives us a big number that is not on our list of primes. </p><p>This new number is not divisible by any of the primes in our list. When we divide it by any of our primes, there is always a remainder of one. This is because, by definition, this big number is equal to something multiplied by that prime number plus one.</p><p>But every number has some prime divisors, or it is prime. So, either this new number is a prime not in our list, or it has prime factors that were not in our original list. </p><p>In either case, we have a contradiction. We assumed that we had a complete list of all the primes, but now we&#8217;ve found a prime that wasn&#8217;t on our list. This contradiction means that our original assumption (that there are only finitely many primes) must be false. Therefore, there must be infinitely many prime numbers. </p></blockquote><p>The previous proof is rigorous because each claim follows from the previous claims and premises, and there are no hidden assumptions. There is no flawed reasoning, i.e., the logic of the argumentation is sound. However, it is still hard to follow because the lack of formal notation forces us to use phrases like &#8220;that number&#8221; which may be ambiguous, especially when the argumentation is sufficiently long.</p><p>Finally, let&#8217;s make it formal:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dBI4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dBI4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 424w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 848w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 1272w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dBI4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png" width="852" height="384" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:384,&quot;width&quot;:852,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69157,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dBI4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 424w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 848w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 1272w, https://substackcdn.com/image/fetch/$s_!dBI4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F33561c32-4a16-4b46-87e1-f8f533c44272_852x384.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><em>Due to Substack&#8217;s lack of inline math support, we have to put an image here.</em></figcaption></figure></div><p>It doesn&#8217;t matter if you precisely understand every step in this formal demonstration. We can turn a rigorous proof into a formal one simply by carefully naming things and using the proper syntax and notation. However, if the proof is not rigorous, to begin with, no amount of formalization will make it better.</p><p>Incidentally, note how, in this formal demonstration, we didn&#8217;t need to explicitly differentiate whether <em>m</em> is prime itself or a composite number with a prime divisor not in <em>P</em>. This is just a tiny detail to highlight that, upon formalization, a proof may become more straightforward &#8212;if you understand the notation, of course.</p><h2>Conclusions</h2><p>Writing is one of the best ways to think clearly. Instead of relying on your faulty memory, if you explicitly lay out your ideas on paper &#8212;or electrons, for that matter&#8212; you can more easily see if your ideas make sense and discover connections you previously didn&#8217;t think of.</p><p>However, not all writing is the same. Depending on your purpose, your writing can be more or less detailed and more or less structured. Sometimes, completely unstructured, free-flow writing is precisely what you need to get something out of your mind. However, if your purpose is to be correct and convincing, you&#8217;re better off striving to be rigorous and formal.</p><p>Formality and rigor are two cornerstones of sound, logically-backed reasoning. By learning to structure and organize your arguments such that they are both rigorous and as formal as necessary &#8212;but not overly formal as to make them difficult to understand&#8212; you can become a better writer and, ultimately, a better thinker.</p>]]></content:encoded></item><item><title><![CDATA[Foundations of ML #2 - Learning Paradigms]]></title><description><![CDATA[A framework to characterize and understand the different flavors of machine learning, from supervised, unsupervised and reinforcement, to the many hybrid variants.]]></description><link>https://blog.apiad.net/p/foundations-of-ml-2</link><guid isPermaLink="false">https://blog.apiad.net/p/foundations-of-ml-2</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Wed, 09 Aug 2023 11:00:54 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This is the second entry in a series on the <strong><a href="https://apiad.substack.com/t/foundations-of-ml">Foundations of Machine Learning</a></strong>. In the previous post, we talked about how Machine Learning works. It&#8217;s about having some source of experience E for solving a given task T, which allows us to find a program P that is (hopefully) optimal for some metric M. We argued that this paradigm represents a fundamental shift in how we build software because we turn the problem from coming up with a solution ourselves to searching for a suitable solution among sensible strategies &#8212;from open-ended to closed-ended.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="6107" height="4071" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4071,&quot;width&quot;:6107,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;brown duck on green grass during daytime&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="brown duck on green grass during daytime" title="brown duck on green grass during daytime" srcset="https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1620573084768-d8274700eea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHwyN3x8ZHVja2xpbmdzfGVufDB8fHx8MTY5MDg4NTEzM3ww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@tchompalov">Vlad Tchompalov</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>If you haven&#8217;t read the previous post or need a recap, check it out before moving on.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;74225d80-9658-4e3d-8216-f76743a07275&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Foundations of ML #1 - What is Machine Learning?&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:6970039,&quot;name&quot;:&quot;Alejandro Piad Morffis&quot;,&quot;bio&quot;:&quot;Democratizing knowledge one post at a time. I talk about Computer Science, AI, Education, Philosophy, you know, mostly harmless stuff.&quot;,&quot;photo_url&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26aafc21-b149-4bf0-9382-e0ae3636e23a_640x640.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null},{&quot;id&quot;:127360029,&quot;name&quot;:&quot;Daniel Vald&#233;s&quot;,&quot;bio&quot;:&quot;Mathematician, computer scientist, and educator at Havana University. I love machine learning, computational math, statistics, ... you get it. Passionate about philosophy and the power of conveying knowledge. Just documenting this intellectual trek!&quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb7ba4c6-ba0e-4ca0-a88d-c6caa7bd6481_640x640.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-07-26T16:14:45.483Z&quot;,&quot;cover_image&quot;:&quot;https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://apiad.substack.com/p/foundations-of-ml-1&quot;,&quot;section_name&quot;:&quot;Intro to CS&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:135327122,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:20,&quot;comment_count&quot;:4,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Mostly Harmless Ideas&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5fc9bad-532d-49e5-8458-a9282304168f_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>In this post, we will start discussing the different subtypes of machine learning paradigms we can find. If you are familiar with ML, you&#8217;ve probably heard terms like <em>supervised</em>, <em>unsupervised</em>, or <em>reinforcement learning</em>. This post will explain exactly what these terms mean. But before, we will develop a unified framework to think about machine learning paradigms encompassing these three and many other ML flavors.</p><p>All machine learning is learning from <em>experience</em>, as we&#8217;ve seen. To learn, you need to be able to measure how well you&#8217;re doing; that is, you need <em>feedback</em>. Thus, to understand where learning paradigms differ, we will look at the different types of experiences that we can access and the types of feedback we can rely on. Once those intuitions are in place, we will meet the three fundamental learning strategies: learning by imitation, pattern recognition, and trial and error.</p><p>Combining different flavors of experiences, feedback, and learning strategies, we can define all machine learning paradigms, from supervised, unsupervised, and reinforcement learning, to self-supervised learning, active learning, and other hybrid modes. We will finish this post by describing the most popular paradigms.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.apiad.net/subscribe?"><span>Subscribe now</span></a></p><p>Buckle up!</p><h2>Deconstructing learning paradigms</h2><p>Machine learning paradigms vary in at least three essential factors: the nature of the experience available, the quality of the feedback, and the strategy used to learn. The fundamental dimension to characterize a source of experience is whether it is <em>static </em>or<em> dynamic. </em>Regarding feedback, the fundamental dimension to characterize it is <em>implicit vs. explicit</em>.</p><h3>Nature of experience</h3><p><em><strong>Static experience</strong></em> is, for example, a collection of books. You can learn from books by reading other people&#8217;s experiences. But you are limited beforehand to the amount of quality of experience that was put in those books. If you read from a very good author &#8212;or teacher&#8212; they will have chosen the precise experience you need to learn effectively. But you cannot control what they teach you &#8212;you cannot ask questions to a book&#8212;you can only choose beforehand what source to consult.</p><p>In contrast, <em><strong>dynamic experience</strong></em> is what you get by practicing, e.g., playing a sport or a musical instrument. Dynamic here means that the amount and quality of the experience you get depends at least partially on how you act. You try to kick the ball a certain way or put your fingers on a particular key on the piano, and you&#8217;ll get different feedback. Thus you can, to some extent, control the experience you get by asking different questions.</p><p>In short, static experience is predefined before we access it. We can perhaps decide in which order to consume it, but we cannot fundamentally change the experience we get. Dynamic experience depends upon our behavior &#8212;by acting in specific ways, we can shape the experience we get. We must understand, though, that this isn&#8217;t a binary distinction but a spectrum going from pure static to more dynamic.</p><p>In computational terms, the most common type of static experience is a <em>dataset</em>, i.e., a collection of data &#8212;e.g., images, text, audio, video, etc.&#8212; that someone put together. The most common type of dynamic experience is a <em>simulation</em>, i.e., a computer program with specific rules where one or more virtual agents (also computer programs) can interact.</p><h3>Quality of feedback</h3><p><em><strong>Explicit feedback </strong></em>is directly related to your learning target. For example, if you&#8217;re learning to play an instrument, the most explicit feedback would be, &#8220;<em>This is how you must move your fingers.&#8221;</em> In the chess example, very explicit feedback would be knowing the optimal move on a given board.</p><p>However, you often can only get <em><strong>implicit feedback</strong>.</em>, in various degrees.<em> </em>For example, take learning to play soccer. You kick the ball and observe its trajectory. If it doesn&#8217;t land where it should, you know you did something wrong but not exactly what. This feedback is only indirectly related to your learning target &#8212;e.g., the exact force and torque you need to hit the ball. This is also a spectrum rather than a binary distinction.</p><p>The more explicit the feedback, the easier it is to learn. However, providing explicit feedback often entails knowing how to solve the problem and effectively communicating that knowledge. Your music teacher not only knows how to play the guitar; they can also tell you precisely what you&#8217;re doing right or wrong. But if you&#8217;re learning to ride a bicycle, no amount of explanation will do. We don&#8217;t even know <em>exactly</em> how we do it, let alone how to explain it to someone else.</p><p>Lower-quality feedback also can occur in at least two critical ways: it becomes delayed and sparse. <em><strong>Delayed feedback</strong></em> is, for example, when you lose a game of chess. You only know that your strategy was flawed at the end, but you can&#8217;t tell exactly which moves were good or bad. <em><strong>Sparse feedback</strong> </em>is the more general issue of getting a feedback signal only for a subset of your decisions. Both these phenomena make learning increasingly harder.</p><h3>Learning strategies</h3><p>Three main learning strategies underpin all ML algorithms so far in use. These are the actual mechanisms by which a model is trained based on experience. While the lines between ML paradigms are somewhat blurry, they all use one or a combination of learning by <em><strong>imitation</strong></em>, <em><strong>trial-and-error</strong></em>, and <em><strong>pattern recognition</strong></em><strong>.</strong></p><p><em><strong>Learning by imitation </strong></em>is the most common and intuitive technique. It&#8217;s one of the main ways children learn in humans and most mammal species. You observe some behavior and try to reproduce it. Learning by imitation is the most efficient type but requires clear and direct feedback.</p><p><em><strong>Learning by trial and error </strong></em>is what you do when feedback is indirect and sparse. If you cannot know precisely what you should do, but at least you can know if your actions are better or worse, you can try different things and see which is better. Learning by trial and error can take much longer than imitation, especially if the space of possible decisions is huge. It requires dynamic feedback since you need to be able to decide which actions to try out.</p><p><em><strong>Learning by pattern recognition </strong></em>is the most indirect type of learning, useful when the feedback is the worst quality: implicit and static. It&#8217;s the learning that happens when, for example, you read a non-didactic book or watch a movie. There is no explicit learning objective, but you can still find some interesting lessons to keep. It involves finding patterns in the available experience that explain or summarize at least part of it.</p><p>These three learning strategies are not disjoint. They can be used in different combinations depending on the available experience.</p><div><hr></div><h2>Machine learning paradigms</h2><p>Now that all intuitions are in place, we can briefly enumerate the most important machine learning paradigms. We will start with the three basics: supervised, unsupervised, and reinforcement learning. Each occurs when one specific combination of experience, feedback, and learning strategies intersect. Then we will see three prominent hybrid paradigms that blur the frontiers between these three.</p><h3>Supervised Learning</h3><p>The most common, simple, and helpful learning paradigm is <em><strong>Supervised Learning</strong></em><strong>. </strong>It involves static experience with the most explicit kind of feedback, and it&#8217;s based on imitation learning.</p><p>In this paradigm, the experience is a static collection of input/output pairs, and the task is defined as finding a function that produces the correct output for any given input. Supervised learning is thus a problem if <em>prediction: </em>given an input, predict the corresponding output<em>. </em>The underlying assumption is that there is some correlation (or, in general, a computable relation) between the structure of an input and its corresponding output and that it is possible to infer that function or mapping from a sufficiently large number of examples. </p><p>The output can have any structure, from highly complex to simple atomic values. When the output has a  complex structure (e.g., a sequence or an arbitrary object with properties), we call it a <em><strong>structured prediction</strong></em> problem. When the output is a simple atomic value, we have two special sub-problems: <em>classification</em> and <em>regression</em><strong>.</strong> </p><p><em><strong>Classification</strong></em> is when the output is a category out of a finite set. Examples are detecting the object(s) that appear in an image, assigning a sentiment to a text, or predicting if a person has a disease &#8212;like cancer&#8212; given the results of a set of medical exams.</p><p>Classification problems can be <em>binary</em> &#8212;e.g., predict cancer or no cancer&#8212; or <em>multi-class</em> &#8212;e.g., predict the sentiment of a text. Multi-class problems can also be <em>multi-label </em>when the output can be zero, one, or more than one category for a single input&#8212;for example, predicting the topics of a piece of text.</p><p><em><strong>Regression</strong></em> is when the output is a continuous value, bounded or not. A typical example is property valuation, e..g, predicting the price of a house or car, or any other object given its characteristics. </p><h3>Unsupervised Learning</h3><p>The main alternative to supervised learning is, you guessed it, <em><strong>Unsupervised Learning</strong>. </em>The main difference is that we don&#8217;t have access to the &#8220;right outputs.&#8221; Instead, we have a large static dataset and want to find hidden patterns. Thus, feedback is highly indirect and often implicitly defined, and we resort to pattern recognition as the primary learning strategy.</p><p>The underlying assumption is that there is some regularity in the structure of those elements that help explain their characteristics with a restricted amount of information, hopefully significantly less than just enumerating all elements. In this approach, the programmer leaves a deeper footprint since the kind of regularities that can be found are a bias that needs to be provided.</p><p>Two common sub-problems in unsupervised learning are associated with where we want to find that structure: <em>clustering </em>and <em>dimensionality reduction</em>.</p><p><em><strong>Clustering</strong></em> is when we care about the relationship between different elements. This task is often framed as finding the (generally predefined number of) groups to which each element belongs. Examples include grouping users given their behavior on social media or grouping products given their characteristics in an online store.</p><p>Clustering requires defining an implicit similarity relation between elements, such that elements in the same group are, on average, more similar to each other than to the elements in other groups. Thus, the performance of clustering is often highly subjective, depending on how we define that similarity. Also, other assumptions and biases determine the &#8220;geometry &#8220;of the clusters. Long story short, every clustering algorithm is the best one under its own assumptions.</p><p><em><strong>Dimensionality Reduction</strong></em> is when we care about the internal structure internal of each element. The task is often framed as finding a compact representation of the elements capturing their most salient characteristics. In other words,  they keep the most information possible, where each model defines what <em>information</em> means in its context.</p><p>This task is often used as a preprocessing step before supervised learning because it helps reduce each element&#8217;s detail to its most essential traits. For this reason, there aren&#8217;t easily recognizable examples of dimensionality reduction in user-facing applications.</p><h3>Reinforcement Learning</h3><p>The third fundamental ML paradigm is <em><strong>Reinforcement Learning</strong></em>. The main difference with the previous two is that instead of a static collection of data, here we have a dynamic simulation where an agent can act, and the task is formulation as learning to make decisions that lead to desirable outcomes. It is based on learning by trial and error.</p><p>This paradigm is useful when we have to learn to perform a sequence of actions, and there is no obvious way to define the &#8220;correct&#8221; sequence beforehand other than trial and error, such as training artificial players for video games, robots in real life, or self-driven cars. The feedback is formulated as a <em><strong>payoff</strong></em> obtained after the agent performs one or a sequence of actions, and the objective is often to maximize the lifetime expected accumulated payoff.</p><p>Feedback in reinforcement earning can be delayed and sparse, meaning our agents must learn to perform long sequences of actions that lead to a single outcome. Thus, a major problem is <em><strong>credit assignment</strong></em>, i.e., deciding which actions in that sequence should account for what part of the ultimate payoff. Also, the same action can lead to different payoffs at different moments.</p><p>For example, in self-driving cars, you get an immediate positive payoff every second the car hasn&#8217;t crashed, a mid-term negative payoff for every driving law broken, a longer-term payoff if you reach the desired location, etc. The same action &#8212;e.g., moving the driving wheel a degree to the left&#8212; can be involved in all those payoffs. This level of indirection between action and feedback makes RL far more complex than supervised and unsupervised in general.</p><p>Reinforcement learning approaches can be divided into <em><strong>model-based </strong></em>and <em><strong>model-free</strong></em>. In the former, the agent learns a model of the environment. Thus it can predict the payoff that specific sequences of actions will provide and optimize accordingly. In the latter, the agent learns to predict the &#8220;correct&#8221; action without explicitly computing its expected payoff.</p><h3>Semi-supervised Learning</h3><p>This<em><strong> </strong></em>is a straightforward mixture of supervised and unsupervised learning, in which we have explicit output samples for just a few of the inputs plus many additional inputs where we can try, at least, to learn some structure.</p><p><em><strong>Semi-supervised Learning</strong></em> is useful in almost any supervised learning problem when we hit the point where getting additional <em>labeled</em> data &#8212;with both inputs and outputs&#8212; is too expensive, but it is easy to get lots of <em>unlabeled</em> data &#8212;just with inputs.</p><p>Its advantage is that if the input data is relatively uniform, the underlying structure useful for predicting outputs &#8212;the one you would need to learn in supervised mode&#8212; will closely match the structure you can discover unsupervised. Thus, you can learn a lot from the data alone, in an unsupervised way, and then add a small supervised tweak to the mix.</p><p>One form of this paradigm, <em><strong>unsupervised pertaining</strong></em>, was very popular in the early days of deep learning. Training an entire neural network end-to-end on lots of data was computationally unfeasible back then. The alternative was to pre-train intermediate layers of the network in unsupervised mode before training the final layer(s) in supervised mode.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> As newer, simpler architectures have been invented and computational power has increased, this approach has fallen out of favor, but it is still helpful in low-resource scenarios.</p><h3>Self-supervised Learning</h3><p>This paradigm is also in-between supervised and unsupervised learning but has a different setup. In <em><strong>Self-supervised Learning</strong></em>, we want to predict an explicit output, but that output is simultaneously part of the input. So in a sense, the output is also defined implicitly. Thus, this paradigm is simultaneously supervised and unsupervised instead of simply concatenating supervised and unsupervised problems.</p><p>A straightforward example is language models, like BERT and GPT, where the objective is (hugely oversimplifying) to predict the n-th word in a sentence from the surrounding words, a problem for which we have lots of data &#8212;e.g., all the text on the Internet.</p><p>Self-supervised learning is a highly effective approach in machine learning as it blurs the boundaries between supervised and unsupervised learning. Its reliance on explicit feedback makes it as efficient in learning as the supervised paradigm. However, what sets it apart is that it doesn&#8217;t require human labeling, making it a scalable and much more efficient option, just like in unsupervised learning.</p><h3>Active Learning</h3><p>The final paradigm we&#8217;ll analyze in this post is <em><strong>Active Learning</strong>, </em>which is also a hybrid of sorts, but this time mixing traits of supervised and reinforcement learning. In this setup, we have a vast, potentially infinite amount of unlabelled data as experience and access to an &#8220;oracle&#8221; &#8212;e.g., a human expert&#8212; to whom we can ask for the correct output for any specific input.</p><p>The key to active learning lies in pinpointing the most effective examples to request from humans. This approach can optimize our knowledge acquisition while minimizing human effort.</p><p>Active learning can reduce the cost of data collection enormously compared to traditional supervised learning while keeping the same model performance. As in supervised learning, we have explicit, high-quality feedback. But unlike supervised learning, we only pay the cost of getting that feedback &#8212;which often entails having a human annotator&#8212; for the set of learning most informative examples.</p><p>In active learning, we train the model and annotate the data simultaneously in a tight loop. As the model improves, it will tell us exactly which data point is most cost-effective to annotate next. Once finished, we obtain the trained model and the final, optimally annotated dataset.</p><div><hr></div><h2>Final remarks </h2><p>Not every task comes with a paradigm label, though. In the realm of machine learning, these paradigms not only operate independently. Often the more powerful methods live on the frontiers.</p><p>In this final section, we aim to give you a flavor of how these interactions look. We will present the ideas behind some illustrative examples without technical details.</p><p><em><strong>Autoencoders</strong></em> are an excellent example of how supervised and unsupervised learning encapsulate a dual role. At their core, they are unsupervised models designed to uncover hidden patterns in unlabeled data. Yet, this process can be enhanced using supervised learning techniques. We feed an encoder with the input data, and it returns a more compact representation as output. Then a decoder receives this output as an input, producing something in the same format as the original output. The composition of both the encoder and the decoder is what we call the <em>autoencoder</em>. Given a similarity metric, the task is to learn to reconstruct the input.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>This architecture resembles <em>self-supervised learning</em> &#8212;in the sense that the output is part of the input, i.e., it&#8217;s the input itself. We are not quite interested in the output itself, though. We are instead interested in the intermediate, more compact representation.</p><p><em><strong>Embeddings</strong></em> are another interesting example, a general method for representing discrete variables, like words, items, or users, by transforming them into continuous vectors within a lower-dimensional space. These embeddings encapsulate some semantic or contextual attributes of the variables. Their application extends to natural language processing, computer vision, recommender systems, and beyond.</p><p>In the unsupervised scenario, they can detect similarity, association, or hierarchy. Facing supervised problems, they offer substantial utility due to their capacity to handle nominal data that do not have explicit characteristics. For instance, when dealing with word embeddings, words that share analogous meanings or fall within the same category can be positioned closer together within the vector space.</p><h2>Conclusions</h2><p>In conclusion, the various subtypes of Machine Learning paradigms are shaped by the interplay between different types of experiences and feedback and the learning strategies employed.</p><p>Static and dynamic experiences refer to the nature of the data used for training, with static experiences involving fixed datasets and dynamic experiences involving continuous data streams or simulations. Explicit and implicit feedback refers to the type of guidance provided to the machine learning algorithm, with explicit feedback being more direct while implicit feedback is more subtle and indirect.</p><p>Considering these three key concepts, we can better understand the differences and similarities between machine learning paradigms. For example, supervised learning involves explicit feedback and static experiences, while reinforcement learning involves implicit feedback and dynamic experiences. On the other hand, unsupervised learning relies on implicit feedback and can be either static or more dynamic, depending on the nature of the data.</p><p>Ultimately, by understanding these key concepts, we can gain a deeper understanding of the underlying principles that govern Machine Learning and make informed decisions about which approach to use for a given problem. In the next entry in this series, we will discuss another fundamental distinction between Machine Learning approaches: generative vs discriminative modeling.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Don&#8217;t worry about the details of this process. We will talk about neural networks and their training paradigms in future posts.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>This concept is analogous to a musician trying to replicate several pieces by ear. The musician&#8217;s brain builds a representation of the music that&#8217;s simpler than the music itself. Eventually, most musicians agreed on a unified language for this representation &#8212;but that&#8217;s totally out of scope for this article ;)</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Foundations of ML #1 - What is Machine Learning?]]></title><description><![CDATA[The first issue on the Foundations of Machine Learning series, exploring the most basic concepts in the field.]]></description><link>https://blog.apiad.net/p/foundations-of-ml-1</link><guid isPermaLink="false">https://blog.apiad.net/p/foundations-of-ml-1</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Wed, 26 Jul 2023 16:14:45 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Machine Learning is a fundamental paradigm shift in how we build computer programs. It opens the door to solving problems that are unsolvable by traditional means. In short, Machine Learning answers the question, &#8220;<em>What if we don't know how to write a program to solve this problem?</em>&#8221; The solution is simple and elegant: we write another program to<em> find the best program </em>to solve this problem.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="5360" height="3248" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:3248,&quot;width&quot;:5360,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;white ceramic figurine on black table&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="white ceramic figurine on black table" title="white ceramic figurine on black table" srcset="https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1586165368502-1bad197a6461?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wzMDAzMzh8MHwxfHNlYXJjaHw1fHxjaGVzc3xlbnwwfHx8fDE2OTAwODE2Mjh8MA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@hpzworkz">Hassan Pasha</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>This is the first article in a series about the <strong><a href="https://apiad.substack.com/t/foundations-of-ml">Foundations of Machine Learning</a></strong>. This series will cover basic concepts, the main learning and modeling paradigms, and evaluating and comparing models. From there, future series will explore specific models and algorithms in greater detail.</p><blockquote><p><em>This series is written in collaboration with </em><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Daniel Vald&#233;s&quot;,&quot;id&quot;:127360029,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb7ba4c6-ba0e-4ca0-a88d-c6caa7bd6481_640x640.jpeg&quot;,&quot;uuid&quot;:&quot;b15f6746-48b5-47b2-8eb9-484de56406be&quot;}" data-component-name="MentionToDOM"></span><em>, a mathematician turned PhD student of mine in Machine Learning, which is like, the best combo I could get.</em></p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.apiad.net/subscribe?"><span>Subscribe now</span></a></p><p>This first series is aimed at general readers interested in knowing more about this field so they can understand the conversation around Machine Learning going on in the media. For this reason, this series has no code or math whatsoever, just intuitions &#8212;ok, maybe I&#8217;ll throw in a few equations for performative reasons, but nothing strictly necessary.</p><p>However, if you are interested in Machine Learning from a software development or a scientific perspective, this series is still for you. In that case, I believe this series will be helpful as an intuitive foundation from which you can move on to more technical courses. I&#8217;ll give you some pointers if you want to dig deeper.</p><p>In this first article, I want to answer the broadest questions: <em>What is Machine Learning, and when is it useful? </em>To get there, first, we&#8217;ll look at <em>why</em> we want Machine Learning in the first place by comparing it with the traditional approach in computer science on a motivating example: making a world-class chess player. Then we&#8217;ll define exactly <em>what</em> &#8220;the Machine Learning approach&#8221; means. And finally, we&#8217;ll briefly discuss <em>how</em> we can actually do Machine Learning.</p><p>Buckle up!</p><h2>Building a chess player the traditional way</h2><p>To understand why machine learning is important, we must first discuss when the traditional approach to solving computer problems fails miserably. For that, let&#8217;s briefly talk about what it would take to solve what was for a long time considered the quintessential problem in artificial intelligence: making a chess player that can beat the world champion.</p><p>If you know how to code, you can already begin to imagine how hard it must be to write a program that plays chess at the highest level. Let me illustrate the type of approach that a typical software developer would follow.</p><p>First, you must understand the rules of chess: how pieces move and what it means to win and lose a game. This only guarantees that you can write a program that never makes invalid moves. But that&#8217;s far from good enough. To beat even the weakest opponents, you&#8217;ll need to code some <em>strategies</em>, i.e., rules for the program to not simply pick one random valid move but a move with a reasonable chance of leading to victory.</p><p>To find strategies, you can either read strategy books, consult an expert, or maybe think really hard and develop good ideas yourself. Either way, you will end up coding a program that does a combination of the following:</p><ul><li><p>a bunch of hard-coded rules for well-known openings and endings; and</p></li><li><p>some heuristic to play the mid-game, most likely based on weighting different pieces according to their position on the board.</p></li></ul><p>And this approach works, but it has many disadvantages, some obvious and some less. The first obvious limitation is that building and maintaining such a complex program is increasingly difficult, especially as new strategies are discovered. That kind of long collection of rules is a headache for most software engineers. Second, slightly less obvious, we never know if we're playing the optimal strategy. Chess is an unsolved game, meaning no definitive strategy is known to work against all opponents.</p><p>But the most important limitation of the traditional programming approach is that <em>the</em> <em>program can only be as good as the programmer</em>. There is nuance here, of course. Maybe the knowledge comes from domain experts and not precisely the programmers. But in any case, one or more humans&#8217; knowledge about the problem must be explicitly coded in software.</p><p>This means that while the computer is definitely an immense boost in scale and speed &#8212;we can solve bigger problems much faster&#8212;, fundamentally, traditional software cannot take us beyond human capabilities. The best chess-playing program using this approach might exceed the best human by sheer brute force, but it <em>cannot fundamentally play better chess</em>.</p><p>To see why this is a huge issue, consider what happens when we face a problem no one knows how to solve explicitly. At least two kinds of problems in this category are amenable to machine learning.</p><p>First, we have <em>unstructured </em>problems that we can solve, but we can&#8217;t explain how. These are problems where we hint there must be a set of rules that work &#8212;because we humans solve them intuitively&#8212; but we cannot explicitly list those rules in a way that a computer can understand &#8212;i.e., in a computer program. Examples include perception (e.g., recognizing objects in images) and language. </p><p>And second, we have <em>inverse </em>problems that we can solve easily in one direction but not in reverse. These are problems for which we know how to go from cause to effect, but it is not easy to determine, given an effect, what was the cause. Most physics falls in this category, e.g., given a specific design for an engine, we can simulate in a computer&#8212;and thus calculate&#8212; its performance under certain conditions. The inverse problem would be, given some constraints of design and a desired performance, to find the optimal engine design.</p><p>Our motivating example, playing chess, falls somewhere in between. On the one hand, some humans are extremely good at it. Still, while there are books and books of strategies, no one can explain exactly what the world champions do, not even themselves &#8212;otherwise, everyone could be a world champion. On the other hand, given a set of moves in chess, we can simulate it and compute who is the winner, but it is not easy to determine the right set of moves that, from a given board, leads to someone winning.</p><p>The bottom line is: we know there must be an optimal strategy (or set of strategies) for playing chess at the world-champion level &#8212;because there are people who do it&#8212;, but neither we nor anyone else can think through and come up with a computationally convenient description of that strategy.</p><h2>The way of Machine Learning</h2><p>Now here is the Machine Learning approach to this problem.</p><p>Instead of attempting to code the optimal strategy directly, let&#8217;s turn the problem on its side and ask, &#8220;<em>If I had a huge number of possible strategies, could I identity the best one?</em>&#8221; </p><p>This change in framing is a big leap because it makes the problem at least tractable. We are no longer trying to invent or discover something; we are &#8220;merely&#8221; searching for something inside a well-defined set of things. The problem shifted from being open-ended (come up with a winning strategy) to closed-ended (select the best strategy among all of these)! </p><p>However, this leap hinges on two crucial assumptions. </p><p>First, we must be able to enumerate all possible chess-playing strategies or, at least, to define a sufficiently large set of strategies such that the best one among them has a fair chance of being the one we&#8217;re looking for. We call this set the <em><strong>hypothesis space</strong>,</em> and defining it will prove non-trivial. In fact, having a good hypothesis space will be the fundamental obstacle in getting machine learning to work.</p><p>For this motivating example, we can easily define a sensible hypothesis space that will illustrate the thinking one needs to develop in machine learning. Let&#8217;s say we assign a score to each pair of piece-position, for example, <em>white-pawn-at-B7</em>, <em>black-rook-at-D3</em>, etc. We compute the &#8220;value&#8221; of any concrete board configuration by adding all scores associated with the pieces in their corresponding locations.</p><p>Assuming we have <em>the right scores</em>, our chess-playing program is pretty simple:</p><ul><li><p>Generate every possible board from the current one, applying all valid moves.</p></li><li><p>For each board, compute its value using those &#8212;still unknown&#8212; scores.</p></li><li><p>Return the move that leads to the highest valued board.</p></li></ul><p>We assume that those scores somehow capture the notion of &#8220;<em>this is a good board to be in</em>.&#8221; A board with a higher value is better because I&#8217;m more likely to win by playing a move that takes me to that configuration. This is, of course, a huge oversimplification because we are <em>ignoring all interactions</em> between pieces. A rook may be more or less valuable in a given position because it challenges an enemy piece or protects one of your own.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>However, even with this simplification, we already have six different types of pieces (rooks, knights, bishops, pawns, queens, and kings) times 64 different positions times 2, equal to 768 different scores. Every possible assignment to those 768 scores represents a different strategy, a <em><strong>hypothesis</strong> &#8212;</em>also called a <em><strong>model</strong></em>. Note that even if we restrict the scores to whole numbers between 1 and 100, we still talk about 100 to the power of 786 different strategies &#8212;a 1 followed by 1536 zeros! Trying out all those hypotheses before the universe reaches heat death is impossible.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> </p><p>So far, we have a simplistic but still huge hypothesis space. Now we need a way to search for an optimal &#8212;or as good as possible&#8212; strategy in it, which in practice means finding the right way to tune those scores so that moving to boards with higher scores actually tends to increase your chance of winning. But how do we know which boards actually lead to winning? </p><p>Here comes another key piece in machine learning solutions: leveraging <em><strong>experience</strong></em>. Obviously, we don&#8217;t know an <em>a priori</em> way to determine if a board is better than another. If we had, that would be our strategy! But we can access millions, potentially even an infinite number of chess matches. How can we <em>learn </em>the right scores from that source of experience? </p><p>There are two fundamentally different paradigms in machine learning which fit chess  well. We will dive deeper into them next time, but for now, let&#8217;s illustrate how they work in the case of chess.</p><p>The first paradigm is <em>learning by imitation </em>&#8212;also called <strong>supervised learning</strong>. In our example, it would work as follows. We first collect all the chess matches ever recorded that we can find. We note whether whites win or lose for each match and tag each board in that match accordingly.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p><p>The second paradigm is <em>learning by trial and error</em> &#8212;also called <strong>reinforcement learning</strong>. Instead of using pre-recorded matches, we let two computer programs play at will &#8212;e.g., choosing each move randomly. And just like before, we tag each board as a winning or losing board conditioned on the results of each simulated match.</p><p>We will have plenty to talk about the advantages and limitations of each paradigm in future entries in this series. For now, all that matters is that we can access a huge amount of experience that tells us how good different boards are in practice.</p><p>With all that experience, how do we actually write a Machine Learning program? Or, specifically in this case, how do we adjust the scores so that the resulting strategy is the best possible? Details vary, but the bottom line is always the same.</p><p>Instead of directly coding the program that plays chess, we write a meta-program &#8212;also called a <em><strong>training algorithm</strong>&#8212;</em> that will search for the best chess program, which means finding the best set of scores in our example. And here comes the final ingredient: <em>best with respect to what</em>?</p><p>In any machine learning setting, we will need a way to compare different hypotheses &#8212;models, or strategies in the case of chess. Thus, finding the best model in our hypothesis space is equivalent to solving an <em>optimization problem</em> in which we seek the hypothesis or model that minimizes some <em><strong>error metric</strong></em><strong>. </strong>This metric tells us how well any given hypothesis solves the task we wanted to learn, e.g., playing chess in this article.</p><p>We will discuss evaluation metrics in detail in a future article, but for now, let&#8217;s consider the most straightforward metric solution in our example. The best strategy in chess is the one that wins the most number of games. Thus, the direct solution would be optimized to maximize the probability of winning. However, for reasons that will become evident in future articles, we can rarely optimize for a direct success metric. That is usually mathematically intractable or at least quite involved.</p><p>Instead, we often find a <em>proxy error metric</em> easier to formulate as an optimization problem and close enough to our objective. In this example, a sensible approximation would be attempting to guess whether the current board is winning. Thus, we will compare two strategies &#8212;hypotheses or models&#8212; not precisely by which is more likely to win but by which is <em>more accurate guessing if a given board appears on a winning game</em>.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></p><p>Now comes the technical part. Instead of simply enumerating all hypotheses &#8212;which we know is impossible, we will pull a rabbit out of the hat and turn the problem of finding the best strategy into solving a system of mathematical equations! Taking the scores as variables, each winning board yields an equation like the following:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sum w_i \\cdot x_i = 1&quot;,&quot;id&quot;:&quot;TPMNSTPEKO&quot;}" data-component-name="LatexBlockToDOM"></div><p>While each losing board yields a similar equation:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\sum w_i \\cdot x_i = 0&quot;,&quot;id&quot;:&quot;JLKKGKGFFZ&quot;}" data-component-name="LatexBlockToDOM"></div><p>Then, we will use a bit of mathematical magic<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a> to determine how to assign the scores <em>w</em> such that most winning boards sum close to 1 and losing boards sum close to 0.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a></p><p>This magic trick of turning an impossibly large search problem into a clever mathematical problem is pivotal to the success of machine learning. It is what allows our <em><strong>trainer algorithm</strong></em> to actually work at all. Otherwise, we would be stuck with trying randomly strategy after strategy to see which is best &#8212;something that we will actually do at some point, mind you.</p><p>And that&#8217;s it! We just tricked a computer into learning to play chess!</p><h2>Machine Learning formalized</h2><p>So far, we&#8217;ve built an intuitive formulation for a Machine Learning approach to solving chess. To summarize, we first simplified playing good chess to merely deciding which is a good next board by assigning some scores to all possible pieces and positions. Then we used loads of previous experience (recorded or simulated) to gather evidence for good and bad boards. And then, we turned the problem of finding the best scores into solving a mathematical problem.</p><p>Now let&#8217;s zoom out and finally define machine learning. This one is my favorite definition, due to MIT professor and author of one of the most influential books on ML, <a href="http://www.cs.cmu.edu/~tom/">Tom Mitchell</a>. </p><blockquote><p>Machine Learning is a computational approach to problem-solving with four key ingredients:</p><ol><li><p>A task to solve (<strong>T</strong>)</p></li><li><p>A performance metric (<strong>M</strong>)</p></li><li><p>A computer program (<strong>P)</strong> </p></li><li><p>A source of experience (<strong>E)</strong></p></li></ol><p>You have a Machine Learning solution when:</p><p><em>The performance of program <strong>P</strong> at task <strong>T</strong>, as measured by <strong>M</strong>, improves with access to the experience <strong>E</strong>.</em></p></blockquote><p>That's it. Notice that the gist of the definition is that <em>experience improves performance</em>. This starkly contrasts traditional software, as we&#8217;ve seen in this post.</p><p>In a typical software application, how well our program solves a problem depends only on its initial programming. The application doesn&#8217;t improve the more you use it. Summarizing, in the traditional approach we:</p><ul><li><p>Define a desired output, e.g., the best move in a given board.</p></li><li><p>Think very hard about the process to compute that output based on a deep understanding of the problem.</p></li><li><p>Write the program P that produces the output.</p></li></ul><p>Machine learning aims to build a program that improves automatically with experience, even if we don&#8217;t fully understand how to solve the problem. To achieve that, we:</p><ul><li><p>Assume there is a template that any sensible program P follows, e.g., a formula parameterized with some unknown values &#8212;a hypothesis space.</p></li><li><p>Write a program Q &#8212; a training algorithm&#8212; that finds the best values based on some experience E.</p></li><li><p>Run Q on E to find the best program P &#8212;the model or hypothesis.</p></li></ul><p>The training algorithm Q is any of a vast array of machine learning techniques: decision trees, neural networks, naive Bayes, logistic regression, etc. Don&#8217;t worry if these names sound alien; we&#8217;ll meet them all in due time.</p><h2>Conclusion</h2><p>In conclusion, the Machine Learning approach represents a major paradigm shift to computational problem-solving. Instead of directly writing a program P to solve task T, you actually code a trainer program Q that, when run on suitable experience E, finds the best program P, according to some metric M.</p><p>This paradigm is so useful because there is an incredible amount of tasks for which we don't know how to write a solution directly. However, in many cases, writing a trainer algorithm is fairly straightforward, provided we have enough experience (e.g., data or simulations) to train on. Machine Learning allows us to tackle problems we can&#8217;t solve directly with a performance that often surpasses the best humans in that task.</p><p>And that's it for today. In the next entry in the series, we'll talk about the different flavors of experience we can have.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This simplification of ignoring interactions between elements is extremely common in machine learning. Viewing this from a probabilistic perspective, we&#8217;re <em>assuming independence </em>among the influence of each variable &#8212;each piece-position pair&#8212; concerning the probability of having a winning board. Assuming independence is often dubbed the <em>naive </em>approach, but it is actually a pretty smart thing to do in many cases.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>A careful examination will show you that there are symmetrical positions for which having different scores makes no sense. However, for simplicity, let&#8217;s happily ignore that fact. Even accounting for all symmetries, the number of strategies will be so large it is unfathomable. And yes, that&#8217;s a word I just learned.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>This means we&#8217;re computing scores for the white player. Scores for the black player will be symmetrical but with opposite signs.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>In practice, you won&#8217;t directly optimize this probability, but rather a continuous approximation called the <em><a href="https://en.wikipedia.org/wiki/Logistic_function">logistic function</a></em>.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>Mathematical magic is also known as algebra, optimization, probabilities, etc.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>I told you we would throw a few math formulas for performative reasons, but don&#8217;t worry; the exact equations don&#8217;t matter. All that matters, for now, is that there is a way to convert a search problem into a mathematical problem. These equations aren&#8217;t even the ones we would actually use (see footnote 4).</p></div></div>]]></content:encoded></item><item><title><![CDATA[What is Computer Science]]></title><description><![CDATA[A high-level overview of the whole field with lots of pointers for further reading]]></description><link>https://blog.apiad.net/p/computer-science</link><guid isPermaLink="false">https://blog.apiad.net/p/computer-science</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Mon, 05 Jun 2023 12:01:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Rbrd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Computer Science is a relatively new field that emerged in the early 20th century from a massive effort to formalize Mathematics. However, it wasn't until the mid-60s and early 70s that it gained recognition as a distinct and unique scientific field. This was achieved by establishing the theoretical grounds of computability and complexity theory, which proved there were many interesting, novel, and challenging scientific questions involving computation.</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Rbrd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Rbrd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Rbrd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg" width="1024" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:273803,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Rbrd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Rbrd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb48a6cb0-7674-480a-a117-e3584ab4bb14_1024x1024.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Computer Science is an extensive field that encompasses a wide range of knowledge and skills. It goes from the most abstract concepts related to the nature of computable problems to the most practical considerations for developing useful software. To solve problems in this field, one must navigate through various levels of abstraction, making it challenging to provide a concise summary that the average reader can easily understand.</p><p>In this series, I will introduce you to the vast and exciting world of Computer Science. We will begin by examining the numerous interconnected subfields of CS at a macro level. We will delve into specific fields, concepts, and even practical techniques and algorithms in future posts. I hope you enjoy the ride, and maybe, if I&#8217;m persuasive enough, you will decide that you want to master Computer Science.</p><blockquote><p>If you enjoy this post, you will probably want to check my upcoming book <strong>The Science of Computation</strong>, which will expand on all these subjects.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;73ab4816-9f7c-4e4e-a982-caebe57d9a48&quot;,&quot;caption&quot;:&quot;&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;sm&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Book Teaser - The Science of Computation&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:6970039,&quot;name&quot;:&quot;Alejandro Piad Morffis&quot;,&quot;bio&quot;:&quot;Democratizing knowledge one post at a time. I talk about Computer Science, AI, Education, Philosophy, you know, mostly harmless stuff.\nBuilding a community of tech writers on Substack.\nAnd now also venturing into creative writing.&quot;,&quot;photo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F26aafc21-b149-4bf0-9382-e0ae3636e23a_640x640.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2024-01-20T20:18:45.138Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9b6d56c-6a04-479f-b76f-6bd5f9b121df_1024x1024.jpeg&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://blog.apiad.net/p/book-teaser-the-science-of-computation&quot;,&quot;section_name&quot;:&quot;&#129504; Computer Science&quot;,&quot;video_upload_id&quot;:null,&quot;id&quot;:140745794,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:28,&quot;comment_count&quot;:20,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;Mostly Harmless Ideas&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2b621db-62a6-452b-b433-ccc0f5c4f0b3_1024x1024.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div></blockquote><h2><strong>A Map of Computer Science</strong></h2><p>Computer Science encompasses a vast range of subjects, incorporating multiple areas of math and engineering. It also introduces many original concepts and ideas. Thus it is impossible to divide this field objectively into subfields or separate areas with precise borders. I will attempt to categorize it into somewhat cohesive disciplines, but keep in mind there is considerable interconnectedness between them.</p><p>In the following sections, I will lay out what I believe are the most fundamental concepts and problems in Computer Science. Whenever possible, I will provide a link to further reading, most commonly to a relevant Wikipedia article, which in these topics is a highly accurate and accessible resource. I will also provide links to the other posts in this series <strong>in bold</strong> format.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Mostly Harmless Ideas is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><h3><strong>Theoretical Foundations</strong></h3><p>Let's start by looking at the foundations. The fundamental question of Computer Science is something akin to <em>"What kinds of problems can be solved with algorithms."</em> It was first asked formally by David Hilbert in 1901 and first answered by Alan Turing in 1936. This central question of <a href="https://en.wikipedia.org/wiki/Computability_theory">computability theory</a> establishes the foundational theory for what can be done with any computer.</p><p>The core concept in computability is the <a href="https://en.wikipedia.org/wiki/Turing_machine">Turing machine</a>, an abstract computer model that we define to study the properties of computation and computable problems irrespective of any concrete machine our current technology supports. Turing machines let us answer which kinds of problems are, in principle, undecidable &#8212;which means that no algorithm can ever be devised to solve them completely. Surprisingly, there are many of those, not all esoteric; there are very practical problems in Computer Science that we know are mathematically impossible to solve. Turing machines also give a precise definition of <a href="https://en.wikipedia.org/wiki/Algorithm">algorithm</a>.</p><p>Once we lay out the limits of computation, we can ask which computable problems are easier or harder. <a href="https://en.wikipedia.org/wiki/Computational_complexity_theory">Complexity theory</a> deals with the complexity of different problems. It asks how efficiently, most commonly in terms of computing time and memory, we can solve any problem. For some problems, we can even prove that we have found the most efficient algorithm anyone could ever develop. The most important problem in complexity theory, and probably in the whole of Computer Science, is the famous question of whether <a href="https://en.wikipedia.org/wiki/P_versus_NP_problem">P=NP</a>, which is ultimately a question about the nature of really hard problems.</p><p>The final ingredient in the foundational theory of Computer Science is the relationship between <a href="https://en.wikipedia.org/wiki/Formal_language">formal languages</a> and <a href="https://en.wikipedia.org/wiki/Automata_theory">automata</a>. Formal language theory allows us to formalize the notion of a language, whether it is a human language like English or Spanish, a programming language like Python or C#, and any technical, abstract, or mathematical notations used in many fields.</p><p>The basic concept in formal language theory is <a href="https://en.wikipedia.org/wiki/Formal_grammar">formal grammar</a>, a formal definition of what can be said with a specific language. In contrast, automata theory deals with abstract machines &#8212;like Turing machines&#8212; of different levels of complexity that can recognize specific families of formal languages. The study of the relationship between language generation and recognition led to the invention of <a href="https://en.wikipedia.org/wiki/Compiler">compilers</a>, which are computer programs that understand specific programming languages and translate them to machine code that can be run on concrete hardware.</p><h3><strong>Math Foundations</strong></h3><p>Computer Science emerged from Mathematics, and therefore, it adopted the mathematical practice of establishing axioms and demonstrating theorems. Besides, when tackling real-world computational challenges, we frequently apply mathematical techniques used in engineering and other fields of science. Consequently, a substantial amount of mathematical knowledge underpins Computer Science, albeit with a computational perspective.</p><p><a href="https://en.wikipedia.org/wiki/Logic">Logic</a> forms the bedrock of Computer Science as it gave birth to its fundamental principles. By enabling us to formalize reasoning algorithmically, Logic allows us to create programs that can manipulate logical formulas and prove theorems and also lets us formally prove that an algorithm works as intended. <a href="https://en.wikipedia.org/wiki/Discrete_mathematics">Discrete Math</a> is a natural extension of Logic, encompassing a vast mathematical field that studies discrete objects such as collections of natural numbers. It formalizes numerous basic computational concepts like <em>graphs</em> and <em>trees</em>. Additionally, Discrete Math lies at the core of modern cryptography, which relies heavily on <a href="https://en.wikipedia.org/wiki/Number_theory">number theory</a>.</p><p><a href="https://en.wikipedia.org/wiki/Algebra">Algebra</a> and <a href="https://en.wikipedia.org/wiki/Calculus">calculus</a> are fundamental math subfields used in most engineering and scientific disciplines, and even more so in Computer Science. Algebra deals with mathematical structures such as <em>vectors</em>, <em>matrices</em>, <em>vector spaces</em>, and operations between them. Many abstract algebraic operations can be interpreted as some form of data manipulation. Thus they appear at the core of many CS applications, from computer graphics to compression to search engines to machine learning. Algebra also strongly connects with <a href="https://en.wikipedia.org/wiki/Computational_geometry">computational geometry</a>, the branch of geometry that studies computational approaches to 2D and 3D modeling, computer-aided design (CAD), and many related applications.</p><p>Calculus deals with the relationship between changing quantities. It enables us to determine how to adjust the input to achieve a desired output, even when their relationship is fairly complex. If you go deeper into the formal properties of these relations, you will find the field of <a href="https://en.wikipedia.org/wiki/Mathematical_analysis">mathematical analysis</a>. Two key concepts in calculus and analysis are <a href="https://en.wikipedia.org/wiki/Differential_calculus">differentiation</a> and <a href="https://en.wikipedia.org/wiki/Integral">integration</a>, and they have numerous applications in Computer Science, particularly in <a href="https://en.wikipedia.org/wiki/Mathematical_optimization">continuous optimization</a>, which also underpins many modern machine learning methods. An interesting middle ground between algebra and calculus is the field of <a href="https://en.wikipedia.org/wiki/Differential_equation">differential equations</a>, which helps to model complex phenomena, from weather to engines to epidemics, where the rates of change among different quantities depend on each other. Mathematical analysis also provides the foundations for the fields of probability and statistics. </p><p><a href="https://en.wikipedia.org/wiki/Probability">Probability</a> is the branch of mathematics that studies reasoning under uncertainty. In a sense, it&#8217;s an extension of Logic when we consider that statements can not only be true or false, but they have some degree of likelihood. A related field is <a href="https://en.wikipedia.org/wiki/Statistics">Statistics</a>, which involves understanding and extracting insights from &#8212;often uncertain&#8212; data. Both fields are extremely relevant to <em><a href="https://en.wikipedia.org/wiki/Data_science">data science</a></em> and intersect with Computer Science in many tasks, from analyzing real-world data to designing programs that can reason and make decisions under uncertainty, such as autonomous vehicles or virtual agents.</p><p>However, continuous math (including algebra, calculus, probabilities, and statistics) assumes real numbers with infinite precision, but in physical computers, all we can hope for is finite approximations. Thus, every mathematical operation performed in a computer can involve some approximation errors. Dealing with this problem robustly and efficiently is surprisingly hard. It is the purpose of <a href="https://en.wikipedia.org/wiki/Numerical_analysis">numerical analysis</a><em>, </em>an essential tool to avoid catastrophic errors from misunderstood approximations. It also provides efficient algorithms for many abstract operations from algebra and calculus.</p><h3><strong>Algorithms</strong></h3><p>Beyond the theoretical foundations, solving a concrete Computer Science problem will often require using one or more <a href="https://en.wikipedia.org/wiki/Algorithm">algorithms</a>. Hence, studying which specific algorithm can solve which concrete problem is a big part of Computer Science. Some of the most basic and commonly used algorithms you&#8217;ll encounter are devoted to solving problems on collections of items, such as lists of numbers or sequences of letters. Two basic data structures used throughout Computer Science are <em>arrays</em> and <em>strings</em>.</p><p><a href="https://en.wikipedia.org/wiki/String_(computer_science)">Strings</a> are sequences of symbols &#8212;called <em>characters</em>&#8212; most commonly used to represent text. <a href="https://en.wikipedia.org/wiki/String-searching_algorithm">String matching</a>, i.e., the problem of finding if a given pattern appears in a text, is one the most studied problems in CS with applications everywhere from compiler design to DNA analysis to chatbots to search engines.</p><p>An <a href="https://en.wikipedia.org/wiki/Array_(data_structure)">array</a> is a collection of items of an arbitrary type &#8212;e.g., numbers, words, images, or custom user data records. The most basic operations in arrays are <strong><a href="https://apiad.substack.com/p/binary-search">searching</a></strong> and <a href="https://en.wikipedia.org/wiki/Sorting_algorithm">sorting</a>, which give rise to some of the most clever algorithms ever designed. On top of arrays, we find many <a href="https://en.wikipedia.org/wiki/Data_structure">data structures</a> that focus on efficiently performing some particular operations on specific types of objects. These include <em>lists</em>, <em>queues</em>, <em>stacks</em>, <em>heaps</em>, and the two fundamental ways to represent data in Computer Science: <em>trees</em> and <em>graphs</em>.</p><p>A <a href="https://en.wikipedia.org/wiki/Tree_(data_structure)">tree</a> is a hierarchical collection of items in which every item has a <em>parent</em> and potentially many <em>children</em>. It is used anywhere we need to represent intrinsically hierarchical data, such as organizations of people. However, trees also appear in many problems where the hierarchy is not obvious, such as evaluating mathematical expressions or searching large mutable collections of objects.</p><p><a href="https://en.wikipedia.org/wiki/Graph_(discrete_mathematics)">Graphs</a> are the most general data structure to represent abstract information computationally. A graph is a collection of nodes connected by edges. It can represent anything network-like, from geospatial data to social networks to abstract things like the dependencies between subtasks in a given problem. Graph algorithms are so vast that you can find whole subfields dedicated to just a subset of them. Still, the most basic one is <a href="https://en.wikipedia.org/wiki/Shortest_path_problem">path-finding</a>, i.e., finding a path &#8212;often optimal in some sense&#8212; between one specific source node and one or more destinations.</p><p>However, just memorizing a huge toolbox of algorithms is not enough. Sometimes you&#8217;ll find problems for which no one has already designed an algorithm. In these cases, you&#8217;ll need <em><a href="https://en.wikipedia.org/wiki/Algorithmic_paradigm">algorithm design strategies</a></em>, which are higher-level ideas and patterns useful for creating new algorithms.</p><p>The most powerful such strategy is <a href="https://en.wikipedia.org/wiki/Recursion_(computer_science)">recursion</a>, so much so that <em>&#8220;you can do anything with recursion&#8221;</em> is a popular meme in Computer Science. Recursion is all about solving a problem by decomposing it into subproblems that are easier to solve. When taken to its extreme, this idea allows us to formalize the whole theory of computability, which means that any algorithm in Computer Science is, at its core, recursive. There are many recursive patterns; some of the most commonly used are <em>tail recursion</em>, <em>divide and conquer</em>, and <em>backtracking</em>.</p><p>Other powerful design strategies underpin many of the most successful algorithms in Computer Science. <em><a href="https://en.wikipedia.org/wiki/Greedy_algorithm">Greedy algorithms</a></em>, for example, are the ones that make the best short-term choice. While this is often suboptimal, there are surprisingly many cases where a carefully chosen local optimum leads to a global optimum. <em><a href="https://en.wikipedia.org/wiki/Dynamic_programming">Dynamic programming</a></em> is another such strategy. Under the right circumstances, it allows transforming a slow recursive algorithm into a very fast non-recursive version while retaining all the correctness guarantees.</p><h3><strong>Computational Systems</strong></h3><p>Mastering algorithms is not enough, though. Ultimately, we need a physical device that can run those algorithms and give us a result at a reasonable cost. Real computers are the physical embodiment of Turing machines, but the devil is in the details. Building a real computer is far more involved than just wiring some cables. Even assuming, as we do in CS, that electronic components always work as expected, the design of resilient computational systems is a whole discipline.</p><p>At the lowest level, we have <a href="https://en.wikipedia.org/wiki/Logic_gate">transistors</a>, microscopic circuitry that performs a very simple operation: an electronic current breaker. We can design logical circuits &#8212;combinations of electronic components that perform whatever logical operation we desire&#8212; with just a few transistors. We can design circuits to add, multiply, or store values to build a <em><a href="https://en.wikipedia.org/wiki/History_of_general-purpose_CPUs">Central Processing Unit</a></em> (CPU) connected to a <em><a href="https://en.wikipedia.org/wiki/Random-access_memory">Random Access Memory</a></em> (RAM) bank. This is the basic computer, which can be programmed with very simple languages called <em>Assembly Languages</em>. It is at this level that the frontier between hardware and software melds.</p><p>Modern computers have increasingly more complex components, including external memory drives and peripherals like displays and keyboards. Keeping all of those components in harmony is the job of the <a href="https://en.wikipedia.org/wiki/Operating_system">Operating System</a>. OSes like Windows and Linux do much more, though. They provide an abstraction layer over common operations that many programs need, including interfacing with hardware peripherals &#8212;e.g., playing sounds or capturing video&#8212; or writing and reading from files. Two key abstractions are <em>processes</em>, which allow each program to behave as if it were the only one running, and <em>threads</em>, which enable concurrency even if you have a single physical CPU.</p><p>But if one computer is incredible, the real magic begins once you have two or more working together. Enter the world of <a href="https://en.wikipedia.org/wiki/Computer_network">computer networking</a>. The first problem we must solve is simply getting two computers on both sides of the planet, talking reliably to each other over a noisy, error-prone communication channel. The <a href="https://en.wikipedia.org/wiki/Internet_protocol_suite">TCP/IP protocol</a> is a collection of algorithms that guarantee communication even when intermediary steps fail constantly. It's the software backbone of the Internet, possibly the single most important technological advance after the first industrial revolution.</p><p><a href="https://en.wikipedia.org/wiki/Distributed_computing">Distributed systems</a> allow multiple computers to communicate and collaborate, creating larger organizational levels of computational systems. The simplest setup is the client-server architecture, where an application is split between the user and the service provider. As these systems scale up, they require coordination among several computers to maintain reliability even when some individual components fail. To achieve this, <em><a href="https://en.wikipedia.org/wiki/Signal_processing">consensus algorithms</a></em> are used for data distribution, monitoring system health, and error correction tasks.</p><p>Some of today's largest software platforms, like the Google Search Engine and Amazon Web Services, rely on distributed systems as their foundation. These infrastructures are often called <em><a href="https://en.wikipedia.org/wiki/Cloud_computing">cloud computing</a></em> &#8212;vast networks of computers working together as one unified computing platform.</p><p>A crucial component in computational systems is security, especially when valuable information is stored on computers connected to the internet. Ensuring reliable and secure communication between computers is a major challenge in computer science, addressed with the help of cryptography.</p><p><a href="https://en.wikipedia.org/wiki/Cryptography">Cryptography</a> has its roots in breaking machine codes during World War II, such as the Enigma code deciphered by Alan Turing. Modern cryptography relies on <em>symmetric</em> and <em>asymmetric</em> or public-key methods, which enable two actors to establish a secure channel over an insecure communication medium without ever meeting each other. This principle forms the backbone of most online interactions, from reading your email to using your bank account to chatting with another person so that no one can access your data, often not even the service provider.</p><h3><strong>Software Engineering </strong></h3><p>Building software that works is extremely hard. It's not enough to master all the algorithms, data structures, theorems, and protocols. Software products have unique qualities among all other engineering products, especially regarding flexibility and adaptability requirements. Any software that lives long enough will have to be changed in ways that weren't predictable when the software was first conceived. This poses unique challenges to the engineering process of making software, the domain of <a href="https://en.wikipedia.org/wiki/Software_engineering">software engineering</a>.</p><p>Software construction starts with a <a href="https://en.wikipedia.org/wiki/Programming_language">programming language</a>, of which there are plenty of variants. Some programming languages are designed for specific domains, while others are called general purpose and designed for any programming task. A fundamental distinction is between <em>imperative</em> and <em>declarative</em> languages.  The most influential paradigms are <em>functional</em> (often declarative) and <em>object-oriented</em> (most commonly imperative) programming models.</p><p>Programming languages are tools, so their effectiveness in solving a concrete problem relies heavily on applying best practices. Software engineering also deals with finding <a href="https://en.wikipedia.org/wiki/List_of_software_development_philosophies">principles and practices</a> to use better the available tools, including technical tools and human resources. The most important set of software engineering principles is the <a href="https://en.wikipedia.org/wiki/SOLID">SOLID principles</a>. Other principles, such as DRY and YAGNI, emphasize specific, pragmatic mindsets about software development. Additionally, we have dozens of <a href="https://en.wikipedia.org/wiki/Design_pattern_(computer_science)">design patterns</a>: concrete reusable solutions to common software development problems.</p><p>Beyond the actual code, the most crucial resource most applications must manage is data. As the necessity to organize, query, and process larger and larger amounts of data increases, we turn from classic in-memory data structures to more advanced long-term storage solutions: <a href="https://en.wikipedia.org/wiki/Database">databases</a>. The <em>relational database</em> is the most pervasive model for representing and storing application data, especially structured data. However, several alternative non-relational paradigms are gaining relevance as less structured domains (such as human language and images) become increasingly important.</p><p>In the data-centric software world, <a href="https://en.wikipedia.org/wiki/Information_system">information systems</a> are some of the most complex applications we can find. They provide access to vast amounts of information, which can be from a concrete domain &#8212;such as medical or commercial information&#8212; or general purpose like search engines. These systems combine complex algorithms and data structures for efficient search with massively distributed hardware architectures to serve millions of users in real-time.</p><p>As we've seen, software ultimately runs on someone's computer, and different computational systems pose different challenges. From a software engineering perspective, we can understand those challenges better if we think in terms of <em>platforms</em>. The three major software platforms are the <em>desktop</em> (apps installed in your computer), the <em>mobile </em>(apps installed in your smartphone), and the <em>web </em>(apps running on your browser).</p><p>Developing desktop software is hard because different users will have different hardware, operating systems, and other considerations, making it hard to build robust and portable software. Mobile development brings additional challenges because mobile devices vary widely and are often more limited than desktop hardware, so performance is even more crucial. The <a href="https://en.wikipedia.org/wiki/World_wide_web">web</a> is the largest platform, and we've already discussed distributed systems. The web is an interesting platform from the software engineering perspective because it is pervasive and lets us abstract from the user's hardware. Perhaps the most famous software development technologies are those associated with web development: HTML, CSS, and JavaScript.</p><p>The final component in software engineering concerns the interaction between the user and the application. <a href="https://en.wikipedia.org/wiki/Human%E2%80%93computer_interaction">Human-computer interaction</a> (HCI) studies the design of effective user interfaces, both physical and digital. Two major concerns are designing an appropriate <em>user experience</em>, and ensuring <em>accessibility</em> for all users, fundamentally those with special needs such as limited eyesight, hearing, or movement.</p><h3><strong>Artificial Intelligence</strong></h3><p><a href="https://en.wikipedia.org/wiki/Artificial_intelligence">Artificial Intelligence</a> (AI) is a broad and loosely defined umbrella term encompassing different disciplines and approaches to designing and building computational systems that exhibit some form of intelligence. Examples of machines exhibiting intelligent behavior range from automatically proving new theorems to playing expert-level chess to self-driving cars to modern chatbots. Accurately defining what we mean by machine intelligence is extremely difficult and out of the scope of this post, but ultimately it revolves around the capacity to solve hard problems with as little explicit guidance as possible. We can cluster the different approaches in AI into three broad areas: <em>knowledge</em>, <em>search</em>, and <em>learning.</em></p><p><a href="https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning">Knowledge representation and reasoning</a> studies how to store and manipulate domain knowledge to solve reasoning and inference tasks, such as medical diagnosis. We can draw from Logic and formal languages to represent knowledge in a computationally convenient form. <a href="https://en.wikipedia.org/wiki/Ontology_(computer_science)">Ontologies</a> are computational representations of the concepts, relations, and inference rules in a concrete domain that can be used to infer new facts or discover inconsistencies automatically via logical reasoning. Knowledge discovery encompasses the tasks for automatically creating these representations, for example, by analyzing large amounts of text and extracting the main entities and relations mentioned. Ontologies are a special case of <a href="https://en.wikipedia.org/wiki/Semantic_network">semantic networks</a>, graph-like representations of knowledge, often with informal or semi-formal semantics.</p><p><a href="https://en.wikipedia.org/wiki/Mathematical_optimization">Search</a> deals with finding solutions to complex problems, such as the best move in a chess game or the optimal distribution of delivery routes. The hardest search problems often appear in <em>combinatorial optimization</em>, where the space of possible solutions is exponential and thus unfeasible to explore completely. The most basic general search procedures &#8212;Depth-First Search (DFS) and Breadth-First Search (BFS)&#8212; are exact, exhaustive, and thus often impractical. Once you introduce some domain knowledge, you can apply heuristic search methods, such as A* and Monte Carlo Tree Search, which avoid searching the entire space of solutions by cleverly choosing which solutions to look at. The ultimate expression of heuristic search is <a href="https://en.wikipedia.org/wiki/Metaheuristic">metaheuristics</a> &#8212;general-purpose search and optimization algorithms that can be applied nearly universally without requiring too much domain knowledge.</p><p><a href="https://en.wikipedia.org/wiki/Machine_learning">Machine learning</a> enables the design of computer programs that improve automatically with experience and is behind some of the most impressive AI applications, such as self-driving cars and generative art. In ML, we often say a program is &#8220;trained&#8221; instead of explicitly coded to refer to this notion of <em>learning on its own</em>. Ultimately, this involves finding hypotheses that can be efficiently updated with new evidence.</p><p>The three major paradigms in this field are <em>supervised</em>, <em>unsupervised</em>, and <em>reinforcement</em> learning. Each case differs in the type of experience and/or feedback the learning algorithm receives. In <a href="https://en.wikipedia.org/wiki/Supervised_learning">supervised learning</a>, we use annotated data where the correct output for each input is known. <a href="https://en.wikipedia.org/wiki/Unsupervised_learning">Unsupervised learning</a>, in contrast, doesn&#8217;t require a known output; it attempts to extract patterns from the input data solely by looking at its internal structure. </p><p><a href="https://en.wikipedia.org/wiki/Reinforcement_learning">Reinforcement learning</a> involves designing systems that can learn by interaction via trial and error. Instead of a fixed chunk of data, reinforcement learning places a learning system &#8212;also called an <em>agent </em>in this paradigm&#8212; in an environment, simulated or real. The agent perceives the environment, acts upon it, and receives feedback about its progress in whatever task it is being trained on. When the environment is simulated, we can rely on different paradigms, such as <em>discrete events</em> or <em>Monte Carlo simulations</em>, to build a relatively realistic simulation. Reinforcement learning is crucial in robotics and recent advances in large language models.</p><p>All of the above are general approaches that can be applied to various domains, from medical diagnosis to self-driving cars to robots for space exploration. However, two domains of special importance that have seen massive improvements recently are vision and language. The most successful approaches in both fields involve using <a href="https://en.wikipedia.org/wiki/Artificial_neural_network">artificial neural networks</a>, a computational model loosely inspired by the brain that can be trained to perform many perceptual and generative tasks. ANNs draw heavily from algebra, calculus, probability, and statistics, representing some of the most complex computer programs ever created. The field of neural networks is alternatively called <em><a href="https://en.wikipedia.org/wiki/Deep_learning">deep learning</a></em>, mostly for branding purposes.</p><p><a href="https://en.wikipedia.org/wiki/Computer_vision">Computer vision</a> deals with endowing computational systems with the ability to process and understand images and videos for tasks like automatic object segmentation and classification. Classic approaches to computer vision rely heavily on <a href="https://en.wikipedia.org/wiki/Signal_processing">signal processing algorithms</a> stemming from algebra and numerical analysis. Modern approaches often leverage neural networks, most commonly <em><a href="https://en.wikipedia.org/wiki/Convolutional_neural_network">convolutional networks</a></em>, loosely inspired by the visual parts of animal brains.</p><p><a href="https://en.wikipedia.org/wiki/Natural_language_processing">Natural language processing</a> (NLP) enables computational systems to process, understand, and generate human-like language. It encompasses many problems, from low-level linguistic tasks, such as detecting the part-of-speech of words in a sentence or extracting named entities, to higher-level tasks, such as translation, summarization, or maintaining conversations with a human interlocutor. The most successful approaches in modern NLP leverage <em><a href="https://en.wikipedia.org/wiki/Transformer_(machine_learning_model)">transformer networks</a></em>, a special type of neural network architecture that can represent some forms of contextual information more easily than other architectures. These are the mathematical underpinnings behind technologies like <a href="https://en.wikipedia.org/wiki/Large_language_model">large language models</a> and chatbots.</p><h2><strong>Conclusions</strong></h2><p>Computer science is a vast field encompassing both theoretical and practical aspects. It goes from the most abstract computational concepts grounded in logic and mathematics to the most pragmatic applications based on solid engineering principles to frontier research like building intelligent systems. Working in CS also involves navigating complex social interactions between developers, users, and society and requires awareness of the many ethical issues that automation and computation pose.</p><p>Mastering computer science is a significant challenge, making it one of the most demanding academic pursuits. However, this discipline offers immense fulfillment since computation lies at the heart of our modern world. Software pervades all sectors and industries. Those proficient in computer science can find work across various disciplines and not only by creating commercial software. Across all scientific disciplines, from understanding the frontiers of space to solving climate change, designing new materials, and extending human life, every challenging problem in every scientific field has computational aspects that require collaboration between computer scientists and experts from that domain.</p><p>With this post, I hope to have ignited your curiosity in exploring the beautiful ideas at the core of computer science and its intersection with other fields. If that's the case, then I invite you to stay in touch. I'll be back with more Computer Science topics very soon.</p>]]></content:encoded></item><item><title><![CDATA[Binary Search]]></title><description><![CDATA[An introduction to the most important problem in Computer Science and one of the most clever algorithms ever devised.]]></description><link>https://blog.apiad.net/p/binary-search</link><guid isPermaLink="false">https://blog.apiad.net/p/binary-search</guid><dc:creator><![CDATA[Alejandro Piad Morffis]]></dc:creator><pubDate>Mon, 27 Mar 2023 02:07:04 GMT</pubDate><enclosure url="https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw"><img src="https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080" width="1080" height="721" data-attrs="{&quot;src&quot;:&quot;https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:721,&quot;width&quot;:1080,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;library interior&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="library interior" title="library interior" srcset="https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 424w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 848w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1272w, https://images.unsplash.com/photo-1533327325824-76bc4e62d560?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwzMDAzMzh8MHwxfHNlYXJjaHwxOHx8Ym9va3NoZWxmfGVufDB8fHx8MTY3OTQ5NzQ0NA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=1080 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Photo by <a href="https://unsplash.com/@claybanks">Clay Banks</a> on <a href="https://unsplash.com">Unsplash</a></figcaption></figure></div><p>Searching is at the core of the vast majority of software ever written. From scientific computation to everyday apps, there&#8217;s no shortage of examples where searching for something, a piece of information, a concrete datum, or a solution to an equation, is a fundamental operation. Databases are the most visible and common implementation of search ubiquitous in most applications. </p><p>But searching in Computer Science goes far beyond scanning a list of elements to find the one that matches a query. Searching is one of the fundamental strategies for problem-solving. The hardest problems in Computer Science, the so-called <a href="https://en.wikipedia.org/wiki/NP-hardness">NP-Hard</a>, are all about search. So it&#8217;s no wonder search algorithms abound, from the basic linear search to using super elaborate data structures, heuristics, and approximations.</p><p>In this and one or more follow-up posts, I want to tell you about the basic ideas behind searching and sorting and how to make both processes efficient. And finally, I want to show you a beautiful and surprising relationship between both problems, which has interesting philosophical implications for Computer Science at large.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.apiad.net/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.apiad.net/subscribe?"><span>Subscribe now</span></a></p><p>Suppose you have to search for a given book in a huge library, and all you know is the title. The simplest (and dumbest) strategy is to scan the bookshelf from top to bottom, left to right, looking at <em>every single book</em> until you find the one you&#8217;re looking for, or you&#8217;re convinced it is not in there. If you have, say, 1 million books<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, and the time it takes you to grab a book, read its title and put it back is on average 30 seconds, it could take you almost a year (~347 days) to scan the whole library. Assuming the book you&#8217;re looking for is equally likely to be anywhere in the library, every query will take on average close to six months!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Can we do any better? Well, of course! If we only had some sort of organization, for example, putting all books that start with the same letter on contiguous shelves, we could speed up the search immensely. We can complicate this system as much as we want, with rows tagged themselves also by the second letter of the title, and so on. </p><p>However, there is one simple strategy we can use that is almost too good to be true. What if we just sort all books by title, starting from the top left shelf to the bottom right? How fast can we search now? The answer, it turns out, is that we can search <em>as fast as possible</em>.</p><h2>Searching as fast as possible</h2><p>The basic idea we will follow is quickly discarding the biggest possible number of books with the minimum amount of effort. If the books are sorted, and we pick a random book, we can immediately discard either all the books before or all the books after it, depending on whether the title we&#8217;re looking for comes before or after the title we randomly picked. We repeat this procedure among the remaining set of books until we either find the one we&#8217;re looking for or discard all the books. </p><p>How much faster is this approach? Well, it depends on how many books we can discard in each step. If we pick one of the books close to the beginning of the list, e.g., the 10,000th book, then two things can happen. If we&#8217;re lucky and the title we&#8217;re looking for comes before, we&#8217;ve just discarded 99% of the library by looking at a single book! But if we&#8217;re unlucky, we only discarded the first 1%. Intuitively, we should try to discard the same amount of books regardless of whether the one we&#8217;re looking for comes before or after, so we should always split the list in half.</p><div class="pullquote"><p>This algorithm is called <a href="https://en.wikipedia.org/wiki/Binary_search_algorithm">Binary Search</a>, and it is one of the most beautiful algorithms you encounter when first learning to program.</p></div><p>If we do this, looking at the 500,000th book first, then either the 250,000th or the 750,000th, and so on, we can narrow down the list of possible books pretty fast. A simple information-theoretic argument shows that this is the best possible strategy if the only operation we can do is compare titles.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> In the worst case, we will have to do at most close to log(N) comparisons, where N is the initial number of books, which for 1 million gives us a whooping amount of 20 comparisons! Even if each comparison takes us 10 minutes instead of 30 seconds (presumably because we have to walk across the library to go from the 500,000th to the 750,000th book) we still find the book we&#8217;re looking for, among 1 million books, in a mere 3 hours. Compare that with the six months our naive strategy required!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Lc9n!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Lc9n!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 424w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 848w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 1272w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Lc9n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif" width="1280" height="720" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:720,&quot;width&quot;:1280,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:625759,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Lc9n!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 424w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 848w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 1272w, https://substackcdn.com/image/fetch/$s_!Lc9n!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71206c58-1fe2-476b-bfa0-7b726f5cfe5d_1280x720.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">An illustrative example of Binary Search in a small collection of sorted numbers.</figcaption></figure></div><h2>The lesson from Binary Search</h2><p>Binary Search is the first truly clever algorithm you learn about, one that exploits an innocent characteristic of the problem to obtain a maximally efficient strategy. The main takeaway from Binary Search is a lesson that most grandmas are keen on repeating over and over to their grandchildren: if you keep things in order, you will have a much easier time finding them. Granny just didn&#8217;t know how true this can be. By exploiting the order of elements and carefully choosing where we look we can speed up the search <em>exponentially</em>.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></p><div class="pullquote"><p><strong>In brief, </strong><em><strong>it pays to keep things sorted.</strong></em></p></div><p>Hence, next time we&#8217;ll take a look at sorting, the complementary operation of searching, how to make it as fast as possible, and a surprising connection that will close the story beautifully.</p><div><hr></div><p><em>And this is all for today. I want to thank <a href="https://twitter.com/Hrokrinn">@Hrokrinn</a> for their proofreading and suggestions, and all of my subscribers and Twitter followers for giving me the inspiration to keep writing.</em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This is not an exaggeration by any means. For example, the Library of Congress has over 25 million books and close to 170 million items in total. There are hundreds of libraries worldwide with more than 1 million physical books inside.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>This is why libraries have catalogs, indexes, and all sorts of shortcuts for quickly finding what you&#8217;re looking for.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>An intuitive explanation goes like this. We have to find a specific element X among N, and it could be potentially anywhere, so the probability that either of the elements is X is 1/N. How can we ask a single question that gives us the maximum amount of information? One way to look at this problem is to consider the relation between information and entropy. The more entropy a distribution has, the less information it contains. Our current best guess is that X can be anywhere, uniformly distributed, and has the maximum amount of entropy for all discrete distributions of N elements, so it has the least amount of information. </p><p>If we split the N elements at the k-th percentile, in two subsets of sizes k*N and (1-k)*N respectively, then the amount of information we gain with that single question can be shown to be proportional to the sum of the entropies of both subsets (again, each taken uniformly distributed). A simple mathematical analysis shows that this sum is maximum when k = 0.5, which is when we split the collection in half.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>To see why this is the case, consider looking at Binary Search from the inverse function viewpoint. Let&#8217;s say searching with Binary Search takes K operations (K comparisons, that is). In K comparisons, you can find any given element among N, such that log(K) = N. This means that N = 2^K (that&#8217;s 2 to the power of K). Thus, a naive linear search will require exponentially more effort than a Binary Search in a collection of the same size.</p></div></div>]]></content:encoded></item></channel></rss>