<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Algorithm Archives | Abdul Wahab Junaid</title>
	<atom:link href="https://awjunaid.com/category/algorithm/feed/" rel="self" type="application/rss+xml" />
	<link>https://awjunaid.com/category/algorithm/</link>
	<description>Offensive Security Researcher &#38; Quantum Cryptography Analyst</description>
	<lastBuildDate>Sat, 25 Jul 2026 22:44:01 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://i0.wp.com/awjunaid.com/wp-content/uploads/2023/06/cropped-1668274976669.jpeg?fit=32%2C32&#038;ssl=1</url>
	<title>Algorithm Archives | Abdul Wahab Junaid</title>
	<link>https://awjunaid.com/category/algorithm/</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">220030102</site>	<item>
		<title>Matrices in Mathematics: A Comprehensive Guide with Applications</title>
		<link>https://awjunaid.com/algorithm/matrices-in-mathematics-a-comprehensive-guide-with-applications/</link>
					<comments>https://awjunaid.com/algorithm/matrices-in-mathematics-a-comprehensive-guide-with-applications/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 17:07:38 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10901</guid>

					<description><![CDATA[<p>I want to begin by explaining what a matrix actually is: a rectangular array of numbers, symbols, or&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/matrices-in-mathematics-a-comprehensive-guide-with-applications/">Matrices in Mathematics: A Comprehensive Guide with Applications</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I want to begin by explaining what a matrix actually is: a rectangular array of numbers, symbols, or expressions arranged in rows and columns. I use matrices whenever I need to represent linear relationships compactly, whether I am solving systems of equations, transforming coordinates in graphics, or encoding data for machine learning. The importance of matrices, in my view, comes from their dual nature — they are both a bookkeeping device for numbers and an algebraic object with its own rules of addition, multiplication, and inversion. Because so many fields depend on linear structure, I find matrices sitting at the core of physics, computer science, economics, and engineering alike.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the earliest matrix-like reasoning back to ancient Chinese mathematics, specifically the text &#8220;The Nine Chapters on the Mathematical Art&#8221; (circa 200 BCE), where I find array-based methods for solving systems of linear equations that closely resemble Gaussian elimination. Moving forward in time, I see the modern formalism emerging in the 19th century through the work of James Joseph Sylvester, who coined the term &#8220;matrix&#8221; in 1850, and Arthur Cayley, who developed matrix algebra in his 1858 paper &#8220;A Memoir on the Theory of Matrices.&#8221; I note that Cayley treated matrices as objects in their own right, defining addition and multiplication, which allowed the theory to grow independently of the systems of equations that originally motivated it. Through the late 19th and 20th centuries, I see matrix theory absorbed into linear algebra, becoming essential to quantum mechanics (through Heisenberg&#8217;s matrix mechanics), computer graphics, and numerical analysis.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use matrices to solve a recurring class of problems: how do I represent and manipulate linear relationships between multiple variables at once? Without matrices, I would need to write out long systems of equations term by term. With matrices, I can express an entire system as $$A\mathbf{x} = \mathbf{b}$$ and manipulate it using well-defined operations. I also rely on matrices to solve problems of transformation (rotating, scaling, projecting geometric objects), problems of representation (adjacency matrices for graphs), and problems of optimization (matrices appear throughout linear programming and machine learning).</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I define a matrix of size $m \times n$ as an array with $m$ rows and $n$ columns, denoted $A = [a_{ij}]$ where $a_{ij}$ is the entry in row $i$ and column $j$. I distinguish several important types:</p>



<ul class="wp-block-list">
<li><strong>Square matrix</strong>: $m = n$</li>



<li><strong>Identity matrix</strong> $I$: a square matrix with 1s on the diagonal and 0s elsewhere</li>



<li><strong>Diagonal matrix</strong>: nonzero entries only on the diagonal</li>



<li><strong>Symmetric matrix</strong>: $A = A^T$</li>



<li><strong>Zero matrix</strong>: all entries zero</li>
</ul>



<p class="wp-block-paragraph">I also rely on the concepts of matrix transpose (flipping rows and columns), matrix rank (the number of linearly independent rows or columns), determinant (a scalar describing invertibility and volume scaling), and eigenvalues/eigenvectors (values and directions preserved under a linear transformation, up to scaling).</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I work with matrices, I follow a consistent set of operational steps depending on the task:</p>



<ol class="wp-block-list">
<li>I define the matrices involved and confirm their dimensions are compatible with the operation I intend to perform.</li>



<li>For addition or subtraction, I combine corresponding entries of matrices of the same size.</li>



<li>For multiplication, I take the dot product of rows from the first matrix with columns of the second.</li>



<li>For solving a linear system, I convert the system into an augmented matrix and apply row reduction.</li>



<li>For finding eigenvalues, I solve the characteristic equation $\det(A &#8211; \lambda I) = 0$.</li>



<li>I interpret the final numeric result in the context of my original problem — a solution vector, a transformed set of points, or a rank value.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I think of a matrix as encoding a linear transformation between vector spaces. When I multiply a matrix $A$ by a vector $\mathbf{x}$, I am not just performing arithmetic — I am applying a transformation that maps $\mathbf{x}$ from one space to another while preserving linearity (i.e., $A(\alpha \mathbf{x} + \beta \mathbf{y}) = \alpha A\mathbf{x} + \beta A\mathbf{y}$). I rely on this internal logic whenever I compose transformations (matrix multiplication is composition), invert transformations (matrix inversion undoes a mapping), or decompose transformations into simpler pieces (eigendecomposition, singular value decomposition). The mechanism underlying nearly every matrix algorithm is repeated application of these linear combination rules, executed systematically over rows and columns.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define the determinant of a $2\times 2$ matrix as:</p>



<p class="wp-block-paragraph">$$ \det \begin{pmatrix} a &amp; b \ c &amp; d \end{pmatrix} = ad &#8211; bc $$</p>



<p class="wp-block-paragraph">For an $n \times n$ matrix, I use the general Laplace expansion:</p>



<p class="wp-block-paragraph">$$ \det(A) = \sum_{j=1}^{n} (-1)^{i+j} a_{ij} M_{ij} $$</p>



<p class="wp-block-paragraph">where $M_{ij}$ is the minor obtained by deleting row $i$ and column $j$.</p>



<p class="wp-block-paragraph">I define the inverse of $A$, when it exists, as the matrix $A^{-1}$ satisfying:</p>



<p class="wp-block-paragraph">$$ AA^{-1} = A^{-1}A = I $$</p>



<p class="wp-block-paragraph">I compute it for a $2\times 2$ matrix as:</p>



<p class="wp-block-paragraph">$$ A^{-1} = \frac{1}{\det(A)} \begin{pmatrix} d &amp; -b \ -c &amp; a \end{pmatrix} $$</p>



<p class="wp-block-paragraph">I define eigenvalues $\lambda$ and eigenvectors $\mathbf{v}$ by the relation:</p>



<p class="wp-block-paragraph">$$ A\mathbf{v} = \lambda \mathbf{v} $$</p>



<p class="wp-block-paragraph">which I solve using the characteristic polynomial:</p>



<p class="wp-block-paragraph">$$ \det(A &#8211; \lambda I) = 0 $$</p>



<p class="wp-block-paragraph">I prove that matrix multiplication is associative, $(AB)C = A(BC)$, by expanding both sides using summation notation and showing the resulting triple sums are identical after reordering, which relies on the associativity and commutativity of scalar addition and multiplication.</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Start: Define matrices A and B] --> B{What operation?}
    B -->|Addition/Subtraction| C[Combine corresponding entries]
    B -->|Multiplication| D[Compute row-column dot products]
    B -->|Solve Ax = b| E[Form augmented matrix]
    E --> F[Apply Gaussian elimination]
    F --> G[Back-substitute for solution]
    D --> H[Return result matrix]
    C --> H
    G --> H[Return result]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write the pseudocode for multiplying two matrices as follows:</p>



<pre class="wp-block-code"><code>function MATRIX_MULTIPLY(A, B):
    m = rows(A)
    n = cols(A)      // must equal rows(B)
    p = cols(B)
    C = new matrix of size m x p, initialized to 0

    for i from 1 to m:
        for j from 1 to p:
            sum = 0
            for k from 1 to n:
                sum = sum + A&#91;i]&#91;k] * B&#91;k]&#91;j]
            C&#91;i]&#91;j] = sum

    return C
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I take two matrices:</p>



<p class="wp-block-paragraph">$$ A = \begin{pmatrix} 1 &amp; 2 \ 3 &amp; 4 \end{pmatrix}, \quad B = \begin{pmatrix} 5 &amp; 6 \ 7 &amp; 8 \end{pmatrix} $$</p>



<p class="wp-block-paragraph">I compute $C = AB$ entry by entry:</p>



<ul class="wp-block-list">
<li>$C_{11} = 1\cdot5 + 2\cdot7 = 5 + 14 = 19$</li>



<li>$C_{12} = 1\cdot6 + 2\cdot8 = 6 + 16 = 22$</li>



<li>$C_{21} = 3\cdot5 + 4\cdot7 = 15 + 28 = 43$</li>



<li>$C_{22} = 3\cdot6 + 4\cdot8 = 18 + 32 = 50$</li>
</ul>



<p class="wp-block-paragraph">I arrive at:</p>



<p class="wp-block-paragraph">$$ C = \begin{pmatrix} 19 &amp; 22 \ 43 &amp; 50 \end{pmatrix} $$</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I analyze the standard matrix multiplication algorithm as requiring $O(n^3)$ operations for two $n \times n$ matrices, since I compute $n^2$ entries, each requiring $n$ multiplications and additions. In the best, average, and worst cases, this remains $O(n^3)$ for the naive algorithm, since I always perform the same number of operations regardless of the actual values in the matrix. I note that faster algorithms exist, such as Strassen&#8217;s algorithm at approximately $O(n^{2.807})$, and the theoretical Coppersmith–Winograd-style algorithms that approach $O(n^{2.371})$, though I rarely use these in practice due to large constant factors and numerical instability.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(m \times n)$ space to store an $m \times n$ matrix. For operations like addition, I need additional $O(m \times n)$ space for the result unless I overwrite one of the inputs. For multiplication, I need $O(m \times p)$ space for the result matrix. When I perform Gaussian elimination or LU decomposition, I can often work in place, reusing the original matrix&#8217;s storage, which keeps my auxiliary space requirement at $O(1)$ beyond the input itself, though a numerically safer implementation may use $O(n^2)$ extra space to preserve the original matrix.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the correctness of matrix multiplication directly from its definition as an encoding of composed linear maps: if $A$ represents a transformation $T_A$ and $B$ represents $T_B$, then $AB$ represents $T_A \circ T_B$, and I verify this by checking that applying $(AB)\mathbf{x}$ produces the same result as applying $B$ first and then $A$. For Gaussian elimination, I confirm correctness by noting that each row operation (swapping rows, scaling a row, adding a multiple of one row to another) preserves the solution set of the linear system, so the final reduced form has exactly the same solutions as the original system.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I can represent complex systems of equations and transformations compactly.</li>



<li>I gain access to a mature, well-studied algebraic structure with predictable rules.</li>



<li>I can leverage highly optimized libraries (BLAS, LAPACK) for fast numerical computation.</li>



<li>I can decompose matrices (LU, QR, SVD) to simplify otherwise difficult problems.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I encounter cubic-time complexity for naive multiplication, which becomes expensive for very large matrices.</li>



<li>I face numerical instability issues, especially with ill-conditioned matrices where small input errors cause large output errors.</li>



<li>I need significant memory for dense matrices, which becomes a bottleneck at scale.</li>



<li>I find some operations, like computing determinants of very large matrices, computationally impractical without specialized techniques.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I use matrices extensively in:</p>



<ul class="wp-block-list">
<li><strong>Computer graphics</strong>: representing rotations, translations, and projections of 3D objects.</li>



<li><strong>Machine learning</strong>: representing datasets, weight parameters in neural networks, and performing forward/backward propagation.</li>



<li><strong>Physics</strong>: representing quantum states and operators in matrix mechanics.</li>



<li><strong>Economics</strong>: modeling input-output relationships between industries (Leontief models).</li>



<li><strong>Cryptography</strong>: Hill cipher and other matrix-based encoding schemes.</li>



<li><strong>Network analysis</strong>: adjacency and Laplacian matrices for graphs.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement matrix multiplication in C below, with comments explaining each part:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;stdlib.h>

// I allocate a matrix dynamically given rows and columns
int** allocateMatrix(int rows, int cols) {
    int** mat = (int**)malloc(rows * sizeof(int*));
    for (int i = 0; i &lt; rows; i++) {
        mat&#91;i&#93; = (int*)malloc(cols * sizeof(int));
    }
    return mat;
}

// I multiply matrix A (m x n) with matrix B (n x p), producing C (m x p)
void multiplyMatrices(int** A, int** B, int** C, int m, int n, int p) {
    for (int i = 0; i &lt; m; i++) {
        for (int j = 0; j &lt; p; j++) {
            C&#91;i&#93;&#91;j&#93; = 0;
            for (int k = 0; k &lt; n; k++) {
                C&#91;i&#93;&#91;j&#93; += A&#91;i&#93;&#91;k&#93; * B&#91;k&#93;&#91;j&#93;;
            }
        }
    }
}

void printMatrix(int** mat, int rows, int cols) {
    for (int i = 0; i &lt; rows; i++) {
        for (int j = 0; j &lt; cols; j++) {
            printf("%d ", mat&#91;i&#93;&#91;j&#93;);
        }
        printf("\n");
    }
}

int main() {
    int m = 2, n = 2, p = 2;

    int** A = allocateMatrix(m, n);
    int** B = allocateMatrix(n, p);
    int** C = allocateMatrix(m, p);

    // I initialize A and B with sample values
    A&#91;0&#93;&#91;0&#93; = 1; A&#91;0&#93;&#91;1&#93; = 2;
    A&#91;1&#93;&#91;0&#93; = 3; A&#91;1&#93;&#91;1&#93; = 4;

    B&#91;0&#93;&#91;0&#93; = 5; B&#91;0&#93;&#91;1&#93; = 6;
    B&#91;1&#93;&#91;0&#93; = 7; B&#91;1&#93;&#91;1&#93; = 8;

    multiplyMatrices(A, B, C, m, n, p);

    printf("Result matrix C:\n");
    printMatrix(C, m, p);

    // I free allocated memory to avoid leaks
    for (int i = 0; i &lt; m; i++) free(A&#91;i&#93;);
    for (int i = 0; i &lt; n; i++) free(B&#91;i&#93;);
    for (int i = 0; i &lt; m; i++) free(C&#91;i&#93;);
    free(A); free(B); free(C);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdlib.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I allocate a matrix dynamically given rows and columns</span></span>
<span class="line"><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">allocateMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rows</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">cols</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> mat </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int**</span><span style="color: #ECEFF4">)</span><span style="color: #88C0D0">malloc</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">rows </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">sizeof</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int*</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> rows</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        mat</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int*</span><span style="color: #ECEFF4">)</span><span style="color: #88C0D0">malloc</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">cols </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">sizeof</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> mat</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I multiply matrix A (m x n) with matrix B (n x p), producing C (m x p)</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">multiplyMatrices</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">A</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">B</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">C</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">p</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> p</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            C</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> k </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> k </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> k</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                C</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">k</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">k</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">printMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mat</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rows</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">cols</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> rows</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> cols</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%d </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> mat</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> p </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> A </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">allocateMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> n</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> B </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">allocateMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> p</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int**</span><span style="color: #D8DEE9FF"> C </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">allocateMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> p</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I initialize A and B with sample values</span></span>
<span class="line"><span style="color: #D8DEE9FF">    A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">6</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">7</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">multiplyMatrices</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">A</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> B</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> C</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> p</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Result matrix C:</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printMatrix</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">C</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> p</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I free allocated memory to avoid leaks</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">A</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">B</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">C</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">A</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">B</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">free</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">C</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I use the following input matrices:</p>



<pre class="wp-block-code"><code>A = 
1 2
3 4

B = 
5 6
7 8
</code></pre>



<p class="wp-block-paragraph">I expect the program to produce this output:</p>



<pre class="wp-block-code"><code>Result matrix C:
19 22
43 50
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<p class="wp-block-paragraph">I improve matrix computation performance through several techniques:</p>



<ul class="wp-block-list">
<li><strong>Blocked (tiled) multiplication</strong>: I divide matrices into smaller blocks that fit into CPU cache, reducing memory latency.</li>



<li><strong>Strassen&#8217;s algorithm</strong>: I recursively divide matrices to reduce the multiplication count from 8 to 7 per recursive step, lowering the exponent from 3 to about 2.807.</li>



<li><strong>Parallelization</strong>: I distribute row/column computations across multiple threads or GPU cores.</li>



<li><strong>Sparse matrix representations</strong>: I store only nonzero entries (using formats like CSR or CSC) when the matrix has many zeros, saving both time and space.</li>



<li><strong>Vectorization (SIMD)</strong>: I use CPU vector instructions to perform multiple multiplications simultaneously.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes forget to check that matrix dimensions are compatible before multiplying, which leads to undefined behavior in code.</li>



<li>I confuse row-major and column-major storage order, which can silently produce transposed or incorrect results.</li>



<li>I overlook numerical precision issues when working with floating-point matrices, especially in determinant or inverse calculations.</li>



<li>I fail to free dynamically allocated memory in C, leading to memory leaks in long-running programs.</li>



<li>I mistakenly assume matrix multiplication is commutative, when in fact $AB \neq BA$ in general.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Gilbert Strang, <em>Introduction to Linear Algebra</em>: https://math.mit.edu/~gs/linearalgebra/</li>



<li>MIT OpenCourseWare, 18.06 Linear Algebra: https://ocw.mit.edu/courses/18-06-linear-algebra-spring-2010/</li>



<li>Cayley, A. (1858). &#8220;A Memoir on the Theory of Matrices.&#8221; Philosophical Transactions of the Royal Society: https://royalsocietypublishing.org/doi/10.1098/rstl.1858.0002</li>



<li>LAPACK Users&#8217; Guide: https://www.netlib.org/lapack/lug/</li>



<li>Golub, G. H., &amp; Van Loan, C. F. <em>Matrix Computations</em>: https://jhupbooks.press.jhu.edu/title/matrix-computations</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/matrices-in-mathematics-a-comprehensive-guide-with-applications/">Matrices in Mathematics: A Comprehensive Guide with Applications</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/matrices-in-mathematics-a-comprehensive-guide-with-applications/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10901</post-id>	</item>
		<item>
		<title>Counting and Probability: A Complete Guide to Combinatorics and Probability Theory</title>
		<link>https://awjunaid.com/algorithm/counting-and-probability-a-complete-guide-to-combinatorics-and-probability-theory/</link>
					<comments>https://awjunaid.com/algorithm/counting-and-probability-a-complete-guide-to-combinatorics-and-probability-theory/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 17:03:34 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10898</guid>

					<description><![CDATA[<p>I use counting and probability whenever I need to reason about how many ways something can happen and&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/counting-and-probability-a-complete-guide-to-combinatorics-and-probability-theory/">Counting and Probability: A Complete Guide to Combinatorics and Probability Theory</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use counting and probability whenever I need to reason about how many ways something can happen and how likely each outcome is. I think of combinatorics as the mathematics of counting arrangements, selections, and structures, while probability builds on top of that counting to assign likelihoods to events. I find this pairing important because it underlies algorithm analysis (expected running time), statistics, cryptography, machine learning, and everyday decision-making under uncertainty.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace combinatorics back to ancient civilizations — Indian mathematicians studied permutations and combinations as early as the 6th century BCE in relation to Sanskrit prosody, and the Chinese and Arab mathematicians independently developed binomial coefficients. I see probability theory formally emerge much later, in the 17th century, through correspondence between Blaise Pascal and Pierre de Fermat in 1654, prompted by gambling problems posed by the Chevalier de Méré. I note that Jacob Bernoulli&#8217;s <em>Ars Conjectandi</em> (published posthumously in 1713) formalized the law of large numbers, and Pierre-Simon Laplace&#8217;s <em>Théorie Analytique des Probabilités</em> (1812) unified much of classical probability. In the 20th century, I see Andrey Kolmogorov&#8217;s 1933 axiomatization giving probability its modern, rigorous measure-theoretic foundation.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use counting techniques to answer questions like &#8220;how many ways can I arrange these objects?&#8221; or &#8220;how many subsets satisfy this property?&#8221; I use probability to answer &#8220;how likely is this event, given the space of possible outcomes?&#8221; Both fields exist to let me reason precisely about uncertainty and combinatorial structure rather than relying on intuition, which I find frequently misleads people (as in the famous birthday paradox).</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I rely on the following foundational ideas:</p>



<ul class="wp-block-list">
<li><strong>Permutation</strong>: an ordered arrangement of objects.</li>



<li><strong>Combination</strong>: an unordered selection of objects.</li>



<li><strong>Sample space</strong> ($S$): the set of all possible outcomes of an experiment.</li>



<li><strong>Event</strong> ($E$): a subset of the sample space.</li>



<li><strong>Probability function</strong> $P$: assigns a number in $[0,1]$ to each event, satisfying Kolmogorov&#8217;s axioms.</li>



<li><strong>Random variable</strong>: a function mapping outcomes to numerical values.</li>



<li><strong>Independence</strong>: two events $A, B$ are independent if $P(A \cap B) = P(A)P(B)$.</li>



<li><strong>Conditional probability</strong>: the probability of an event given that another has occurred.</li>
</ul>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I approach a counting or probability problem, I follow this general process:</p>



<ol class="wp-block-list">
<li>I identify the sample space or the set of objects being arranged/selected.</li>



<li>I determine whether order matters (permutation) or not (combination).</li>



<li>I check whether repetition is allowed.</li>



<li>I apply the appropriate counting formula or the multiplication/addition principle.</li>



<li>For probability, I define the event of interest as a subset of the sample space.</li>



<li>I compute the probability as the ratio of favorable outcomes to total outcomes (for equally likely outcomes), or I use conditional/Bayesian reasoning for dependent events.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of counting through two foundational principles: the <strong>rule of sum</strong> (if two events cannot occur together, the number of ways either can happen is the sum of the individual ways) and the <strong>rule of product</strong> (if one event can happen in $m$ ways and a second, independent event in $n$ ways, both can happen together in $m \times n$ ways). Probability builds directly on this counting foundation: once I know how many total outcomes exist and how many satisfy my event, I express probability as a ratio, then use axiomatic rules (additivity over disjoint events, complement rule) to combine probabilities of composite events.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define the number of permutations of $n$ distinct objects taken $r$ at a time as:</p>



<p class="wp-block-paragraph">$$ P(n, r) = \frac{n!}{(n-r)!} $$</p>



<p class="wp-block-paragraph">I define the number of combinations as:</p>



<p class="wp-block-paragraph">$$ C(n, r) = \binom{n}{r} = \frac{n!}{r!(n-r)!} $$</p>



<p class="wp-block-paragraph">I state the binomial theorem as:</p>



<p class="wp-block-paragraph">$$ (x + y)^n = \sum_{k=0}^{n} \binom{n}{k} x^{n-k} y^k $$</p>



<p class="wp-block-paragraph">I define probability using Kolmogorov&#8217;s axioms: for a sample space $S$ and event $A \subseteq S$,</p>



<p class="wp-block-paragraph">$$ 0 \le P(A) \le 1, \quad P(S) = 1, \quad P\left(\bigcup_i A_i\right) = \sum_i P(A_i) \text{ for disjoint } A_i $$</p>



<p class="wp-block-paragraph">I define conditional probability as:</p>



<p class="wp-block-paragraph">$$ P(A \mid B) = \frac{P(A \cap B)}{P(B)}, \quad P(B) &gt; 0 $$</p>



<p class="wp-block-paragraph">I state Bayes&#8217; theorem as:</p>



<p class="wp-block-paragraph">$$ P(A \mid B) = \frac{P(B \mid A) P(A)}{P(B)} $$</p>



<p class="wp-block-paragraph">I define the expected value of a discrete random variable $X$ as:</p>



<p class="wp-block-paragraph">$$ E[X] = \sum_{i} x_i P(X = x_i) $$</p>



<p class="wp-block-paragraph">and variance as:</p>



<p class="wp-block-paragraph">$$ \text{Var}(X) = E[(X &#8211; E[X])^2] = E[X^2] &#8211; (E[X])^2 $$</p>



<p class="wp-block-paragraph">I prove the addition rule for non-disjoint events using inclusion-exclusion:</p>



<p class="wp-block-paragraph">$$ P(A \cup B) = P(A) + P(B) &#8211; P(A \cap B) $$</p>



<p class="wp-block-paragraph">which follows because summing $P(A) + P(B)$ double-counts the overlap $P(A \cap B)$, so I subtract it once to correct the count.</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Define the problem] --> B{Counting or Probability?}
    B -->|Counting| C{Order matters?}
    C -->|Yes| D[Use Permutation formula]
    C -->|No| E[Use Combination formula]
    B -->|Probability| F[Define sample space S and event A]
    F --> G{Events independent?}
    G -->|Yes| H[Multiply individual probabilities]
    G -->|No| I[Apply conditional probability / Bayes theorem]
    D --> J[Return result]
    E --> J
    H --> J
    I --> J
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for computing combinations efficiently (avoiding factorial overflow) below:</p>



<pre class="wp-block-code"><code>function COMBINATION(n, r):
    if r &gt; n - r:
        r = n - r          // exploit symmetry C(n, r) = C(n, n-r)

    result = 1
    for i from 0 to r - 1:
        result = result * (n - i)
        result = result / (i + 1)

    return result
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I compute the probability of drawing 2 aces from a standard 52-card deck when drawing 5 cards without replacement.</p>



<p class="wp-block-paragraph">I first compute the total number of 5-card hands:</p>



<p class="wp-block-paragraph">$$ \binom{52}{5} = 2{,}598{,}960 $$</p>



<p class="wp-block-paragraph">I then compute the number of favorable hands (2 aces from 4, and 3 non-aces from 48):</p>



<p class="wp-block-paragraph">$$ \binom{4}{2} \times \binom{48}{3} = 6 \times 17{,}296 = 103{,}776 $$</p>



<p class="wp-block-paragraph">I compute the probability as:</p>



<p class="wp-block-paragraph">$$ P(\text{exactly 2 aces}) = \frac{103{,}776}{2{,}598{,}960} \approx 0.0399 $$</p>



<p class="wp-block-paragraph">I conclude there is roughly a 3.99% chance of this event.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I compute $n!$ or $\binom{n}{r}$ using an iterative approach in $O(r)$ time when I use the incremental multiplication formula rather than computing full factorials, which would cost $O(n)$ each and risk overflow. For probability calculations involving enumeration of a sample space, I note that complexity depends heavily on the structure — enumerating all subsets is $O(2^n)$, while computing conditional probabilities from a precomputed table is $O(1)$. Best, average, and worst cases for combination computation are all $O(r)$ since the loop always runs a fixed number of iterations.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require only $O(1)$ auxiliary space for the iterative combination formula, since I maintain a running result rather than storing a full factorial table. If I precompute Pascal&#8217;s Triangle up to row $n$ for repeated queries, I require $O(n^2)$ space, though I can reduce this to $O(n)$ by keeping only the current and previous rows.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the permutation formula by noting that I have $n$ choices for the first position, $n-1$ for the second, and so on down to $n &#8211; r + 1$ for the $r$-th position, and multiplying these together gives $\frac{n!}{(n-r)!}$. I justify the combination formula by observing that each combination of $r$ objects corresponds to exactly $r!$ permutations (since order does not matter within the selection), so I divide the permutation count by $r!$. For probability, correctness follows directly from Kolmogorov&#8217;s axioms, from which I derive all further identities like the addition rule and Bayes&#8217; theorem through pure logical/algebraic manipulation.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I gain exact, verifiable answers to questions about arrangements and likelihoods rather than relying on guesswork.</li>



<li>I can model complex real-world uncertainty (weather, genetics, finance) using a shared mathematical language.</li>



<li>Counting techniques give me a foundation for analyzing algorithm complexity and combinatorial structures.</li>



<li>Probability lets me quantify risk and make principled decisions under uncertainty.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find some counting problems (like counting objects under complex constraints) become combinatorially explosive and hard to compute directly.</li>



<li>I encounter probability paradoxes and misinterpretations (like the base rate fallacy) that require careful framing to avoid errors.</li>



<li>Continuous probability distributions require calculus, which raises the barrier to entry compared to discrete counting.</li>



<li>Certain combinatorial identities and proofs are non-obvious and require creative bijective or inductive arguments.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I use counting and probability in:</p>



<ul class="wp-block-list">
<li><strong>Cryptography</strong>: computing key space sizes and brute-force attack feasibility.</li>



<li><strong>Machine learning</strong>: Bayesian inference, Naive Bayes classifiers, and probabilistic graphical models.</li>



<li><strong>Algorithm analysis</strong>: expected running time of randomized algorithms (like randomized quicksort).</li>



<li><strong>Genetics</strong>: computing probabilities of inherited traits using Punnett squares and combinatorics.</li>



<li><strong>Finance</strong>: modeling risk, option pricing (via stochastic processes), and portfolio theory.</li>



<li><strong>Game design and gambling</strong>: computing odds, expected payouts, and fair game structures.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement a function to compute combinations and use it to calculate a hypergeometric probability, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>

// I compute C(n, r) iteratively to avoid overflow from large factorials
double combination(int n, int r) {
    if (r > n - r) {
        r = n - r; // I exploit symmetry to reduce iterations
    }
    double result = 1.0;
    for (int i = 0; i &lt; r; i++) {
        result *= (n - i);
        result /= (i + 1);
    }
    return result;
}

int main() {
    // I compute the probability of drawing exactly 2 aces in a 5-card hand
    double totalHands = combination(52, 5);
    double favorableHands = combination(4, 2) * combination(48, 3);

    double probability = favorableHands / totalHands;

    printf("Total hands: %.0f\n", totalHands);
    printf("Favorable hands: %.0f\n", favorableHands);
    printf("Probability of exactly 2 aces: %.4f\n", probability);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I compute C(n, r) iteratively to avoid overflow from large factorials</span></span>
<span class="line"><span style="color: #81A1C1">double</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">combination</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">r</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">r </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> r</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        r </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> r</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I exploit symmetry to reduce iterations</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">double</span><span style="color: #D8DEE9FF"> result </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1.0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> r</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        result </span><span style="color: #81A1C1">*=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">n </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> i</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        result </span><span style="color: #81A1C1">/=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">i </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> result</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I compute the probability of drawing exactly 2 aces in a 5-card hand</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">double</span><span style="color: #D8DEE9FF"> totalHands </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">combination</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">52</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">double</span><span style="color: #D8DEE9FF"> favorableHands </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">combination</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">combination</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">48</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">double</span><span style="color: #D8DEE9FF"> probability </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> favorableHands </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> totalHands</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Total hands: %.0f</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> totalHands</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Favorable hands: %.0f</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> favorableHands</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Probability of exactly 2 aces: %.4f</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> probability</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I run the program with the fixed values (n=52, r=5, aces=4, non-aces=48) hardcoded, producing:</p>



<pre class="wp-block-code"><code>Total hands: 2598960
Favorable hands: 103776
Probability of exactly 2 aces: 0.0399
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I precompute Pascal&#8217;s Triangle when I need many repeated combination queries, turning each query into an $O(1)$ lookup after $O(n^2)$ preprocessing.</li>



<li>I use logarithms (summing $\log$ factorials) when factorials would overflow standard integer or floating-point types.</li>



<li>I apply modular arithmetic (computing $\binom{n}{r} \bmod p$) using modular inverses when working within finite fields, common in competitive programming.</li>



<li>I use memoization for recursive probability computations (like Markov chain state probabilities) to avoid redundant recomputation.</li>



<li>I apply Monte Carlo simulation as an approximation technique when exact probability computation is analytically intractable.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes confuse permutations and combinations, applying the wrong formula when order does or does not matter.</li>



<li>I forget to account for overlapping events, leading to double-counting instead of applying inclusion-exclusion.</li>



<li>I incorrectly assume events are independent when they are not, which invalidates simple multiplication of probabilities.</li>



<li>I mishandle &#8220;at least one&#8221; problems by forgetting the complement rule, $P(\text{at least one}) = 1 &#8211; P(\text{none})$.</li>



<li>I let factorial computations overflow standard data types instead of using the incremental combination formula.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Feller, W. <em>An Introduction to Probability Theory and Its Applications</em>: https://www.wiley.com/en-us/An+Introduction+to+Probability+Theory+and+Its+Applications%2C+Volume+1%2C+3rd+Edition-p-9780471257080</li>



<li>MIT OpenCourseWare, 6.042J Mathematics for Computer Science: https://ocw.mit.edu/courses/6-042j-mathematics-for-computer-science-fall-2010/</li>



<li>Grinstead, C. M., &amp; Snell, J. L. <em>Introduction to Probability</em>: https://math.dartmouth.edu/~prob/prob/prob.pdf</li>



<li>Kolmogorov, A. N. <em>Foundations of the Theory of Probability</em>: https://archive.org/details/foundationsofthe00kolm</li>



<li>Rosen, K. H. <em>Discrete Mathematics and Its Applications</em> (combinatorics chapters): https://www.mheducation.com/highered/product/discrete-mathematics-its-applications-rosen/M9781259676512.html</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/counting-and-probability-a-complete-guide-to-combinatorics-and-probability-theory/">Counting and Probability: A Complete Guide to Combinatorics and Probability Theory</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/counting-and-probability-a-complete-guide-to-combinatorics-and-probability-theory/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10898</post-id>	</item>
		<item>
		<title>Comprehensive Guide to Sets, Relations, Functions, Graphs, and Trees in Discrete Mathematics</title>
		<link>https://awjunaid.com/algorithm/comprehensive-guide-to-sets-relations-functions-graphs-and-trees-in-discrete-mathematics/</link>
					<comments>https://awjunaid.com/algorithm/comprehensive-guide-to-sets-relations-functions-graphs-and-trees-in-discrete-mathematics/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 16:59:52 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10895</guid>

					<description><![CDATA[<p>I treat sets, relations, functions, graphs, and trees as the backbone vocabulary of discrete mathematics. I use sets&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/comprehensive-guide-to-sets-relations-functions-graphs-and-trees-in-discrete-mathematics/">Comprehensive Guide to Sets, Relations, Functions, Graphs, and Trees in Discrete Mathematics</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I treat sets, relations, functions, graphs, and trees as the backbone vocabulary of discrete mathematics. I use sets to group objects, relations to connect them, functions to map between them, graphs to model networks of connections, and trees as a special, hierarchical case of graphs. I find that nearly every data structure and algorithm I encounter in computer science rests on one or more of these five concepts, which is why I consider them foundational rather than optional theory.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace set theory to Georg Cantor&#8217;s work in the 1870s, where he formalized the notion of infinite sets and cardinality, sparking both a mathematical revolution and philosophical controversy. I see relations and functions formalized alongside set theory, especially through the work of Giuseppe Peano and later the Bourbaki group, who grounded functions as special sets of ordered pairs. Graph theory, I note, began with Leonhard Euler&#8217;s 1736 solution to the Seven Bridges of Königsberg problem, widely regarded as the founding result of the field. Tree structures emerged from both graph theory and Arthur Cayley&#8217;s 1857 work counting tree structures related to chemical isomers, and later became a core structure in computer science through the development of data structures in the mid-20th century.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use these structures to solve the general problem of representing and reasoning about collections of objects and their relationships. Sets let me answer &#8220;what belongs together?&#8221; Relations let me answer &#8220;how are these objects connected?&#8221; Functions let me answer &#8220;what does this input map to?&#8221; Graphs let me model arbitrary networks (social networks, road maps, dependency graphs), and trees let me model strictly hierarchical relationships (file systems, organizational charts, decision processes) efficiently.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph"><strong>Sets</strong>: I define a set as an unordered collection of distinct elements, denoted $A = {1, 2, 3}$. I use operations like union ($\cup$), intersection ($\cap$), difference ($-$), and complement.</p>



<p class="wp-block-paragraph"><strong>Relations</strong>: I define a relation $R$ between sets $A$ and $B$ as a subset of $A \times B$. I classify relations by properties: reflexive, symmetric, antisymmetric, and transitive. A relation that is reflexive, symmetric, and transitive is an <strong>equivalence relation</strong>.</p>



<p class="wp-block-paragraph"><strong>Functions</strong>: I define a function $f: A \to B$ as a relation where every element of $A$ maps to exactly one element of $B$. I classify functions as injective (one-to-one), surjective (onto), or bijective (both).</p>



<p class="wp-block-paragraph"><strong>Graphs</strong>: I define a graph $G = (V, E)$ as a set of vertices $V$ and edges $E$ connecting pairs of vertices. I distinguish directed vs undirected, weighted vs unweighted, and cyclic vs acyclic graphs.</p>



<p class="wp-block-paragraph"><strong>Trees</strong>: I define a tree as a connected, acyclic graph. I use terms like root, parent, child, leaf, depth, and height to describe tree structure.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">I approach problems in this domain through a consistent process:</p>



<ol class="wp-block-list">
<li>I identify which structure best models my problem (set membership, pairwise relationship, mapping, network, or hierarchy).</li>



<li>For sets, I determine which operations (union, intersection, etc.) answer my question.</li>



<li>For relations, I check the defining properties (reflexivity, symmetry, transitivity) to classify the relation.</li>



<li>For functions, I verify whether the mapping is well-defined and check injectivity/surjectivity.</li>



<li>For graphs, I choose a representation (adjacency matrix or list) and apply a traversal or search algorithm (BFS, DFS).</li>



<li>For trees, I apply recursive algorithms that exploit the hierarchical, acyclic structure (traversals, balancing, searching).</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of these structures as being built on top of one another: a relation is fundamentally a subset of a Cartesian product (itself built from sets), a function is a constrained relation, and a graph is a generalized relation visualized as vertices and edges. A tree is a graph with the additional constraint of connectivity and acyclicity, which gives it the property that there exists exactly one path between any two nodes. I rely on this nested structure whenever I reason about correctness — properties proven for general relations often specialize cleanly to functions, and properties proven for general graphs often specialize to trees.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define set cardinality using the inclusion-exclusion principle for two sets:</p>



<p class="wp-block-paragraph">$$ |A \cup B| = |A| + |B| &#8211; |A \cap B| $$</p>



<p class="wp-block-paragraph">I define a relation&#8217;s transitive closure $R^+$ as the smallest transitive relation containing $R$, computed as:</p>



<p class="wp-block-paragraph">$$ R^+ = \bigcup_{k=1}^{\infty} R^k $$</p>



<p class="wp-block-paragraph">I define function composition for $f: A \to B$ and $g: B \to C$ as:</p>



<p class="wp-block-paragraph">$$ (g \circ f)(x) = g(f(x)) $$</p>



<p class="wp-block-paragraph">I state the Handshaking Lemma for graphs:</p>



<p class="wp-block-paragraph">$$ \sum_{v \in V} \deg(v) = 2|E| $$</p>



<p class="wp-block-paragraph">I define a tree with $n$ vertices as having exactly:</p>



<p class="wp-block-paragraph">$$ |E| = n &#8211; 1 $$</p>



<p class="wp-block-paragraph">edges, which I prove by induction: a single-vertex tree has 0 edges ($n-1 = 0$), and adding any new vertex to a tree must add exactly one edge to preserve connectivity without creating a cycle, so if a tree with $k$ vertices has $k-1$ edges, a tree with $k+1$ vertices has $k$ edges.</p>



<p class="wp-block-paragraph">I define the height $h$ of a balanced binary tree with $n$ nodes as bounded by:</p>



<p class="wp-block-paragraph">$$ h = \lceil \log_2(n+1) \rceil &#8211; 1 $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Problem: Model relationships between objects] --> B{What kind of structure?}
    B -->|Grouping objects| C[Use Sets]
    B -->|Pairwise connection| D[Use Relations]
    B -->|Input to output mapping| E[Use Functions]
    B -->|Arbitrary network| F[Use Graphs]
    F --> G{Connected and Acyclic?}
    G -->|Yes| H[Special case: Tree]
    G -->|No| I[General Graph]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for a breadth-first traversal of a tree, which I use to process nodes level by level:</p>



<pre class="wp-block-code"><code>function BFS_TREE(root):
    if root is null:
        return

    queue = new empty queue
    enqueue(queue, root)

    while queue is not empty:
        node = dequeue(queue)
        visit(node)

        for each child in node.children:
            enqueue(queue, child)
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I demonstrate with a small binary tree:</p>



<pre class="wp-block-code"><code>        1
       / \
      2   3
     / \
    4   5
</code></pre>



<p class="wp-block-paragraph">I perform a breadth-first traversal:</p>



<ol class="wp-block-list">
<li>I enqueue node 1, then dequeue and visit it. I enqueue its children, 2 and 3.</li>



<li>I dequeue and visit 2. I enqueue its children, 4 and 5.</li>



<li>I dequeue and visit 3. It has no children.</li>



<li>I dequeue and visit 4. It has no children.</li>



<li>I dequeue and visit 5. It has no children.</li>
</ol>



<p class="wp-block-paragraph">I record the traversal order as: 1, 2, 3, 4, 5.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I analyze breadth-first traversal of a tree with $n$ nodes as $O(n)$ in the best, average, and worst case, since I visit every node exactly once and perform $O(1)$ work enqueuing/dequeuing each. For general graph traversal (BFS/DFS) using an adjacency list, I get $O(V + E)$, where $V$ is the number of vertices and $E$ the number of edges, since I visit each vertex once and examine each edge once. Set operations like union and intersection run in $O(|A| + |B|)$ when implemented with hash-based sets, or $O(|A| \log|A| + |B| \log |B|)$ with sorted/tree-based sets.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(V)$ space for the queue in BFS in the worst case (a wide tree/graph where most nodes are at the same level), and $O(h)$ space for DFS recursion, where $h$ is the height of the tree/graph (representing the maximum call stack depth). For representing a graph, I need $O(V^2)$ space with an adjacency matrix or $O(V + E)$ space with an adjacency list, which I prefer for sparse graphs.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify BFS correctness by induction on levels: I assume all nodes at depth $d$ are correctly enqueued before processing begins on depth $d+1$, and I show that since I only enqueue a node&#8217;s children after visiting the node itself, all nodes at depth $d$ are dequeued (and their children enqueued) before any node at depth $d+1$ is dequeued, preserving level-order correctness. I justify the tree edge-count identity ($|E| = n &#8211; 1$) by structural induction, as shown in the Mathematical Foundation section. I justify equivalence relation partitioning by showing that reflexivity, symmetry, and transitivity together guarantee that the equivalence classes I generate are disjoint and their union is the entire set.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I gain a unified, precise vocabulary for describing relationships between objects across many domains.</li>



<li>Trees give me logarithmic-time operations when balanced, which I use throughout searching and indexing.</li>



<li>Graphs let me model essentially any network structure, from social graphs to transportation systems.</li>



<li>Set theory gives me a rigorous foundation that underlies nearly all of formal mathematics and logic.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find unbalanced trees can degrade to linear-time operations, losing their efficiency advantage.</li>



<li>Dense graphs require significant memory ($O(V^2)$) if I use adjacency matrices.</li>



<li>Some relation properties (like computing transitive closure) can be computationally expensive for large relations.</li>



<li>Reasoning about infinite sets introduces subtleties (different cardinalities of infinity) that can be counterintuitive.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply these concepts in:</p>



<ul class="wp-block-list">
<li><strong>Databases</strong>: relations directly correspond to database tables in relational algebra.</li>



<li><strong>File systems</strong>: directory structures are modeled as trees.</li>



<li><strong>Networking</strong>: routing protocols model networks as weighted graphs.</li>



<li><strong>Compilers</strong>: abstract syntax trees represent parsed program structure.</li>



<li><strong>Social networks</strong>: graphs model friendships, followers, and influence propagation.</li>



<li><strong>Type systems</strong>: functions model well-typed mappings between input and output types in programming languages.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement a simple binary tree with BFS traversal, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;stdlib.h>

typedef struct Node {
    int data;
    struct Node* left;
    struct Node* right;
} Node;

// I create a new tree node with given data
Node* createNode(int data) {
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->left = node->right = NULL;
    return node;
}

// I implement a simple queue using an array for BFS
#define MAX_QUEUE 100

void bfsTraversal(Node* root) {
    if (root == NULL) return;

    Node* queue&#91;MAX_QUEUE&#93;;
    int front = 0, rear = 0;

    queue&#91;rear++&#93; = root;

    while (front &lt; rear) {
        Node* current = queue&#91;front++&#93;;
        printf("%d ", current->data); // I visit the node

        if (current->left != NULL) queue&#91;rear++&#93; = current->left;
        if (current->right != NULL) queue&#91;rear++&#93; = current->right;
    }
    printf("\n");
}

int main() {
    // I build the sample tree from the walkthrough
    Node* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);

    printf("BFS traversal: ");
    bfsTraversal(root);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdlib.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">struct</span><span style="color: #D8DEE9FF"> Node </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> data</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">struct</span><span style="color: #D8DEE9FF"> Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> left</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">struct</span><span style="color: #D8DEE9FF"> Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> right</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> Node</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I create a new tree node with given data</span></span>
<span class="line"><span style="color: #D8DEE9FF">Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> node </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">Node</span><span style="color: #81A1C1">*</span><span style="color: #ECEFF4">)</span><span style="color: #88C0D0">malloc</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">sizeof</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">Node</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">node</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> data</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">node</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">node</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">right</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">NULL;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> node</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I implement a simple queue using an array for BFS</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">MAX_QUEUE</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">100</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">bfsTraversal</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">root</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">root </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">NULL</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> queue</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">MAX_QUEUE</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> front </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> rear </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    queue</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">rear</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> root</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">front </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> rear</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> current </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> queue</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">front</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%d </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">current</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I visit the node</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">current</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">NULL</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> queue</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">rear</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">current</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">current</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">right</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">NULL</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> queue</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">rear</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">current</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">right</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I build the sample tree from the walkthrough</span></span>
<span class="line"><span style="color: #D8DEE9FF">    Node</span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> root </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">root</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">root</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">right</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">root</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">root</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">left</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">right</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">createNode</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">BFS traversal: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">bfsTraversal</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">root</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I build the tree shown in the step-by-step example directly in code (no external input needed), and I expect this output:</p>



<pre class="wp-block-code"><code>BFS traversal: 1 2 3 4 5
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I use self-balancing trees (AVL, Red-Black trees) to guarantee $O(\log n)$ operations regardless of insertion order.</li>



<li>I use hash sets instead of sorted sets when I only need membership testing, reducing operations to average $O(1)$.</li>



<li>I use adjacency lists instead of adjacency matrices for sparse graphs to save memory and speed up traversal.</li>



<li>I use union-find (disjoint set) structures with path compression and union by rank to efficiently manage equivalence classes and connectivity queries.</li>



<li>I use bit-vector representations for sets over small, fixed universes to enable extremely fast set operations via bitwise instructions.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes forget to check all three properties (reflexive, symmetric, transitive) before calling a relation an equivalence relation.</li>



<li>I confuse functions with general relations, forgetting that a function requires exactly one output per input.</li>



<li>I let a binary search tree become unbalanced through repeated sorted insertions, degrading performance to $O(n)$.</li>



<li>I use recursion for deep trees without considering stack overflow risk, instead of an iterative approach with an explicit stack.</li>



<li>I miscount edges or vertices when verifying the tree property $|E| = n &#8211; 1$, especially in disconnected or cyclic graphs mistaken for trees.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Rosen, K. H. <em>Discrete Mathematics and Its Applications</em>: https://www.mheducation.com/highered/product/discrete-mathematics-its-applications-rosen/M9781259676512.html</li>



<li>Cormen, T. H., Leiserson, C. E., Rivest, R. L., &amp; Stein, C. <em>Introduction to Algorithms</em> (graph and tree chapters): https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/</li>



<li>Euler, L. (1736). &#8220;Solutio problematis ad geometriam situs pertinentis&#8221;: https://scholarlycommons.pacific.edu/euler-works/53/</li>



<li>MIT OpenCourseWare, 6.042J Mathematics for Computer Science: https://ocw.mit.edu/courses/6-042j-mathematics-for-computer-science-fall-2010/</li>



<li>Halmos, P. R. <em>Naive Set Theory</em>: https://www.springer.com/gp/book/9780387900926</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/comprehensive-guide-to-sets-relations-functions-graphs-and-trees-in-discrete-mathematics/">Comprehensive Guide to Sets, Relations, Functions, Graphs, and Trees in Discrete Mathematics</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/comprehensive-guide-to-sets-relations-functions-graphs-and-trees-in-discrete-mathematics/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10895</post-id>	</item>
		<item>
		<title>Summations: Essential Formulas, Properties, and Bounding Techniques Explained</title>
		<link>https://awjunaid.com/algorithm/summations-essential-formulas-properties-and-bounding-techniques-explained/</link>
					<comments>https://awjunaid.com/algorithm/summations-essential-formulas-properties-and-bounding-techniques-explained/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 16:55:34 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10892</guid>

					<description><![CDATA[<p>I use summation notation whenever I need to express the addition of a sequence of terms compactly, especially&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/summations-essential-formulas-properties-and-bounding-techniques-explained/">Summations: Essential Formulas, Properties, and Bounding Techniques Explained</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use summation notation whenever I need to express the addition of a sequence of terms compactly, especially when the number of terms is large or variable. I rely on summations constantly when analyzing algorithm running times, proving mathematical identities, and working with series in calculus and discrete mathematics. I consider summation both a notational convenience and a computational tool, since manipulating a sum symbolically often reveals closed-form results I could never obtain by brute-force addition.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the sigma notation ($\sum$) for summation to Leonhard Euler, who introduced it in the 18th century as a compact way to represent sums of series, building on earlier ad hoc notations used by mathematicians studying series convergence. I note that the underlying concept of summing sequences is far older — Archimedes used summation-like reasoning (the method of exhaustion) around 250 BCE to compute areas and volumes, and Indian mathematicians such as Aryabhata derived formulas for sums of squares and cubes around the 5th century CE. I see the formal theory of infinite series developed extensively during the 17th and 18th centuries by Newton, Leibniz, and later Cauchy, who introduced rigorous convergence criteria in the 19th century.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use summation to solve the recurring problem of expressing and simplifying the total of many terms, especially when I want a closed-form expression rather than a term-by-term computation. This becomes essential in algorithm analysis, where I need to compute the total work done across all iterations of a loop, and in combinatorics and probability, where sums naturally arise when totaling over cases.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I define a summation as:</p>



<p class="wp-block-paragraph">$$ \sum_{i=m}^{n} a_i = a_m + a_{m+1} + \cdots + a_n $$</p>



<p class="wp-block-paragraph">I rely on key properties:</p>



<ul class="wp-block-list">
<li><strong>Linearity</strong>: $\sum (a_i + b_i) = \sum a_i + \sum b_i$</li>



<li><strong>Constant factor extraction</strong>: $\sum c \cdot a_i = c \sum a_i$</li>



<li><strong>Splitting</strong>: $\sum_{i=m}^{n} a_i = \sum_{i=m}^{k} a_i + \sum_{i=k+1}^{n} a_i$</li>



<li><strong>Index shifting</strong>: reindexing a sum without changing its value</li>



<li><strong>Telescoping</strong>: sums where consecutive terms cancel, leaving only boundary terms</li>
</ul>



<p class="wp-block-paragraph">I also work extensively with closed-form formulas for arithmetic series, geometric series, and power sums, along with asymptotic bounding techniques that approximate sums using integrals.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I evaluate or bound a summation, I follow these steps:</p>



<ol class="wp-block-list">
<li>I identify the general term $a_i$ and the bounds of summation.</li>



<li>I check whether a known closed-form formula applies (arithmetic, geometric, or power sum).</li>



<li>If no direct formula applies, I look for a telescoping pattern or attempt to manipulate the sum algebraically (splitting, reindexing, substitution).</li>



<li>If an exact closed form is unavailable or unnecessary, I bound the sum using integral approximation or comparison with a known series.</li>



<li>I verify my result, often using induction or a small test case.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand summation manipulation as fundamentally an exercise in reorganizing addition using the associative and commutative properties of arithmetic. Techniques like telescoping work because consecutive terms are constructed to cancel algebraically, leaving only a fixed number of boundary terms regardless of how many terms exist in between. Bounding techniques work because a monotonic function&#8217;s sum can be sandwiched between two integrals, since I can interpret each term as the area of a rectangle that either overestimates or underestimates the corresponding sliver of area under the curve.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I state the arithmetic series formula:</p>



<p class="wp-block-paragraph">$$ \sum_{i=1}^{n} i = \frac{n(n+1)}{2} $$</p>



<p class="wp-block-paragraph">I state the sum of squares:</p>



<p class="wp-block-paragraph">$$ \sum_{i=1}^{n} i^2 = \frac{n(n+1)(2n+1)}{6} $$</p>



<p class="wp-block-paragraph">I state the sum of cubes:</p>



<p class="wp-block-paragraph">$$ \sum_{i=1}^{n} i^3 = \left(\frac{n(n+1)}{2}\right)^2 $$</p>



<p class="wp-block-paragraph">I state the geometric series formula for $r \neq 1$:</p>



<p class="wp-block-paragraph">$$ \sum_{i=0}^{n} r^i = \frac{r^{n+1} &#8211; 1}{r &#8211; 1} $$</p>



<p class="wp-block-paragraph">and for the infinite case with $|r| &lt; 1$:</p>



<p class="wp-block-paragraph">$$ \sum_{i=0}^{\infty} r^i = \frac{1}{1 &#8211; r} $$</p>



<p class="wp-block-paragraph">I prove the arithmetic series formula using the classic pairing technique (attributed to a young Gauss): I write the sum forwards and backwards,</p>



<p class="wp-block-paragraph">$$ S = 1 + 2 + \cdots + n, \qquad S = n + (n-1) + \cdots + 1 $$</p>



<p class="wp-block-paragraph">and add them term by term:</p>



<p class="wp-block-paragraph">$$ 2S = \underbrace{(n+1) + (n+1) + \cdots + (n+1)}_{n \text{ times}} = n(n+1) $$</p>



<p class="wp-block-paragraph">giving $S = \frac{n(n+1)}{2}$.</p>



<p class="wp-block-paragraph">I use the integral bounding technique for a monotonically increasing function $f$:</p>



<p class="wp-block-paragraph">$$ \int_{m-1}^{n} f(x),dx \le \sum_{i=m}^{n} f(i) \le \int_{m}^{n+1} f(x),dx $$</p>



<p class="wp-block-paragraph">which I apply, for example, to bound $\sum_{i=1}^{n} \ln i$ and derive Stirling&#8217;s approximation:</p>



<p class="wp-block-paragraph">$$ \ln(n!) = \sum_{i=1}^{n} \ln i \approx n \ln n &#8211; n $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Given a summation] --> B{Known closed-form pattern?}
    B -->|Arithmetic/Geometric/Power sum| C[Apply direct formula]
    B -->|Telescoping pattern visible| D[Cancel intermediate terms]
    B -->|No direct formula| E[Split or reindex the sum]
    E --> F{Still no closed form?}
    F -->|Yes| G[Approximate using integral bounds]
    F -->|No| C
    C --> H[Return simplified result]
    D --> H
    G --> H
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for computing a summation directly (useful when no closed form is known or when verifying a derived formula):</p>



<pre class="wp-block-code"><code>function SUM(f, m, n):
    total = 0
    for i from m to n:
        total = total + f(i)
    return total
</code></pre>



<p class="wp-block-paragraph">I also provide pseudocode applying a closed-form arithmetic sum formula for comparison:</p>



<pre class="wp-block-code"><code>function ARITHMETIC_SUM_CLOSED_FORM(n):
    return (n * (n + 1)) / 2
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I evaluate $\sum_{i=1}^{5} i^2$ two ways.</p>



<p class="wp-block-paragraph"><strong>Direct computation:</strong></p>



<p class="wp-block-paragraph">$$ 1^2 + 2^2 + 3^2 + 4^2 + 5^2 = 1 + 4 + 9 + 16 + 25 = 55 $$</p>



<p class="wp-block-paragraph"><strong>Closed-form formula:</strong></p>



<p class="wp-block-paragraph">$$ \sum_{i=1}^{5} i^2 = \frac{5 \cdot 6 \cdot 11}{6} = \frac{330}{6} = 55 $$</p>



<p class="wp-block-paragraph">I confirm both approaches agree, giving me confidence in the closed-form identity.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I compute a summation via direct iteration in $O(n)$ time, since I perform one addition per term across $n$ terms, regardless of best, average, or worst case — the number of terms is fixed by the bounds, not by the input&#8217;s values. Using a closed-form formula instead, I reduce this to $O(1)$ time, since I perform a fixed number of arithmetic operations regardless of $n$. This distinction — $O(n)$ direct summation vs $O(1)$ closed-form evaluation — is precisely why I prioritize finding closed forms when analyzing algorithms with large or symbolic bounds.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require only $O(1)$ auxiliary space to compute a summation iteratively, since I maintain a single running total variable. If I instead store every intermediate partial sum (useful for later reference, such as building a prefix-sum array), I require $O(n)$ space to hold all $n$ partial sums.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the direct iterative summation algorithm by simple loop invariant reasoning: before each iteration, my running total correctly holds the sum of all terms processed so far, and this invariant is maintained by adding exactly one new term per iteration, so after the loop completes, the total correctly reflects the sum of all terms in the range. I justify closed-form formulas through the proof techniques shown above (pairing, telescoping, or mathematical induction), each of which independently establishes that the formula produces the same value as direct summation for all valid $n$.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I gain enormous computational savings by replacing $O(n)$ direct sums with $O(1)$ closed forms.</li>



<li>Summation notation lets me express and manipulate long or infinite sequences of terms compactly.</li>



<li>Bounding techniques let me approximate sums I cannot evaluate exactly, which is essential in algorithm analysis.</li>



<li>Telescoping and other algebraic tricks often reveal elegant, simplified structure hidden inside a complicated-looking sum.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find that not every summation has a known or simple closed form, especially for irregular or non-polynomial terms.</li>



<li>Bounding techniques give me approximations rather than exact values, which can be insufficient when precision matters.</li>



<li>Some series (particularly divergent or conditionally convergent ones) require careful handling to avoid incorrect manipulation (like invalid rearrangement).</li>



<li>Deriving a closed form can require creativity and is not always a mechanical process.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply summation heavily in:</p>



<ul class="wp-block-list">
<li><strong>Algorithm analysis</strong>: computing total work across nested loops (e.g., analyzing $O(n^2)$ algorithms via $\sum_{i=1}^{n} i$).</li>



<li><strong>Probability and statistics</strong>: computing expected values and variances as sums over probability-weighted outcomes.</li>



<li><strong>Numerical methods</strong>: Riemann sums approximate integrals; series expansions approximate functions (Taylor series).</li>



<li><strong>Financial mathematics</strong>: computing compound interest and annuities using geometric series.</li>



<li><strong>Physics and engineering</strong>: summing discrete forces, signals, or energy contributions.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement both a direct summation function and a closed-form version for comparison, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>

// I compute the sum of squares directly, term by term
long directSumOfSquares(int n) {
    long total = 0;
    for (int i = 1; i &lt;= n; i++) {
        total += (long)i * i;
    }
    return total;
}

// I compute the sum of squares using the closed-form formula
long closedFormSumOfSquares(int n) {
    return ((long)n * (n + 1) * (2 * n + 1)) / 6;
}

int main() {
    int n = 5;

    long direct = directSumOfSquares(n);
    long closedForm = closedFormSumOfSquares(n);

    printf("Direct computation: %ld\n", direct);
    printf("Closed-form computation: %ld\n", closedForm);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I compute the sum of squares directly, term by term</span></span>
<span class="line"><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">directSumOfSquares</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> total </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        total </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">long</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">i </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> total</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I compute the sum of squares using the closed-form formula</span></span>
<span class="line"><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">closedFormSumOfSquares</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">((</span><span style="color: #81A1C1">long</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">n </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">n </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">6</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> direct </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">directSumOfSquares</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">n</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> closedForm </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">closedFormSumOfSquares</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">n</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Direct computation: %ld</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> direct</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Closed-form computation: %ld</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> closedForm</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I run the program with <code>n = 5</code>, and I expect:</p>



<pre class="wp-block-code"><code>Direct computation: 55
Closed-form computation: 55
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I precompute prefix sums (running totals stored in an array) when I need to answer many range-sum queries efficiently, reducing each query to $O(1)$ after $O(n)$ preprocessing.</li>



<li>I replace direct loops with known closed-form formulas whenever the summed pattern matches arithmetic, geometric, or polynomial sums.</li>



<li>I use integral approximations (like the Euler–Maclaurin formula) to estimate sums of smooth functions without full enumeration.</li>



<li>I exploit symmetry in a summation (such as pairing terms from opposite ends) to simplify or halve the computation needed.</li>



<li>I apply modular arithmetic incrementally when computing large sums modulo a number, avoiding overflow in fixed-width integer types.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes misapply a closed-form formula to bounds that do not start at the assumed index (e.g., forgetting to adjust when a sum starts at 0 instead of 1).</li>



<li>I forget that geometric series formulas require $r \neq 1$, causing a division-by-zero error if I don&#8217;t handle that case separately.</li>



<li>I incorrectly assume linearity applies to non-additive operations, such as trying to split a sum of products the same way I would split a sum of sums.</li>



<li>I lose precision using floating-point summation for very large or very small terms instead of considering more numerically stable summation orders (like Kahan summation).</li>



<li>I forget to verify a derived closed-form formula against a small test case, missing an off-by-one error in the bounds.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Graham, R. L., Knuth, D. E., &amp; Patashnik, O. <em>Concrete Mathematics</em>: https://www-cs-faculty.stanford.edu/~knuth/gkp.html</li>



<li>MIT OpenCourseWare, 6.042J Mathematics for Computer Science: https://ocw.mit.edu/courses/6-042j-mathematics-for-computer-science-fall-2010/</li>



<li>Knuth, D. E. <em>The Art of Computer Programming, Volume 1</em>: https://www-cs-faculty.stanford.edu/~knuth/taocp.html</li>



<li>Weisstein, Eric W. &#8220;Sum.&#8221; MathWorld: https://mathworld.wolfram.com/Sum.html</li>



<li>Apostol, T. M. <em>Calculus, Volume 1</em> (series and summation chapters): https://www.wiley.com/en-us/Calculus%2C+Volume+1%2C+2nd+Edition-p-9780471000051</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/summations-essential-formulas-properties-and-bounding-techniques-explained/">Summations: Essential Formulas, Properties, and Bounding Techniques Explained</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/summations-essential-formulas-properties-and-bounding-techniques-explained/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10892</post-id>	</item>
		<item>
		<title>Approximation Algorithms: Key Problems, Examples, and Implementations</title>
		<link>https://awjunaid.com/algorithm/approximation-algorithms-key-problems-examples-and-implementations/</link>
					<comments>https://awjunaid.com/algorithm/approximation-algorithms-key-problems-examples-and-implementations/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 16:03:04 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10889</guid>

					<description><![CDATA[<p>I turn to approximation algorithms whenever I face a computational problem that is provably hard to solve exactly&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/approximation-algorithms-key-problems-examples-and-implementations/">Approximation Algorithms: Key Problems, Examples, and Implementations</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I turn to approximation algorithms whenever I face a computational problem that is provably hard to solve exactly within a reasonable amount of time, yet still needs a usable answer. I define an approximation algorithm as one that runs in polynomial time and produces a solution guaranteed to be within a known factor of the optimal solution. I find these algorithms essential because many real-world optimization problems are NP-hard, and I would rather have a fast, provably-close-to-optimal answer than wait for an exact solution that might never finish computing.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the formal study of approximation algorithms to the 1960s and 1970s, alongside the development of NP-completeness theory. I note that some of the earliest approximation results include the greedy algorithm analysis for the set cover problem and the 2-approximation for vertex cover, both studied extensively in the 1970s. I see the field formalized further through the work of David Johnson (1974), who analyzed approximation ratios for several classic NP-hard problems, and later through the introduction of the PCP theorem in the early 1990s (Arora, Safra, and others), which established fundamental limits on how well certain problems can be approximated unless P = NP. I regard this era as transforming approximation algorithms from ad hoc heuristics into a rigorous subfield with matching upper and lower bound results.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use approximation algorithms to address NP-hard optimization problems where finding the exact optimal solution would require exponential time in the worst case. Rather than giving up or waiting indefinitely, I use algorithms that trade a small, bounded amount of solution quality for a guarantee of running in polynomial time. My goal in designing or choosing an approximation algorithm is to minimize the approximation ratio — the worst-case factor by which my algorithm&#8217;s result can differ from the true optimum.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I define the <strong>approximation ratio</strong> $\rho$ for a minimization problem as the smallest value such that, for every input instance,</p>



<p class="wp-block-paragraph">$$ \frac{C}{C^*} \le \rho $$</p>



<p class="wp-block-paragraph">where $C$ is the cost of my algorithm&#8217;s solution and $C^<em>$ is the cost of the optimal solution. For maximization problems, I flip the inequality: $\frac{C^</em>}{C} \le \rho$.</p>



<p class="wp-block-paragraph">I distinguish several categories:</p>



<ul class="wp-block-list">
<li><strong>Constant-factor approximation</strong>: the ratio $\rho$ is a fixed constant, independent of input size.</li>



<li><strong>Polynomial-Time Approximation Scheme (PTAS)</strong>: for any $\epsilon > 0$, I can find a $(1+\epsilon)$-approximation in polynomial time (though the exponent may depend on $\epsilon$).</li>



<li><strong>Fully Polynomial-Time Approximation Scheme (FPTAS)</strong>: like a PTAS, but the running time is polynomial in both the input size and $\frac{1}{\epsilon}$.</li>



<li><strong>Inapproximability</strong>: results proving that no polynomial-time algorithm can achieve a certain approximation ratio unless P = NP.</li>
</ul>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I design or apply an approximation algorithm, I follow this general process:</p>



<ol class="wp-block-list">
<li>I identify the NP-hard optimization problem and its objective (minimize or maximize some cost/value).</li>



<li>I design a polynomial-time strategy (often greedy, LP-relaxation-based, or local-search-based) that produces a feasible solution.</li>



<li>I prove an upper bound on my algorithm&#8217;s solution relative to the optimal solution, typically by comparing against a lower bound (for minimization) or upper bound (for maximization) on the true optimum that I can compute or reason about directly.</li>



<li>I verify the bound holds for all inputs, establishing the algorithm&#8217;s guaranteed approximation ratio.</li>



<li>I evaluate whether the ratio is acceptable for my application, or whether I need a tighter algorithm (like a PTAS).</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I rely on a key trick common to most approximation algorithms: since I usually cannot compute the true optimal value $C^<em>$ directly (as that would solve the NP-hard problem exactly), I instead compute or reason about a bound on $C^</em>$ that I can compute efficiently. For example, in vertex cover, I use the size of a maximal matching as a lower bound on the minimum vertex cover size, since I can prove that any vertex cover must include at least one endpoint from each matched edge. I then show that my algorithm&#8217;s output is within a constant factor of this efficiently-computable bound, which transitively bounds it against the true optimum.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I illustrate the mathematical foundation using the <strong>Vertex Cover</strong> problem: given a graph $G = (V, E)$, I want the minimum subset $C \subseteq V$ such that every edge has at least one endpoint in $C$.</p>



<p class="wp-block-paragraph">My 2-approximation algorithm picks a maximal matching $M$ and includes both endpoints of every edge in $M$ into my cover set $S$.</p>



<p class="wp-block-paragraph">I claim $|S| = 2|M|$ and prove correctness:</p>



<p class="wp-block-paragraph">$$ |S| = 2|M| \le 2 \cdot OPT $$</p>



<p class="wp-block-paragraph">I justify this because no two edges in a matching share a vertex, so any valid vertex cover must pick at least one distinct vertex per matched edge — meaning $OPT \ge |M|$. Since my algorithm picks exactly $2|M|$ vertices,</p>



<p class="wp-block-paragraph">$$ \frac{|S|}{OPT} \le \frac{2|M|}{|M|} = 2 $$</p>



<p class="wp-block-paragraph">establishing a 2-approximation.</p>



<p class="wp-block-paragraph">For the <strong>Set Cover</strong> problem, I use a greedy algorithm that repeatedly selects the set covering the most uncovered elements. I state its approximation ratio as:</p>



<p class="wp-block-paragraph">$$ \rho = H(d) = \sum_{i=1}^{d} \frac{1}{i} \approx \ln(d) + 1 $$</p>



<p class="wp-block-paragraph">where $d$ is the size of the largest set, and $H(d)$ is the $d$-th harmonic number.</p>



<p class="wp-block-paragraph">For the <strong>Bin Packing</strong> problem, I use the First-Fit-Decreasing heuristic, which I bound as:</p>



<p class="wp-block-paragraph">$$ FFD(I) \le \frac{11}{9} OPT(I) + 6 $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[NP-hard optimization problem] --> B[Design polynomial-time heuristic]
    B --> C[Compute algorithm solution cost C]
    C --> D[Derive efficiently-computable bound on optimal cost]
    D --> E{Prove C / bound &lt;= rho?}
    E -->|Yes| F[Approximation ratio rho established]
    E -->|No| G[Refine algorithm or bound]
    G --> B
    F --> H[Use algorithm with guaranteed quality]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for the 2-approximation Vertex Cover algorithm:</p>



<pre class="wp-block-code"><code>function APPROX_VERTEX_COVER(G):
    C = empty set
    E' = copy of edge set E(G)

    while E' is not empty:
        pick an arbitrary edge (u, v) from E'
        add u and v to C
        remove all edges in E' incident to u or v

    return C
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I apply the algorithm to a small graph with vertices ${1,2,3,4,5}$ and edges ${(1,2), (2,3), (3,4), (4,5)}$.</p>



<ol class="wp-block-list">
<li>I pick edge $(1,2)$. I add both 1 and 2 to $C$. I remove all edges touching 1 or 2, leaving ${(3,4), (4,5)}$.</li>



<li>I pick edge $(3,4)$. I add both 3 and 4 to $C$. I remove all edges touching 3 or 4, leaving ${}$.</li>



<li>The edge set is empty, so I stop.</li>
</ol>



<p class="wp-block-paragraph">I obtain $C = {1, 2, 3, 4}$, a cover of size 4. I note that the optimal vertex cover for this path graph is actually ${2, 4}$, size 2 — so my algorithm&#8217;s ratio here is $\frac{4}{2} = 2$, matching the proven worst-case bound.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I analyze the vertex cover approximation algorithm as running in $O(V + E)$ time, since each edge is examined at most once when I remove edges incident to the chosen pair, and the while loop processes each edge exactly once across all iterations combined. For the greedy Set Cover algorithm, I get $O(|U| \cdot |S|)$ time in the worst case, where $|U|$ is the universe size and $|S|$ is the number of sets, since I may scan all sets at each of up to $|U|$ iterations. These bounds hold uniformly across best, average, and worst cases because the algorithms perform a fixed, input-size-dependent amount of work regardless of the specific values involved.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(V + E)$ space to store the graph and the current cover set for vertex cover, and $O(|U| + \sum|S_i|)$ space for set cover, since I need to track which elements remain uncovered and which sets are available. I typically need no more than a constant additional factor beyond the input representation itself.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the vertex cover algorithm&#8217;s correctness in two parts: <strong>feasibility</strong>, since every edge in the original graph is either directly processed (both endpoints added to $C$) or removed because one of its endpoints was already added, meaning every edge has at least one endpoint in $C$; and <strong>approximation bound</strong>, established via the matching-based lower bound argument shown in the Mathematical Foundation section. I generalize this reasoning pattern — proving feasibility separately from the approximation ratio — to essentially all approximation algorithms I study.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I obtain provable, worst-case quality guarantees rather than relying on unverified heuristics.</li>



<li>I get polynomial-time performance on problems that would otherwise require exponential time for exact solutions.</li>



<li>Many approximation algorithms are simple to implement (greedy or local search based), making them practical for real systems.</li>



<li>I can often tune the trade-off between running time and solution quality, especially with PTAS-style algorithms.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I accept a solution that may not be optimal, which is unacceptable in some safety-critical or precision-critical applications.</li>



<li>Some problems have strong inapproximability results, meaning no good polynomial-time approximation exists unless P = NP.</li>



<li>Designing a tight approximation algorithm with a strong proven ratio can require significant theoretical creativity.</li>



<li>PTAS and FPTAS algorithms, while theoretically appealing, can have impractically large constants or exponents in their running time.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply approximation algorithms in:</p>



<ul class="wp-block-list">
<li><strong>Network design</strong>: approximating minimum spanning trees with additional constraints, Steiner tree problems.</li>



<li><strong>Logistics</strong>: approximating solutions to the traveling salesman problem and vehicle routing.</li>



<li><strong>Resource allocation</strong>: bin packing for scheduling jobs onto machines or packing shipping containers.</li>



<li><strong>Clustering</strong>: k-means and k-center approximation algorithms in machine learning.</li>



<li><strong>Facility location</strong>: approximating optimal placement of warehouses, cell towers, or emergency services.</li>



<li><strong>Chip design</strong>: approximating VLSI circuit layout and partitioning problems.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement the 2-approximation vertex cover algorithm using an adjacency-based edge list, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;stdbool.h>

#define MAX_EDGES 100

typedef struct {
    int u, v;
    bool removed;
} Edge;

int main() {
    // I define a small path graph: 1-2-3-4-5
    Edge edges[] = {
        {1, 2, false},
        {2, 3, false},
        {3, 4, false},
        {4, 5, false}
    };
    int numEdges = 4;

    bool inCover&#91;6&#93; = {false}; // I track which vertices are in the cover (1-indexed)

    for (int i = 0; i &lt; numEdges; i++) {
        if (edges&#91;i&#93;.removed) continue; // I skip edges already covered

        int u = edges&#91;i&#93;.u;
        int v = edges&#91;i&#93;.v;

        // I add both endpoints of this uncovered edge to the cover
        inCover&#91;u&#93; = true;
        inCover&#91;v&#93; = true;

        // I remove (mark) all edges incident to u or v
        for (int j = 0; j &lt; numEdges; j++) {
            if (!edges&#91;j&#93;.removed &amp;&amp;
                (edges&#91;j&#93;.u == u || edges&#91;j&#93;.v == u ||
                 edges&#91;j&#93;.u == v || edges&#91;j&#93;.v == v)) {
                edges&#91;j&#93;.removed = true;
            }
        }
    }

    printf("Vertex cover: ");
    for (int i = 1; i &lt;= 5; i++) {
        if (inCover&#91;i&#93;) printf("%d ", i);
    }
    printf("\n");

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdbool.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">MAX_EDGES</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">100</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> u</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> v</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> removed</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> Edge</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I define a small path graph: 1-2-3-4-5</span></span>
<span class="line"><span style="color: #D8DEE9FF">    Edge edges</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">3</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> numEdges </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> inCover</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">6</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I track which vertices are in the cover (1-indexed)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> numEdges</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">removed</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">continue;</span><span style="color: #616E88"> // I skip edges already covered</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> u </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">u</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> v </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">v</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// I add both endpoints of this uncovered edge to the cover</span></span>
<span class="line"><span style="color: #D8DEE9FF">        inCover</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">u</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        inCover</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">v</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// I remove (mark) all edges incident to u or v</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> numEdges</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> j</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">removed</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">u</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> u </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> u </span><span style="color: #81A1C1">||</span></span>
<span class="line"><span style="color: #D8DEE9FF">                 edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">u</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> v </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">v</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> v</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                edges</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">removed</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Vertex cover: </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">inCover</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%d </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> i</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I hardcode the path graph $1-2-3-4-5$ as input, and I expect the following output:</p>



<pre class="wp-block-code"><code>Vertex cover: 1 2 3 4
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I use linear programming relaxation followed by rounding to design approximation algorithms with tighter bounds than simple greedy strategies.</li>



<li>I apply local search (repeatedly improving a solution via small modifications) to refine approximate solutions further, as in the Lin-Kernighan heuristic for TSP.</li>



<li>I use primal-dual methods to simultaneously construct a feasible solution and a matching bound on the optimum, often yielding cleaner proofs and tighter ratios.</li>



<li>I exploit problem-specific structure (like metric properties in the triangle-inequality TSP) to design specialized algorithms with better guarantees than the general case allows.</li>



<li>I parallelize independent parts of greedy selection processes to speed up practical runtime on large inputs.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes confuse an algorithm&#8217;s observed performance on test cases with its proven worst-case approximation ratio, which can differ significantly.</li>



<li>I forget to verify that my lower/upper bound argument on the optimal solution actually holds for all instances, not just the one I tested.</li>



<li>I apply an approximation algorithm designed for one problem variant (e.g., unweighted vertex cover) directly to a different variant (e.g., weighted vertex cover) without adjusting the analysis.</li>



<li>I overlook that some approximation ratios (like the harmonic bound for set cover) grow with input size and are not constant factors.</li>



<li>I neglect edge cases such as empty graphs or fully disconnected inputs when implementing and testing my algorithm.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Vazirani, V. V. <em>Approximation Algorithms</em>: https://www.springer.com/gp/book/9783540653677</li>



<li>Williamson, D. P., &amp; Shmoys, D. B. <em>The Design of Approximation Algorithms</em>: https://www.designofapproxalgs.com/</li>



<li>Arora, S., &amp; Barak, B. <em>Computational Complexity: A Modern Approach</em> (approximation and PCP chapters): https://theory.cs.princeton.edu/complexity/</li>



<li>Johnson, D. S. (1974). &#8220;Approximation Algorithms for Combinatorial Problems.&#8221; Journal of Computer and System Sciences: https://www.sciencedirect.com/science/article/pii/S0022000074800443</li>



<li>MIT OpenCourseWare, 6.854/18.415J Advanced Algorithms: https://ocw.mit.edu/courses/18-415j-advanced-algorithms-spring-2015/</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/approximation-algorithms-key-problems-examples-and-implementations/">Approximation Algorithms: Key Problems, Examples, and Implementations</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/approximation-algorithms-key-problems-examples-and-implementations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10889</post-id>	</item>
		<item>
		<title>NP-Completeness: A Comprehensive Guide to Computational Complexity</title>
		<link>https://awjunaid.com/algorithm/np-completeness-a-comprehensive-guide-to-computational-complexity/</link>
					<comments>https://awjunaid.com/algorithm/np-completeness-a-comprehensive-guide-to-computational-complexity/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 16:00:04 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10886</guid>

					<description><![CDATA[<p>I use the theory of NP-completeness whenever I need to understand why certain computational problems seem fundamentally hard&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/np-completeness-a-comprehensive-guide-to-computational-complexity/">NP-Completeness: A Comprehensive Guide to Computational Complexity</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use the theory of NP-completeness whenever I need to understand why certain computational problems seem fundamentally hard to solve efficiently, no matter how cleverly I try to design an algorithm. I think of NP-completeness as a classification tool that groups together the hardest problems in the complexity class NP, such that if I could solve any one of them efficiently, I could solve all of them efficiently. I find this theory essential because it tells me when to stop searching for a fast exact algorithm and instead pursue approximation, heuristics, or restricted special cases.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the foundation of NP-completeness to Stephen Cook&#8217;s 1971 paper, &#8220;The Complexity of Theorem-Proving Procedures,&#8221; where he introduced the Cook-Levin theorem, proving that Boolean satisfiability (SAT) is NP-complete. I note that Leonid Levin independently discovered similar results around the same time in the Soviet Union, which is why I often see this foundational result called the Cook-Levin theorem. I see the field expand rapidly through Richard Karp&#8217;s 1972 paper, &#8220;Reducibility Among Combinatorial Problems,&#8221; which showed 21 additional problems to be NP-complete via polynomial-time reductions from SAT. I regard the subsequent decades as building out an enormous catalog of NP-complete problems, documented extensively in Garey and Johnson&#8217;s 1979 book <em>Computers and Intractability</em>, which remains a standard reference.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use NP-completeness theory to answer the question: given a new computational problem, how do I determine whether it is likely to have an efficient (polynomial-time) algorithm, or whether it belongs to a class of problems widely believed to have no such algorithm? Rather than searching indefinitely for an efficient algorithm that may not exist, I use reduction techniques to show that a problem is at least as hard as known NP-complete problems, which tells me that finding a polynomial-time algorithm for it would resolve the famous P vs NP question.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I define the complexity class <strong>P</strong> as the set of decision problems solvable by a deterministic algorithm in polynomial time. I define <strong>NP</strong> as the set of decision problems for which a proposed solution (a &#8220;certificate&#8221;) can be verified in polynomial time. I define a problem as <strong>NP-hard</strong> if every problem in NP can be reduced to it in polynomial time. I define a problem as <strong>NP-complete</strong> if it is both in NP and NP-hard — meaning it is among the hardest problems in NP.</p>



<p class="wp-block-paragraph">I rely heavily on the concept of <strong>polynomial-time reduction</strong> ($A \le_p B$): I say problem $A$ reduces to problem $B$ if I can transform any instance of $A$ into an instance of $B$ in polynomial time such that the answer to the transformed instance solves the original instance of $A$.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I want to prove a new problem $X$ is NP-complete, I follow this process:</p>



<ol class="wp-block-list">
<li>I show $X \in NP$ by demonstrating that a proposed solution can be verified in polynomial time.</li>



<li>I select a known NP-complete problem $Y$ (such as SAT, 3-SAT, or Vertex Cover).</li>



<li>I construct a polynomial-time transformation that converts any instance of $Y$ into an instance of $X$.</li>



<li>I prove the transformation is correct: a &#8220;yes&#8221; instance of $Y$ maps to a &#8220;yes&#8221; instance of $X$, and a &#8220;no&#8221; instance of $Y$ maps to a &#8220;no&#8221; instance of $X$.</li>



<li>I conclude $Y \le_p X$, and since $Y$ is NP-hard, this establishes that $X$ is also NP-hard. Combined with step 1, $X$ is NP-complete.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of NP-completeness proofs as a chain of &#8220;at least as hard as&#8221; relationships. Once I establish that SAT is NP-hard (via Cook-Levin, by directly simulating a nondeterministic Turing machine&#8217;s computation as a Boolean formula), I can prove additional problems NP-hard purely through reduction, without needing to reason about Turing machines again. This is powerful because each new NP-complete problem I prove becomes a new tool I can reduce from, growing the web of interconnected hardness results — this is precisely how Karp&#8217;s original 21 problems, and the thousands cataloged since, were established.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I state the relationship between complexity classes as:</p>



<p class="wp-block-paragraph">$$ P \subseteq NP \subseteq NP\text{-hard problems in a broader sense} $$</p>



<p class="wp-block-paragraph">I state the central open question of computer science:</p>



<p class="wp-block-paragraph">$$ P \stackrel{?}{=} NP $$</p>



<p class="wp-block-paragraph">I define polynomial-time reduction formally: $A \le_p B$ if there exists a function $f$, computable in time $O(n^k)$ for some constant $k$, such that for every input $x$:</p>



<p class="wp-block-paragraph">$$ x \in A \iff f(x) \in B $$</p>



<p class="wp-block-paragraph">I illustrate with the classic reduction from <strong>3-SAT to Vertex Cover</strong>. Given a 3-SAT formula with $m$ clauses, I construct a graph with a &#8220;gadget&#8221; of 3 vertices (a triangle) per clause, representing the three literals, plus 2 vertices per variable, representing the variable and its negation, connected by an edge. I set the target cover size to:</p>



<p class="wp-block-paragraph">$$ k = m \cdot 2 + n $$</p>



<p class="wp-block-paragraph">(where $m$ is the number of clauses and $n$ is the number of variables), and I prove that the 3-SAT formula is satisfiable if and only if this graph has a vertex cover of size $k$ or smaller — establishing the reduction, and therefore that Vertex Cover is NP-hard (since 3-SAT is already known NP-complete).</p>



<p class="wp-block-paragraph">I also express the certificate-verification definition of NP formally: a language $L \in NP$ if there exists a polynomial-time verifier $V$ and polynomial $p(n)$ such that:</p>



<p class="wp-block-paragraph">$$ x \in L \iff \exists, c,\ |c| \le p(|x|), \ V(x, c) = 1 $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[New problem X] --> B[Show X is in NP: verify solution in poly time]
    B --> C[Pick known NP-complete problem Y]
    C --> D[Construct poly-time reduction Y to X]
    D --> E{Reduction correct? yes-to-yes, no-to-no}
    E -->|Yes| F[X is NP-hard]
    F --> G[X is in NP and NP-hard]
    G --> H[X is NP-complete]
    E -->|No| I[Revise reduction construction]
    I --> D
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for a polynomial-time verifier for the SAT problem, which demonstrates the &#8220;verification in polynomial time&#8221; property central to the definition of NP:</p>



<pre class="wp-block-code"><code>function VERIFY_SAT(formula, assignment):
    for each clause in formula:
        clauseSatisfied = false
        for each literal in clause:
            if evaluate(literal, assignment) == true:
                clauseSatisfied = true
                break
        if clauseSatisfied == false:
            return false     // one unsatisfied clause invalidates the assignment

    return true               // every clause was satisfied
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I verify a small 3-SAT instance:</p>



<p class="wp-block-paragraph">$$ \phi = (x_1 \lor \lnot x_2 \lor x_3) \land (\lnot x_1 \lor x_2 \lor \lnot x_3) $$</p>



<p class="wp-block-paragraph">I propose the certificate (candidate assignment): $x_1 = \text{true}, x_2 = \text{true}, x_3 = \text{false}$.</p>



<ol class="wp-block-list">
<li>I check clause 1: $(x_1 \lor \lnot x_2 \lor x_3) = (\text{true} \lor \text{false} \lor \text{false}) = \text{true}$. Satisfied.</li>



<li>I check clause 2: $(\lnot x_1 \lor x_2 \lor \lnot x_3) = (\text{false} \lor \text{true} \lor \text{true}) = \text{true}$. Satisfied.</li>
</ol>



<p class="wp-block-paragraph">Since I verified both clauses hold under this assignment, I confirm the certificate is valid, and this verification took time proportional to the size of the formula — polynomial time — which is exactly what places SAT in NP.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I note that verifying a certificate for an NP problem (like SAT) takes polynomial time — specifically $O(m \cdot k)$ for $m$ clauses of size $k$ each, since I check each literal in each clause once. In contrast, I note that no known algorithm can <em>solve</em> (find a satisfying assignment for, or determine none exists) an NP-complete problem faster than exponential time, $O(2^n)$ in the worst case for $n$ variables, using brute-force search over all possible assignments. This gap — polynomial-time verification vs. exponential-time (as far as I know) solving — is the defining tension that NP-completeness theory studies. Best-case behavior for solving SAT can be fast if a satisfying assignment happens to be found early by a heuristic solver, but worst-case remains exponential for all known algorithms.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(n + m)$ space to represent a Boolean formula with $n$ variables and $m$ clauses, and $O(n)$ additional space to store a candidate assignment during verification. For solving via brute force, I typically require $O(n)$ space to track the current assignment being tested (recursive backtracking), even though the search space itself has $2^n$ possibilities, since I don&#8217;t need to store all of them simultaneously.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the correctness of a reduction-based NP-hardness proof by verifying the biconditional relationship exactly, as done in the 3-SAT-to-Vertex-Cover construction: I must show both directions — that a satisfying assignment for the formula yields a small enough vertex cover in the constructed graph, and conversely, that a small enough vertex cover implies a satisfying assignment exists. Both directions are necessary; proving only one direction is a common and serious error in reduction proofs. I justify the correctness of the SAT verifier by structural induction over the clauses: the algorithm returns true only if every single clause was individually confirmed satisfied by the loop, and returns false immediately upon finding a counterexample clause, which exactly matches the logical definition of formula satisfaction (a conjunction of clauses, all of which must hold).</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I gain a principled way to recognize when a problem is unlikely to have an efficient exact algorithm, saving time I might otherwise waste searching for one.</li>



<li>The web of reductions lets me quickly classify new problems by connecting them to already-studied NP-complete problems.</li>



<li>NP-completeness theory guides me toward appropriate alternative strategies: approximation algorithms, heuristics, parameterized algorithms, or restricting to special cases.</li>



<li>The theory has deep theoretical value, connecting logic, computability, and complexity in a unified framework.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find that proving a problem NP-complete does not tell me how to solve real instances — it only tells me not to expect a general efficient algorithm.</li>



<li>Some problems resist easy classification, and remain of genuinely unknown status (neither known to be in P nor proven NP-complete).</li>



<li>The reduction proofs themselves can be intricate and error-prone, especially for problems requiring elaborate gadget constructions.</li>



<li>NP-completeness says nothing about hardness in an average or practical sense — many NP-complete problems (like certain SAT instances) are actually solved quickly in practice by modern solvers.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I encounter and apply NP-completeness theory in:</p>



<ul class="wp-block-list">
<li><strong>Scheduling</strong>: job-shop scheduling and resource allocation problems are often NP-complete, motivating heuristic solvers.</li>



<li><strong>Cryptography</strong>: some hardness assumptions related to NP-hard problems underpin cryptographic security arguments, though modern cryptography relies more on specific number-theoretic hardness.</li>



<li><strong>Circuit design and verification</strong>: Boolean satisfiability solvers are used directly in hardware verification and automated test generation.</li>



<li><strong>Bioinformatics</strong>: sequence alignment variants and certain phylogenetic tree problems are NP-complete.</li>



<li><strong>Operations research</strong>: the traveling salesman problem and various packing/covering problems inform logistics and supply chain optimization.</li>



<li><strong>Artificial intelligence</strong>: planning and constraint satisfaction problems frequently reduce to or from NP-complete problems.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement a brute-force SAT solver for small instances, with comments, to illustrate the exponential search NP-completeness theory predicts:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;stdbool.h>
#include &lt;math.h>

#define NUM_VARS 3

// I hardcode a small 3-SAT formula: (x1 OR NOT x2 OR x3) AND (NOT x1 OR x2 OR NOT x3)
bool evaluateFormula(bool x&#91;NUM_VARS&#93;) {
    bool clause1 = x&#91;0&#93; || !x&#91;1&#93; || x&#91;2&#93;;
    bool clause2 = !x&#91;0&#93; || x&#91;1&#93; || !x&#91;2&#93;;
    return clause1 &amp;&amp; clause2;
}

int main() {
    int totalAssignments = (int)pow(2, NUM_VARS);
    bool foundSatisfying = false;

    for (int mask = 0; mask &lt; totalAssignments; mask++) {
        bool assignment&#91;NUM_VARS&#93;;

        // I decode the integer mask into a boolean assignment
        for (int i = 0; i &lt; NUM_VARS; i++) {
            assignment&#91;i&#93; = (mask >> i) &amp; 1;
        }

        if (evaluateFormula(assignment)) {
            printf("Satisfying assignment found: x1=%d x2=%d x3=%d\n",
                   assignment&#91;0&#93;, assignment&#91;1&#93;, assignment&#91;2&#93;);
            foundSatisfying = true;
            break; // I stop at the first satisfying assignment
        }
    }

    if (!foundSatisfying) {
        printf("No satisfying assignment exists.\n");
    }

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdbool.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">math.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">NUM_VARS</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">3</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I hardcode a small 3-SAT formula: (x1 OR NOT x2 OR x3) AND (NOT x1 OR x2 OR NOT x3)</span></span>
<span class="line"><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">evaluateFormula</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">NUM_VARS</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> clause1 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> clause2 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">x</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> clause1 </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> clause2</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> totalAssignments </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #ECEFF4">)</span><span style="color: #88C0D0">pow</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> NUM_VARS</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> foundSatisfying </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> mask </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> mask </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> totalAssignments</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> mask</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">bool</span><span style="color: #D8DEE9FF"> assignment</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">NUM_VARS</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// I decode the integer mask into a boolean assignment</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> NUM_VARS</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            assignment</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">mask </span><span style="color: #81A1C1">&gt;&gt;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">evaluateFormula</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">assignment</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Satisfying assignment found: x1=%d x2=%d x3=%d</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                   assignment</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;,</span><span style="color: #D8DEE9FF"> assignment</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;,</span><span style="color: #D8DEE9FF"> assignment</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            foundSatisfying </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">break;</span><span style="color: #616E88"> // I stop at the first satisfying assignment</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">!</span><span style="color: #D8DEE9FF">foundSatisfying</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">No satisfying assignment exists.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I hardcode the formula from the Step-by-Step Example directly into the program, and I expect output similar to:</p>



<pre class="wp-block-code"><code>Satisfying assignment found: x1=1 x2=1 x3=0
</code></pre>



<p class="wp-block-paragraph">(I note the exact assignment reported depends on iteration order, but any output satisfying both clauses is correct.)</p>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I use the DPLL algorithm (Davis-Putnam-Logemann-Loveland) with unit propagation and pure literal elimination to prune the brute-force search space dramatically for SAT solving.</li>



<li>I apply modern conflict-driven clause learning (CDCL), used in industrial SAT solvers, to learn from failed assignments and avoid repeating similar mistakes.</li>



<li>I use parameterized algorithms (fixed-parameter tractability) when a problem&#8217;s hardness is confined to a specific parameter, allowing efficient solving when that parameter is small.</li>



<li>I apply problem-specific heuristics (like local search or simulated annealing) to find good, though not guaranteed optimal, solutions quickly in practice.</li>



<li>I restrict to tractable special cases (like 2-SAT, solvable in polynomial time, unlike general 3-SAT) whenever the application allows it.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes confuse NP-hard with NP-complete, forgetting that NP-hard problems need not even be in NP (they may not be decision problems, or may not have polynomial-time verifiable certificates).</li>



<li>I mistakenly believe that NP-completeness means a problem is &#8220;unsolvable,&#8221; when it actually just means no known polynomial-time algorithm exists — the problem is still solvable, just potentially slowly.</li>



<li>I prove only one direction of a reduction&#8217;s correctness, forgetting the necessary biconditional (yes-to-yes AND no-to-no).</li>



<li>I attempt to reduce in the wrong direction, mistakenly reducing my new problem to a known NP-complete problem instead of reducing the known NP-complete problem to my new problem.</li>



<li>I assume brute-force exponential time is unavoidable in practice, overlooking that heuristic solvers can handle many real-world NP-complete instances efficiently despite the worst-case bound.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Cook, S. A. (1971). &#8220;The Complexity of Theorem-Proving Procedures.&#8221; Proceedings of STOC: https://dl.acm.org/doi/10.1145/800157.805047</li>



<li>Karp, R. M. (1972). &#8220;Reducibility Among Combinatorial Problems&#8221;: https://www.cs.berkeley.edu/~luca/cs172/karp.pdf</li>



<li>Garey, M. R., &amp; Johnson, D. S. <em>Computers and Intractability: A Guide to the Theory of NP-Completeness</em>: https://www.google.com/books/edition/Computers_and_Intractability/fjxGAQAAIAAJ</li>



<li>Sipser, M. <em>Introduction to the Theory of Computation</em>: https://www.cengage.com/c/introduction-to-the-theory-of-computation-3e-sipser/9781133187790/</li>



<li>Clay Mathematics Institute, &#8220;P vs NP Problem&#8221;: https://www.claymath.org/millennium/p-vs-np/</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/np-completeness-a-comprehensive-guide-to-computational-complexity/">NP-Completeness: A Comprehensive Guide to Computational Complexity</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/np-completeness-a-comprehensive-guide-to-computational-complexity/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10886</post-id>	</item>
		<item>
		<title>Computational Geometry: Key Algorithms and Practical Implementations</title>
		<link>https://awjunaid.com/algorithm/computational-geometry-key-algorithms-and-practical-implementations/</link>
					<comments>https://awjunaid.com/algorithm/computational-geometry-key-algorithms-and-practical-implementations/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 15:56:14 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10883</guid>

					<description><![CDATA[<p>I use computational geometry whenever I need to design efficient algorithms for problems involving points, lines, polygons, and&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/computational-geometry-key-algorithms-and-practical-implementations/">Computational Geometry: Key Algorithms and Practical Implementations</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use computational geometry whenever I need to design efficient algorithms for problems involving points, lines, polygons, and other geometric objects. I think of this field as the intersection of geometry and algorithm design, where I care not just about geometric correctness but about achieving good asymptotic performance on potentially large sets of geometric data. I find computational geometry essential because so many practical systems — mapping software, computer graphics, robotics, and computer-aided design — reduce to fundamentally geometric questions like &#8220;do these shapes intersect?&#8221; or &#8220;what is the smallest enclosing region for these points?&#8221;</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the formal emergence of computational geometry as a distinct field to the 1970s, with Michael Shamos&#8217;s 1978 PhD thesis often cited as foundational, introducing the systematic algorithmic study of geometric problems. I note that earlier geometric algorithm work existed piecemeal — for instance, the gift wrapping algorithm for convex hulls dates to the 1970s as well, developed by R.A. Jarvis in 1973. I see the field mature rapidly through the 1980s with the development of the plane sweep technique by Shamos and Hoey, and Kirkpatrick and Seidel&#8217;s optimal convex hull algorithms. I regard the 1985 textbook by Preparata and Shamos, <em>Computational Geometry: An Introduction</em>, as a landmark that consolidated the field&#8217;s core results and techniques into a coherent curriculum.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use computational geometry to solve problems where I need to efficiently reason about spatial relationships among geometric objects — for example, finding the convex hull of a point set, determining whether two line segments intersect, finding the closest pair of points, or partitioning space for efficient querying. I care about these problems because naive brute-force approaches (checking all pairs of objects, for instance) often scale quadratically or worse, while carefully designed geometric algorithms can achieve much better asymptotic bounds by exploiting spatial structure.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I rely on these foundational ideas:</p>



<ul class="wp-block-list">
<li><strong>Convex hull</strong>: the smallest convex polygon containing a given set of points.</li>



<li><strong>Cross product / orientation test</strong>: determines whether three points make a clockwise, counterclockwise, or collinear turn.</li>



<li><strong>Line segment intersection</strong>: determining whether and where two segments cross.</li>



<li><strong>Plane sweep</strong>: a technique where I move an imaginary line across the plane, processing events (points, segment endpoints) in sorted order.</li>



<li><strong>Voronoi diagram</strong>: a partition of the plane into regions based on proximity to a given set of points.</li>



<li><strong>Delaunay triangulation</strong>: a triangulation maximizing the minimum angle of triangles, dual to the Voronoi diagram.</li>
</ul>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">When I approach a computational geometry problem, I follow this general process:</p>



<ol class="wp-block-list">
<li>I identify the geometric objects involved (points, segments, polygons) and the specific relationship or property I need to compute.</li>



<li>I choose a representation for these objects (coordinate pairs, doubly connected edge lists, etc.).</li>



<li>I select an algorithmic paradigm suited to the problem — sorting-based approaches (for convex hull), divide-and-conquer (for closest pair), or plane sweep (for segment intersection).</li>



<li>I implement geometric primitives carefully (orientation tests, distance calculations), since these are the building blocks every higher-level algorithm depends on.</li>



<li>I combine primitives according to the chosen algorithm, processing objects in a specific order (sorted by angle, by x-coordinate, or by sweep-line event) to achieve the target time complexity.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of most computational geometry algorithms as exploiting <strong>sorted order</strong> and <strong>incremental processing</strong> to avoid redundant pairwise checks. For example, the plane sweep technique works because I only need to compare objects that are &#8220;close&#8221; to the current sweep line position at any given moment, rather than comparing every pair of objects globally — this locality is what allows algorithms like Bentley-Ottmann segment intersection to run in $O((n + k)\log n)$ instead of the naive $O(n^2)$. Convex hull algorithms similarly rely on the geometric fact that hull vertices, when sorted by angle or x-coordinate, form a predictable turning pattern (all left turns or all right turns), which I can verify incrementally using the cross product.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define the cross product of vectors $\vec{OA}$ and $\vec{OB}$ (used for orientation tests) as:</p>



<p class="wp-block-paragraph">$$ \vec{OA} \times \vec{OB} = (A_x &#8211; O_x)(B_y &#8211; O_y) &#8211; (A_y &#8211; O_y)(B_x &#8211; O_x) $$</p>



<p class="wp-block-paragraph">I interpret the sign of this value: positive indicates a counterclockwise turn, negative indicates clockwise, and zero indicates collinearity.</p>



<p class="wp-block-paragraph">I define the Euclidean distance between two points, used in closest-pair algorithms:</p>



<p class="wp-block-paragraph">$$ d(P, Q) = \sqrt{(P_x &#8211; Q_x)^2 + (P_y &#8211; Q_y)^2} $$</p>



<p class="wp-block-paragraph">I state the Graham Scan convex hull algorithm&#8217;s core loop invariant: at every step, the hull points processed so far form a convex polygon, maintained by popping the stack whenever the last three points make a non-counterclockwise turn:</p>



<p class="wp-block-paragraph">$$ \text{cross}(P_{k-2}, P_{k-1}, P_k) \le 0 \implies \text{pop } P_{k-1} $$</p>



<p class="wp-block-paragraph">I state the key recurrence for the closest-pair divide-and-conquer algorithm:</p>



<p class="wp-block-paragraph">$$ T(n) = 2T(n/2) + O(n) $$</p>



<p class="wp-block-paragraph">which, by the Master Theorem, resolves to:</p>



<p class="wp-block-paragraph">$$ T(n) = O(n \log n) $$</p>



<p class="wp-block-paragraph">I justify the linear merge step ($O(n)$) in this recurrence by proving that within the &#8220;strip&#8221; of width $2\delta$ around the dividing line (where $\delta$ is the minimum distance found so far in the two halves), I only need to compare each point against at most 7 other points ahead of it in sorted $y$-order, a geometric packing argument that bounds the number of points that can fit within a $\delta \times 2\delta$ rectangle without violating the minimum distance $\delta$.</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Set of points/segments as input] --> B[Sort by angle, x-coordinate, or build event queue]
    B --> C{Algorithm type}
    C -->|Convex Hull| D[Process points, maintain hull using orientation test]
    C -->|Closest Pair| E[Divide and conquer, check strip near midline]
    C -->|Segment Intersection| F[Sweep line, process events in order]
    D --> G[Return final geometric structure]
    E --> G
    F --> G
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for the Graham Scan convex hull algorithm:</p>



<pre class="wp-block-code"><code>function GRAHAM_SCAN(points):
    p0 = point with lowest y-coordinate (leftmost if tie)
    sort remaining points by polar angle relative to p0

    stack = &#91;p0, points&#91;0], points&#91;1]]

    for i from 2 to length(points) - 1:
        while size(stack) &gt; 1 and
              cross(secondTop(stack), top(stack), points&#91;i]) &lt;= 0:
            pop(stack)
        push(stack, points&#91;i])

    return stack   // the stack now contains the convex hull vertices in order
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I compute the convex hull of the points: $A(0,0)$, $B(2,0)$, $C(2,2)$, $D(0,2)$, $E(1,1)$.</p>



<ol class="wp-block-list">
<li>I select $p_0 = A(0,0)$ as the point with the lowest $y$-coordinate.</li>



<li>I sort the remaining points by polar angle from $A$: $B(2,0)$, $E(1,1)$, $C(2,2)$, $D(0,2)$.</li>



<li>I initialize the stack with $A, B, E$.</li>



<li>I check the turn from $A \to B \to E$: this is a left turn (counterclockwise), so I keep it and push $C$: stack is $A, B, E, C$.</li>



<li>I check the turn from $B \to E \to C$: I compute this as a right turn (clockwise, since $E$ is interior), so I pop $E$: stack is $A, B, C$.</li>



<li>I push $D$: I check the turn $B \to C \to D$, a left turn, so I keep $D$: stack is $A, B, C, D$.</li>
</ol>



<p class="wp-block-paragraph">I obtain the final convex hull: $A(0,0), B(2,0), C(2,2), D(0,2)$ — correctly excluding the interior point $E(1,1)$.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I analyze the Graham Scan convex hull algorithm as $O(n \log n)$ overall — dominated by the initial angular sort, since the scanning phase itself runs in $O(n)$ amortized time (each point is pushed and popped from the stack at most once). I analyze the closest-pair divide-and-conquer algorithm as $O(n \log n)$ as well, per the recurrence solved above. I note that the naive brute-force approach to either problem (checking all pairs for closest pair, or checking all triples for hull membership) runs in $O(n^2)$ or worse, which is precisely why the specialized geometric algorithms matter for large inputs. These bounds represent worst-case behavior; best and average cases for these particular algorithms do not differ asymptotically, since the sorting step dominates regardless of point configuration.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(n)$ space for both the Graham Scan (to store the sorted points and the hull stack) and the closest-pair algorithm (to store the recursive point sets and the strip array during merging). Plane sweep algorithms for segment intersection typically require $O(n + k)$ space, where $k$ is the number of intersection points found, since I maintain an event queue and a sweep-line status structure alongside the output.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify Graham Scan&#8217;s correctness by the loop invariant that the stack always represents a convex polygon over the points processed so far: each time I add a new point, I first remove any points that would create a non-left turn (a reflex angle), guaranteeing the hull property is preserved. Since I process points in angular order around $p_0$, every point that should belong to the hull gets a chance to be added, and every point that lies &#8220;inside&#8221; relative to its neighbors gets correctly popped. I justify the closest-pair algorithm&#8217;s correctness by structural induction on the divide-and-conquer recursion: I assume the recursive calls correctly find the minimum distance within each half, and I prove that the merge step correctly checks the only remaining possibility — a closest pair straddling the dividing line — by scanning the narrow strip described in the Mathematical Foundation section.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I achieve significant asymptotic speedups ($O(n \log n)$) over brute-force ($O(n^2)$ or worse) approaches for many core geometric problems.</li>



<li>Geometric algorithms generalize well, forming reusable primitives (orientation tests, distance calculations) that combine to solve more complex problems.</li>



<li>Plane sweep and divide-and-conquer paradigms transfer to a wide range of related geometric problems beyond the original use case.</li>



<li>Many computational geometry algorithms have elegant, verifiable correctness proofs rooted in provable geometric properties.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find that geometric algorithms are notoriously sensitive to floating-point precision issues, where small numerical errors can cause incorrect orientation tests or missed intersections.</li>



<li>Implementing robust geometric predicates (handling degenerate cases like collinear points) is more intricate than the basic algorithmic idea suggests.</li>



<li>Some higher-dimensional geometric problems (beyond 2D/3D) suffer from the curse of dimensionality, making efficient algorithms much harder to design.</li>



<li>Certain geometric data structures (like fully dynamic Voronoi diagrams) are complex to implement and maintain efficiently under insertions and deletions.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply computational geometry in:</p>



<ul class="wp-block-list">
<li><strong>Geographic Information Systems (GIS)</strong>: point-in-polygon tests, map overlay, and spatial indexing.</li>



<li><strong>Computer graphics</strong>: collision detection, visibility determination, and mesh generation.</li>



<li><strong>Robotics</strong>: motion planning and obstacle avoidance using configuration space geometry.</li>



<li><strong>Computer-aided design (CAD)</strong>: geometric modeling and boundary representation of 3D objects.</li>



<li><strong>Wireless networking</strong>: Voronoi diagrams model coverage regions for cell towers.</li>



<li><strong>Machine learning</strong>: nearest-neighbor search and clustering rely on geometric proximity structures like k-d trees.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement the orientation test and a basic convex hull check using the gift wrapping (Jarvis March) idea for a small point set, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>

typedef struct {
    int x, y;
} Point;

// I compute the cross product to determine orientation of triplet (O, A, B)
// Positive: counterclockwise, Negative: clockwise, Zero: collinear
long cross(Point O, Point A, Point B) {
    return (long)(A.x - O.x) * (B.y - O.y) - (long)(A.y - O.y) * (B.x - O.x);
}

int main() {
    Point points[] = {{0,0}, {2,0}, {2,2}, {0,2}, {1,1}};
    int n = 5;

    // I find the point with the lowest y-coordinate (leftmost if tie)
    int start = 0;
    for (int i = 1; i &lt; n; i++) {
        if (points&#91;i&#93;.y &lt; points&#91;start&#93;.y ||
           (points&#91;i&#93;.y == points&#91;start&#93;.y &amp;&amp; points&#91;i&#93;.x &lt; points&#91;start&#93;.x)) {
            start = i;
        }
    }

    printf("Starting hull point: (%d, %d)\n", points&#91;start&#93;.x, points&#91;start&#93;.y);

    // I demonstrate the orientation test on a sample triplet
    Point O = points&#91;0&#93;, A = points&#91;1&#93;, B = points&#91;4&#93;;
    long orientation = cross(O, A, B);

    if (orientation > 0) {
        printf("Turn from O->A->B is counterclockwise\n");
    } else if (orientation &lt; 0) {
        printf("Turn from O->A->B is clockwise\n");
    } else {
        printf("Points O, A, B are collinear\n");
    }

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> x</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> y</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> Point</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I compute the cross product to determine orientation of triplet (O, A, B)</span></span>
<span class="line"><span style="color: #616E88">// Positive: counterclockwise, Negative: clockwise, Zero: collinear</span></span>
<span class="line"><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">cross</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">Point </span><span style="color: #D8DEE9">O</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> Point </span><span style="color: #D8DEE9">A</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> Point </span><span style="color: #D8DEE9">B</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">long</span><span style="color: #ECEFF4">)(</span><span style="color: #D8DEE9">A</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">x</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">O</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">x</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">B</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">O</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">y</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">long</span><span style="color: #ECEFF4">)(</span><span style="color: #D8DEE9">A</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">O</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">y</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9">B</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">x</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">O</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">x</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    Point points</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">},</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">,</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">}}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">5</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I find the point with the lowest y-coordinate (leftmost if tie)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> start </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">start</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span></span>
<span class="line"><span style="color: #D8DEE9FF">           </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">start</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">y</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">x</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">start</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">x</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            start </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Starting hull point: (%d, %d)</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">start</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">x</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">start</span><span style="color: #ECEFF4">&#93;.</span><span style="color: #D8DEE9">y</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I demonstrate the orientation test on a sample triplet</span></span>
<span class="line"><span style="color: #D8DEE9FF">    Point O </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;,</span><span style="color: #D8DEE9FF"> A </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;,</span><span style="color: #D8DEE9FF"> B </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> points</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">long</span><span style="color: #D8DEE9FF"> orientation </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">cross</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">O</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> A</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> B</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">orientation </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Turn from O-&gt;A-&gt;B is counterclockwise</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">orientation </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Turn from O-&gt;A-&gt;B is clockwise</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Points O, A, B are collinear</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I hardcode the point set $A(0,0), B(2,0), C(2,2), D(0,2), E(1,1)$ from the walkthrough, and I expect:</p>



<pre class="wp-block-code"><code>Starting hull point: (0, 0)
Turn from O-&gt;A-&gt;B is clockwise
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I use k-d trees or range trees to accelerate nearest-neighbor and range-query operations from $O(n)$ per query down to $O(\log n)$ after preprocessing.</li>



<li>I apply rotating calipers technique to solve problems like finding the diameter of a convex polygon in $O(n)$ time after the hull is computed.</li>



<li>I use fortune&#8217;s algorithm (a specialized plane sweep) to construct Voronoi diagrams in optimal $O(n \log n)$ time.</li>



<li>I apply exact arithmetic or carefully designed epsilon-tolerant comparisons to mitigate floating-point robustness issues in orientation tests.</li>



<li>I use spatial partitioning structures (quad-trees, grids) to reduce the number of pairwise geometric checks needed in collision detection systems.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes forget to handle collinear points as a special case in convex hull algorithms, leading to incorrect hull boundaries.</li>



<li>I use floating-point equality checks directly for geometric predicates instead of epsilon-tolerant comparisons, causing subtle bugs from precision errors.</li>



<li>I mismanage the sorting step in Graham Scan, forgetting to break angular ties by distance from the starting point, which can corrupt the scan.</li>



<li>I forget to consider the &#8220;0/1 point&#8221; edge cases (empty input, single point, or all collinear points) when implementing geometric algorithms.</li>



<li>I assume 2D geometric intuition transfers directly to 3D problems without adjustment, missing important differences in complexity and predicate design.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>de Berg, M., Cheong, O., van Kreveld, M., &amp; Overmars, M. <em>Computational Geometry: Algorithms and Applications</em>: https://link.springer.com/book/10.1007/978-3-540-77974-2</li>



<li>Preparata, F. P., &amp; Shamos, M. I. <em>Computational Geometry: An Introduction</em>: https://link.springer.com/book/10.1007/978-1-4612-1098-6</li>



<li>O&#8217;Rourke, J. <em>Computational Geometry in C</em>: https://www.cs.jhu.edu/~misha/Spring20/ORourke98.pdf</li>



<li>CGAL (Computational Geometry Algorithms Library) documentation: https://www.cgal.org/</li>



<li>Shamos, M. I. (1978). &#8220;Computational Geometry&#8221; PhD Thesis, Yale University: https://www.cs.cmu.edu/~shamos/</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/computational-geometry-key-algorithms-and-practical-implementations/">Computational Geometry: Key Algorithms and Practical Implementations</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/computational-geometry-key-algorithms-and-practical-implementations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10883</post-id>	</item>
		<item>
		<title>Knuth-Morris-Pratt (KMP) Algorithm: Detailed Explanation and Implementation</title>
		<link>https://awjunaid.com/algorithm/knuth-morris-pratt-kmp-algorithm-detailed-explanation-and-implementation/</link>
					<comments>https://awjunaid.com/algorithm/knuth-morris-pratt-kmp-algorithm-detailed-explanation-and-implementation/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 15:53:12 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10880</guid>

					<description><![CDATA[<p>I use the Knuth-Morris-Pratt (KMP) algorithm whenever I need to search for occurrences of a pattern string within&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/knuth-morris-pratt-kmp-algorithm-detailed-explanation-and-implementation/">Knuth-Morris-Pratt (KMP) Algorithm: Detailed Explanation and Implementation</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use the Knuth-Morris-Pratt (KMP) algorithm whenever I need to search for occurrences of a pattern string within a text string efficiently, without the wasted work that a naive approach incurs from repeatedly re-checking characters I&#8217;ve already compared. I consider KMP an essential building block in string processing because it guarantees linear-time matching, which I rely on constantly in text editors, search utilities, bioinformatics tools, and network intrusion detection systems.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the KMP algorithm to a 1970 discovery by Donald Knuth and Vaughan Pratt, developed independently around the same time by James H. Morris, with all three ultimately publishing the combined result in 1977 as &#8220;Fast Pattern Matching in Strings&#8221; in the SIAM Journal on Computing. I note that the motivation partly came from a theoretical result by Cook that showed pattern matching could be done on a certain class of automata within linear time, which Knuth, Morris, and Pratt then turned into a practical, implementable algorithm. I regard this discovery as a foundational moment in string algorithms, since it was among the first to demonstrate that avoiding redundant comparisons through clever preprocessing could take a quadratic-looking problem down to linear time.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use KMP to solve the classic pattern-matching problem: given a text $T$ of length $n$ and a pattern $P$ of length $m$, I want to find all occurrences (or the first occurrence) of $P$ within $T$. I want to avoid the inefficiency of the naive algorithm, which in the worst case re-examines characters of $T$ multiple times, leading to $O(nm)$ time. I want an algorithm that never needs to move backward in the text, examining each text character a bounded number of times.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I rely on the concept of the <strong>failure function</strong> (also called the <strong>prefix function</strong> or <strong>partial match table</strong>), denoted $\pi$, where $\pi[i]$ represents the length of the longest proper prefix of $P[0..i]$ that is also a suffix of $P[0..i]$. I use this table to determine, upon a mismatch during matching, exactly how far I can safely shift the pattern without missing any potential match — because I already know, from the failure function, which portion of the pattern I&#8217;ve already confirmed matches.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">I follow this two-phase process when performing KMP matching:</p>



<ol class="wp-block-list">
<li><strong>Preprocessing phase</strong>: I compute the failure function $\pi$ for the pattern $P$, which encodes self-overlap information within the pattern itself.</li>



<li><strong>Matching phase</strong>: I scan the text $T$ left to right, comparing characters against the pattern. When I find a mismatch at pattern position $j$, instead of restarting the pattern comparison from the beginning, I use $\pi[j-1]$ to determine the next pattern position to compare from, without moving the text pointer backward.</li>



<li>Whenever I match the entire pattern (reach $j = m$), I record a match and continue searching by resetting $j$ to $\pi[j-1]$, in case there are overlapping occurrences.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of KMP as exploiting the self-similarity of the pattern to avoid redundant work. When a mismatch occurs after matching some prefix of the pattern, I know exactly which characters of the text I&#8217;ve already seen (they match a prefix of the pattern). Since the failure function already tells me the longest prefix of the pattern that is also a suffix of what I&#8217;ve matched so far, I can &#8220;slide&#8221; the pattern forward to align this known-good suffix with the corresponding prefix, without ever needing to re-examine text characters I&#8217;ve already compared. This is the key mechanism that keeps the text pointer moving strictly forward throughout the entire algorithm.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define the failure function formally:</p>



<p class="wp-block-paragraph">$$ \pi[i] = \max{ k : k &lt; i+1, \ P[0..k-1] = P[i-k+1..i] } $$</p>



<p class="wp-block-paragraph">with $\pi[0] = 0$ by convention (a single character has no proper prefix).</p>



<p class="wp-block-paragraph">I prove the linear-time bound of the matching phase using an <strong>amortized analysis</strong> based on a potential function. I define the potential as the current value of $j$ (the number of pattern characters matched so far). I note that:</p>



<ul class="wp-block-list">
<li>Each successful character comparison increases $j$ by 1, and the text pointer $i$ also always increases by 1 per outer loop iteration.</li>



<li>Each failed comparison decreases $j$ (via $j = \pi[j-1]$) but does not increase $i$.</li>
</ul>



<p class="wp-block-paragraph">Since $j$ can increase at most $n$ times total (bounded by the number of times $i$ advances) across the entire matching phase, and each decrease of $j$ must be &#8220;paid for&#8221; by a prior increase, I conclude the total number of comparisons is bounded by $2n = O(n)$.</p>



<p class="wp-block-paragraph">I similarly bound the failure function computation itself at $O(m)$ using the identical amortized argument applied to the pattern against itself.</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Input: text T, pattern P] --> B[Compute failure function pi for P]
    B --> C[Initialize text pointer i = 0, pattern pointer j = 0]
    C --> D{T i equals P j?}
    D -->|Yes| E[Increment i and j]
    E --> F{j equals length of P?}
    F -->|Yes| G[Record match at i - j]
    G --> H[Set j = pi j-1, continue]
    F -->|No| I{i reached end of T?}
    D -->|No, and j > 0| J[Set j = pi j-1]
    J --> D
    D -->|No, and j == 0| K[Increment i only]
    K --> I
    H --> I
    I -->|No| D
    I -->|Yes| L[Return all matches]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write the pseudocode for computing the failure function and performing the search:</p>



<pre class="wp-block-code"><code>function COMPUTE_FAILURE(P):
    m = length(P)
    pi = array of size m, initialized to 0
    k = 0

    for i from 1 to m - 1:
        while k &gt; 0 and P&#91;i] != P&#91;k]:
            k = pi&#91;k - 1]
        if P&#91;i] == P&#91;k]:
            k = k + 1
        pi&#91;i] = k

    return pi

function KMP_SEARCH(T, P):
    n = length(T)
    m = length(P)
    pi = COMPUTE_FAILURE(P)
    j = 0
    matches = empty list

    for i from 0 to n - 1:
        while j &gt; 0 and T&#91;i] != P&#91;j]:
            j = pi&#91;j - 1]
        if T&#91;i] == P&#91;j]:
            j = j + 1
        if j == m:
            matches.append(i - m + 1)
            j = pi&#91;j - 1]

    return matches
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I search for pattern $P = \text{&#8220;ababaca&#8221;}$&#8217;s failure function first, then match text $T = \text{&#8220;bacbababaca&#8221;}$ against $P = \text{&#8220;ababaca&#8221;}$.</p>



<p class="wp-block-paragraph"><strong>Computing $\pi$ for &#8220;ababaca&#8221;:</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>i</th><th>P[i]</th><th>k before</th><th>k after</th><th>pi[i]</th></tr></thead><tbody><tr><td>0</td><td>a</td><td>&#8211;</td><td>&#8211;</td><td>0</td></tr><tr><td>1</td><td>b</td><td>0</td><td>0</td><td>0</td></tr><tr><td>2</td><td>a</td><td>0</td><td>1</td><td>1</td></tr><tr><td>3</td><td>b</td><td>1</td><td>2</td><td>2</td></tr><tr><td>4</td><td>a</td><td>2</td><td>3</td><td>3</td></tr><tr><td>5</td><td>c</td><td>3</td><td>0</td><td>0</td></tr><tr><td>6</td><td>a</td><td>0</td><td>1</td><td>1</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">I obtain $\pi = [0, 0, 1, 2, 3, 0, 1]$.</p>



<p class="wp-block-paragraph"><strong>Matching against $T = \text{&#8220;bacbababaca&#8221;}$:</strong></p>



<p class="wp-block-paragraph">I scan through the text, and I find that starting at text index 4, the substring &#8220;bababaca&#8221;&#8230; wait, I check carefully: at $i=10$ (0-indexed, end of text), I complete matching the full pattern &#8220;ababaca&#8221; starting at text index 4. I record a match at position 4, and thanks to the failure function, I never had to move the text pointer backward even when earlier partial matches failed.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I establish that KMP runs in $O(n + m)$ time overall: $O(m)$ for computing the failure function and $O(n)$ for the matching phase, both justified by the amortized analysis in the Mathematical Foundation section. This bound holds in the best, average, and worst case alike — unlike the naive algorithm, whose worst case is $O(nm)$ (for example, matching &#8220;aaaa&#8230;a&#8221; against a long run of a&#8217;s), KMP guarantees linear time regardless of the input&#8217;s specific structure, because the text pointer never moves backward.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(m)$ additional space to store the failure function table, where $m$ is the pattern length. I need no extra space proportional to the text length $n$, since I process the text in a single forward pass using only a constant number of index variables ($i$, $j$) beyond the failure table itself.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the correctness of the failure function computation by induction on $i$: I assume $\pi[0..i-1]$ are all correct, and I show that the while loop, which repeatedly falls back to $\pi[k-1]$ upon mismatch, correctly finds the longest proper prefix-suffix match for position $i$ by trying progressively shorter candidate overlaps until one succeeds or none remain. I justify the matching phase&#8217;s correctness similarly: whenever a mismatch occurs, falling back to $j = \pi[j-1]$ preserves the invariant that the characters of $T$ already compared still match the corresponding prefix of $P$ up to the new, shorter value of $j$ — no valid match is ever skipped, because any match starting within the discarded region would have required a longer prefix-suffix overlap than $\pi[j-1]$ allows, which the failure function already ruled out as impossible.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I guarantee linear-time, $O(n+m)$, matching regardless of the input, unlike the naive algorithm&#8217;s worst-case quadratic behavior.</li>



<li>I never need to backtrack in the text, which makes KMP suitable for streaming input where I cannot re-read previous characters.</li>



<li>The failure function preprocessing is reusable across multiple searches of the same pattern against different texts.</li>



<li>KMP is deterministic and doesn&#8217;t rely on hashing, so I avoid the (rare) risk of hash collisions that algorithms like Rabin-Karp face.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I find the failure function construction and the fallback logic conceptually more intricate than simpler (though slower) algorithms like the naive approach or even Boyer-Moore&#8217;s simpler heuristics.</li>



<li>KMP does not take advantage of information about the alphabet size the way Boyer-Moore&#8217;s bad character heuristic does, so in practice it can be slower than Boyer-Moore on typical English text searches.</li>



<li>Implementing KMP correctly requires careful off-by-one handling in the failure function and matching loop, which I find is a common source of bugs.</li>



<li>KMP handles only exact string matching; it does not natively support approximate matching or wildcards without significant modification.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply KMP in:</p>



<ul class="wp-block-list">
<li><strong>Text editors and search utilities</strong>: implementing fast &#8220;find&#8221; functionality.</li>



<li><strong>Bioinformatics</strong>: searching for DNA or protein subsequences within large genomic datasets.</li>



<li><strong>Network security</strong>: intrusion detection systems scanning packet payloads for known attack signatures.</li>



<li><strong>Data compression</strong>: some LZ-family compression algorithms use KMP-like matching to find repeated substrings.</li>



<li><strong>Plagiarism detection</strong>: searching for exact matching passages across large document corpora.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement the KMP algorithm in C, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;string.h>

// I compute the failure function (partial match table) for pattern P
void computeFailure(char* P, int m, int* pi) {
    pi&#91;0&#93; = 0;
    int k = 0;

    for (int i = 1; i &lt; m; i++) {
        while (k > 0 &amp;&amp; P&#91;i&#93; != P&#91;k&#93;) {
            k = pi&#91;k - 1&#93;; // I fall back using the failure function
        }
        if (P&#91;i&#93; == P&#91;k&#93;) {
            k++;
        }
        pi&#91;i&#93; = k;
    }
}

// I search for pattern P within text T using the KMP algorithm
void kmpSearch(char* T, char* P) {
    int n = strlen(T);
    int m = strlen(P);
    int pi&#91;m&#93;;

    computeFailure(P, m, pi);

    int j = 0; // number of characters of P currently matched
    for (int i = 0; i &lt; n; i++) {
        while (j > 0 &amp;&amp; T&#91;i&#93; != P&#91;j&#93;) {
            j = pi&#91;j - 1&#93;;
        }
        if (T&#91;i&#93; == P&#91;j&#93;) {
            j++;
        }
        if (j == m) {
            printf("Match found at index %d\n", i - m + 1);
            j = pi&#91;j - 1&#93;; // I continue searching for further matches
        }
    }
}

int main() {
    char T[] = "bacbababaca";
    char P[] = "ababaca";

    kmpSearch(T, P);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">string.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I compute the failure function (partial match table) for pattern P</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">computeFailure</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">pi</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> k </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">k </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">k</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            k </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">k </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I fall back using the failure function</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">k</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            k</span><span style="color: #81A1C1">++;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> k</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I search for pattern P within text T using the KMP algorithm</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">kmpSearch</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">P</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">m</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">computeFailure</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> pi</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // number of characters of P currently matched</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">j </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            j</span><span style="color: #81A1C1">++;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">j </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Match found at index %d</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            j </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> pi</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">j </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I continue searching for further matches</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">char</span><span style="color: #D8DEE9FF"> T</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">bacbababaca</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">char</span><span style="color: #D8DEE9FF"> P</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ababaca</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">kmpSearch</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I use <code>T = "bacbababaca"</code> and <code>P = "ababaca"</code> as input, and I expect:</p>



<pre class="wp-block-code"><code>Match found at index 4
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I precompute and cache the failure function whenever I need to search for the same pattern across multiple texts, avoiding redundant preprocessing.</li>



<li>I combine KMP with the Aho-Corasick algorithm when I need to search for multiple patterns simultaneously, extending the failure-function idea to a trie structure.</li>



<li>I use bitwise parallel matching techniques (like the Shift-And/Shift-Or algorithm) as an alternative when the pattern is short enough to fit within machine word size, sometimes outperforming KMP in practice.</li>



<li>I apply KMP&#8217;s failure function concept in related string algorithms, like computing the shortest period of a string, since $m &#8211; \pi[m-1]$ gives the length of the smallest repeating unit.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes confuse the failure function index conventions (0-indexed vs 1-indexed), leading to off-by-one errors in the fallback logic.</li>



<li>I forget to reset $j$ using the failure function after finding a match, missing overlapping occurrences of the pattern.</li>



<li>I incorrectly initialize $\pi[0]$ to a nonzero value, violating the definition that a single character has no proper prefix.</li>



<li>I mistakenly apply the naive matching logic (resetting $j$ to 0 on every mismatch) instead of using the failure function, which silently degrades performance back to quadratic time while still &#8220;working&#8221; on small test cases.</li>



<li>I overlook edge cases like an empty pattern or a pattern longer than the text, causing out-of-bounds access.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Knuth, D. E., Morris, J. H., &amp; Pratt, V. R. (1977). &#8220;Fast Pattern Matching in Strings.&#8221; SIAM Journal on Computing: https://epubs.siam.org/doi/10.1137/0206024</li>



<li>Cormen, T. H., Leiserson, C. E., Rivest, R. L., &amp; Stein, C. <em>Introduction to Algorithms</em> (string matching chapter): https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/</li>



<li>Gusfield, D. <em>Algorithms on Strings, Trees, and Sequences</em>: https://www.cambridge.org/core/books/algorithms-on-strings-trees-and-sequences/F0B095049C7E62D2FF6746DE39D65D22</li>



<li>MIT OpenCourseWare, 6.006 Introduction to Algorithms (string matching lecture): https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/</li>



<li>GeeksforGeeks, &#8220;KMP Algorithm for Pattern Searching&#8221;: https://www.geeksforgeeks.org/dsa/kmp-algorithm-for-pattern-searching/</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/knuth-morris-pratt-kmp-algorithm-detailed-explanation-and-implementation/">Knuth-Morris-Pratt (KMP) Algorithm: Detailed Explanation and Implementation</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/knuth-morris-pratt-kmp-algorithm-detailed-explanation-and-implementation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10880</post-id>	</item>
		<item>
		<title>String Matching with Finite Automata: Complete Guide with Examples</title>
		<link>https://awjunaid.com/algorithm/string-matching-with-finite-automata-complete-guide-with-examples/</link>
					<comments>https://awjunaid.com/algorithm/string-matching-with-finite-automata-complete-guide-with-examples/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 15:50:49 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10877</guid>

					<description><![CDATA[<p>I use the finite automaton approach to string matching whenever I want to search for a pattern in&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/string-matching-with-finite-automata-complete-guide-with-examples/">String Matching with Finite Automata: Complete Guide with Examples</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use the finite automaton approach to string matching whenever I want to search for a pattern in a text using a precomputed state machine that examines each text character exactly once. I think of this method as building a specialized machine, tailored to a specific pattern, that transitions between states representing &#8220;how much of the pattern have I matched so far,&#8221; and reaches an accepting state precisely when the pattern has been found. I find this approach conceptually elegant because it separates the matching logic (a generic automaton simulation) from the pattern-specific knowledge (encoded entirely in the precomputed transition table).</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the theoretical foundation of automaton-based string matching to the broader development of automata theory in the 1950s, particularly the work of Stephen Kleene on regular expressions and finite automata, and Michael Rabin and Dana Scott&#8217;s 1959 paper formalizing nondeterministic automata. I see the specific application to string matching popularized through its treatment in Cormen, Leiserson, Rivest, and Stein&#8217;s <em>Introduction to Algorithms</em>, which presents it as a natural bridge between formal automata theory and practical string search algorithms, and closely related in spirit to the automaton implicit within the KMP algorithm&#8217;s failure function. I regard this method as historically important because it demonstrates the deep connection between string matching and formal language theory — the pattern-matching automaton is, in essence, a deterministic finite automaton recognizing the language of all strings ending in the pattern $P$.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use the finite automaton method to solve the same fundamental problem as other string-matching algorithms: given a text $T$ of length $n$ and a pattern $P$ of length $m$, I want to find all positions where $P$ occurs in $T$. I want an algorithm where, once I&#8217;ve built the automaton, each character of the text is processed in strictly constant time per character, giving me a clean linear-time guarantee on the scanning phase, independent of how the automaton itself was constructed.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I build a deterministic finite automaton (DFA) with $m+1$ states, labeled $0$ through $m$, where state $q$ represents &#8220;the longest prefix of $P$ that is a suffix of the text read so far has length $q$.&#8221; I define a <strong>transition function</strong> $\delta(q, c)$ that, given the current state $q$ and the next character $c$ read from the text, returns the next state. State $m$ (having matched the entire pattern) is the unique <strong>accepting state</strong>. I rely on the concept of the <strong>alphabet</strong> $\Sigma$, since the transition function must be defined for every state and every possible character in $\Sigma$.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">I follow this process when applying the automaton-based method:</p>



<ol class="wp-block-list">
<li><strong>Construction phase</strong>: I build the transition table $\delta(q, c)$ for every state $q \in {0, \ldots, m}$ and every character $c \in \Sigma$, based on the pattern $P$.</li>



<li><strong>Matching phase</strong>: I initialize the current state $q = 0$, then scan the text left to right, updating $q = \delta(q, T[i])$ for each character.</li>



<li>Whenever $q$ reaches $m$ (the accepting state), I record a match ending at the current text position.</li>



<li>I continue scanning until the end of the text, since the automaton naturally continues seeking further matches without any special reset logic.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of this method as precomputing, once and for all, the answer to the question &#8220;if I&#8217;m currently in a state representing $q$ matched characters, and I see character $c$ next, what is the new longest matched prefix?&#8221; This requires checking, for every possible next character, what the longest prefix of $P$ that is also a suffix of $(P[0..q-1] + c)$ would be. Because this computation is done entirely during construction, the matching phase itself becomes trivial: I simply follow precomputed transitions, examining each text character exactly once with $O(1)$ work per character, regardless of how complex the pattern&#8217;s internal structure is.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I define the transition function formally:</p>



<p class="wp-block-paragraph">$$ \delta(q, c) = \text{length of the longest prefix of } P \text{ that is a suffix of } P[0..q-1] + c $$</p>



<p class="wp-block-paragraph">I compute this using the following characterization, which I use directly in the construction algorithm: I check, for $k$ from $\min(m, q+1)$ down to $0$, whether $P[0..k-1]$ is a suffix of $P[0..q-1] + c$, and I take the largest such $k$.</p>



<p class="wp-block-paragraph">I state the time complexity of the naive construction algorithm, which checks this condition directly for every state and character:</p>



<p class="wp-block-paragraph">$$ O(m^3 |\Sigma|) $$</p>



<p class="wp-block-paragraph">since for each of the $m+1$ states and $|\Sigma|$ characters, I may need up to $O(m)$ candidate lengths $k$, each requiring an $O(m)$ suffix comparison.</p>



<p class="wp-block-paragraph">I note that a more refined construction algorithm, which reuses previously computed transitions (similar in spirit to the KMP failure function), reduces this to:</p>



<p class="wp-block-paragraph">$$ O(m|\Sigma|) $$</p>



<p class="wp-block-paragraph">by computing $\delta(q, c)$ in terms of $\delta(\pi[q-1], c)$ when $c \neq P[q]$, where $\pi$ is the KMP-style failure function — avoiding redundant recomputation from scratch for every state.</p>



<p class="wp-block-paragraph">I formally justify the matching phase&#8217;s $O(n)$ scanning time since exactly one transition, an $O(1)$ table lookup, is performed per text character:</p>



<p class="wp-block-paragraph">$$ T_{\text{match}}(n) = O(n) $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Input: pattern P, alphabet Sigma] --> B[Build transition table delta for states 0..m]
    B --> C[Initialize state q = 0]
    C --> D[Read next character c from text T]
    D --> E[Set q = delta of q and c]
    E --> F{q equals m?}
    F -->|Yes| G[Record match, continue scanning]
    F -->|No| H{More text remaining?}
    G --> H
    H -->|Yes| D
    H -->|No| I[Return all matches]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write pseudocode for both constructing the automaton (naive version, for clarity) and using it to scan the text:</p>



<pre class="wp-block-code"><code>function COMPUTE_TRANSITION_TABLE(P, Sigma):
    m = length(P)
    delta = table of size (m+1) x |Sigma|

    for q from 0 to m:
        for each character c in Sigma:
            k = min(m, q + 1)
            while k &gt; 0 and NOT IS_SUFFIX(P&#91;0..k-1], P&#91;0..q-1] + c):
                k = k - 1
            delta&#91;q]&#91;c] = k

    return delta

function FA_STRING_MATCHER(T, P, delta):
    n = length(T)
    m = length(P)
    q = 0
    matches = empty list

    for i from 0 to n - 1:
        q = delta&#91;q]&#91;T&#91;i]]
        if q == m:
            matches.append(i - m + 1)

    return matches
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I build the automaton for pattern $P = \text{&#8220;aba&#8221;}$ over alphabet ${a, b}$, then match against text $T = \text{&#8220;ababa&#8221;}$.</p>



<p class="wp-block-paragraph"><strong>Transition table for &#8220;aba&#8221;:</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>State $q$</th><th>on &#8216;a&#8217;</th><th>on &#8216;b&#8217;</th></tr></thead><tbody><tr><td>0</td><td>1</td><td>0</td></tr><tr><td>1</td><td>1</td><td>2</td></tr><tr><td>2</td><td>3</td><td>0</td></tr><tr><td>3 (accept)</td><td>1</td><td>2</td></tr></tbody></table></figure>



<p class="wp-block-paragraph"><strong>Scanning $T = \text{&#8220;ababa&#8221;}$:</strong></p>



<ol class="wp-block-list">
<li>Start at $q=0$. Read &#8216;a&#8217;: $q = \delta(0, a) = 1$.</li>



<li>Read &#8216;b&#8217;: $q = \delta(1, b) = 2$.</li>



<li>Read &#8216;a&#8217;: $q = \delta(2, a) = 3$. State 3 is accepting — I record a match ending at index 2 (starting at index 0).</li>



<li>Read &#8216;b&#8217;: $q = \delta(3, b) = 2$.</li>



<li>Read &#8216;a&#8217;: $q = \delta(2, a) = 3$. Accepting again — I record a match ending at index 4 (starting at index 2).</li>
</ol>



<p class="wp-block-paragraph">I find matches starting at text indices 0 and 2, correctly identifying both overlapping occurrences of &#8220;aba&#8221; in &#8220;ababa&#8221;.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I establish that the matching phase runs in $O(n)$ time, since I perform exactly one table lookup per text character. I establish that the naive construction phase runs in $O(m^3|\Sigma|)$ time, though the optimized construction (reusing KMP-style failure information) reduces this to $O(m|\Sigma|)$. I note the combined complexity is $O(m|\Sigma| + n)$ using the optimized construction, which I consider excellent when the same automaton is reused across many different texts, since the (often larger) construction cost is paid only once. This bound holds uniformly across best, average, and worst cases for the matching phase, since exactly $n$ transitions are always performed regardless of the text&#8217;s content.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require $O(m|\Sigma|)$ space to store the full transition table, since I need an entry for every combination of state (there are $m+1$ of them) and character in the alphabet. I consider this the primary drawback relative to KMP, which requires only $O(m)$ space for its failure function table — the automaton trades additional space for simpler, branch-free matching logic.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the correctness of the automaton by the invariant maintained at every state $q$: after processing text position $i$, $q$ always equals the length of the longest prefix of $P$ that is also a suffix of $T[0..i]$. I prove this invariant is preserved by the transition function&#8217;s definition itself — $\delta(q,c)$ is defined precisely as the new longest matching prefix-suffix length after appending character $c$ to a text whose current longest matching prefix-suffix has length $q$. Since this invariant holds after every character, whenever $q$ reaches $m$, I have proven that the full pattern $P$ is exactly a suffix of the text read so far — meaning a match has genuinely occurred ending at the current position, with no false positives or missed matches possible given the invariant.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I achieve branch-free, constant-time-per-character matching once the automaton is built, since each step is a simple table lookup with no conditional fallback logic (unlike KMP&#8217;s while loop).</li>



<li>The automaton model connects string matching cleanly to the broader theory of regular languages and finite automata, which I find valuable for teaching and formal reasoning.</li>



<li>I can reuse a constructed automaton across arbitrarily many text scans without any reconstruction cost.</li>



<li>The approach generalizes naturally to matching against modified or combined patterns by adjusting the automaton&#8217;s states and transitions.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I incur significant space overhead, $O(m|\Sigter|)$, especially for large alphabets like Unicode, compared to KMP&#8217;s more compact $O(m)$ failure function.</li>



<li>The naive construction algorithm is relatively expensive, $O(m^3|\Sigma|)$, unless I implement the more sophisticated failure-function-based construction.</li>



<li>I find the automaton, once built, is fixed to a specific pattern — any change to the pattern requires full reconstruction of the transition table.</li>



<li>Implementing the optimized construction algorithm correctly is more involved than implementing KMP directly, since it requires understanding both automaton theory and the KMP failure function simultaneously.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply automaton-based string matching in:</p>



<ul class="wp-block-list">
<li><strong>Compiler design</strong>: lexical analyzers are themselves finite automata that tokenize source code, a closely related application of the same theory.</li>



<li><strong>Network intrusion detection</strong>: hardware-accelerated automaton matching scans packet streams for attack signatures at line rate.</li>



<li><strong>Text processing utilities</strong>: some implementations of grep-like tools use automaton-based matching internally, especially for regular-expression search (a generalization of exact pattern matching).</li>



<li><strong>Bioinformatics</strong>: automaton-based scanning of DNA sequences for known motifs.</li>



<li><strong>Digital circuit design</strong>: string-matching automata can be directly synthesized into hardware finite-state machines for high-throughput pattern detection.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement the automaton-based string matcher in C, using the naive construction algorithm for clarity, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;string.h>

#define ALPHABET_SIZE 256

// I check whether string 'a' (of given length) is a suffix of string 'b' (of given length)
int isSuffix(const char* a, int aLen, const char* b, int bLen) {
    if (aLen > bLen) return 0;
    return strncmp(a, b + (bLen - aLen), aLen) == 0;
}

// I build the transition table for pattern P using the naive O(m^3 * |Sigma|) method
void buildAutomaton(const char* P, int m, int delta[]&#91;ALPHABET_SIZE&#93;) {
    for (int q = 0; q &lt;= m; q++) {
        for (int c = 0; c &lt; ALPHABET_SIZE; c++) {
            int k = (m &lt; q + 1) ? m : q + 1;

            char extended&#91;m + 2&#93;;
            memcpy(extended, P, q);
            extended&#91;q&#93; = (char)c;
            int extendedLen = q + 1;

            while (k > 0 &amp;&amp; !isSuffix(P, k, extended, extendedLen)) {
                k--;
            }
            delta&#91;q&#93;&#91;c&#93; = k;
        }
    }
}

// I scan text T using the precomputed automaton
void faStringMatcher(const char* T, int n, int m, int delta[]&#91;ALPHABET_SIZE&#93;) {
    int q = 0;
    for (int i = 0; i &lt; n; i++) {
        q = delta&#91;q&#93;[(unsigned char)T&#91;i&#93;];
        if (q == m) {
            printf("Match found at index %d\n", i - m + 1);
        }
    }
}

int main() {
    const char* P = "aba";
    const char* T = "ababa";
    int m = strlen(P);
    int n = strlen(T);

    static int delta&#91;4&#93;&#91;ALPHABET_SIZE&#93;; // m+1 states for pattern "aba"

    buildAutomaton(P, m, delta);
    faStringMatcher(T, n, m, delta);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">string.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">ALPHABET_SIZE</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">256</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I check whether string &#39;a&#39; (of given length) is a suffix of string &#39;b&#39; (of given length)</span></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">isSuffix</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">aLen</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">b</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bLen</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">aLen </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> bLen</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strncmp</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">a</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> b </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">bLen </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> aLen</span><span style="color: #ECEFF4">),</span><span style="color: #D8DEE9FF"> aLen</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I build the transition table for pattern P using the naive O(m^3 * |Sigma|) method</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buildAutomaton</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #81A1C1">[]</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">ALPHABET_SIZE</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> q</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> c </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> c </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> ALPHABET_SIZE</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> c</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> k </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">m </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">?</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">:</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">char</span><span style="color: #D8DEE9FF"> extended</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">m </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">memcpy</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">extended</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> q</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            extended</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">q</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">char</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">c</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> extendedLen </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">k </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">isSuffix</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> k</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> extended</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> extendedLen</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                k</span><span style="color: #81A1C1">--;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">            delta</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">q</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">c</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> k</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I scan text T using the precomputed automaton</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">faStringMatcher</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #81A1C1">[]</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">ALPHABET_SIZE</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> q </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        q </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">q</span><span style="color: #ECEFF4">&#93;[(</span><span style="color: #81A1C1">unsigned</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">q </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Match found at index %d</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> P </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">aba</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> T </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ababa</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #ECEFF4">&#91;</span><span style="color: #B48EAD">4</span><span style="color: #ECEFF4">&#93;&#91;</span><span style="color: #D8DEE9FF">ALPHABET_SIZE</span><span style="color: #ECEFF4">&#93;</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // m+1 states for pattern &quot;aba&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">buildAutomaton</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">faStringMatcher</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> n</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> delta</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I use <code>P = "aba"</code> and <code>T = "ababa"</code> as input, and I expect:</p>



<pre class="wp-block-code"><code>Match found at index 0
Match found at index 2
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I use the KMP-style optimized construction algorithm, reducing preprocessing time from $O(m^3|\Sigma|)$ to $O(m|\Sigma|)$, whenever construction cost matters.</li>



<li>I restrict the alphabet size to only the characters actually appearing in the pattern (plus a &#8220;default/other&#8221; transition) when memory is constrained, rather than allocating for the full 256-character or Unicode alphabet.</li>



<li>I use sparse transition table representations (hash maps instead of dense arrays) when the alphabet is very large but the pattern is short, trading a small constant-factor lookup cost for large memory savings.</li>



<li>I combine automaton-based matching with hardware acceleration (FPGA-based finite-state machines) for extremely high-throughput packet scanning applications.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes allocate the transition table with the wrong dimensions, forgetting that there are $m+1$ states (0 through $m$ inclusive), not $m$.</li>



<li>I use the slow, naive $O(m^3|\Sigma|)$ construction in performance-critical code without realizing a much faster construction exists, leading to unnecessary preprocessing overhead.</li>



<li>I confuse this automaton-based approach with the KMP algorithm itself, forgetting that they are related but distinct (the automaton avoids the fallback while loop, at the cost of extra space).</li>



<li>I forget to account for large alphabets (like full Unicode) which make the dense transition table impractically large, without considering sparse or restricted-alphabet alternatives.</li>



<li>I fail to reset or properly track overlapping matches, missing valid but overlapping pattern occurrences in the text.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Cormen, T. H., Leiserson, C. E., Rivest, R. L., &amp; Stein, C. <em>Introduction to Algorithms</em> (string matching automata chapter): https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/</li>



<li>Hopcroft, J. E., Motwani, R., &amp; Ullman, J. D. <em>Introduction to Automata Theory, Languages, and Computation</em>: https://www.pearson.com/en-us/subject-catalog/p/introduction-to-automata-theory-languages-and-computation/P200000003483</li>



<li>Rabin, M. O., &amp; Scott, D. (1959). &#8220;Finite Automata and Their Decision Problems.&#8221; IBM Journal of Research and Development: https://ieeexplore.ieee.org/document/5392600</li>



<li>Aho, A. V., Sethi, R., &amp; Ullman, J. D. <em>Compilers: Principles, Techniques, and Tools</em> (lexical analysis and automata): https://www.pearson.com/en-us/subject-catalog/p/compilers-principles-techniques-and-tools/P200000003472</li>



<li>Gusfield, D. <em>Algorithms on Strings, Trees, and Sequences</em>: https://www.cambridge.org/core/books/algorithms-on-strings-trees-and-sequences/F0B095049C7E62D2FF6746DE39D65D22</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/string-matching-with-finite-automata-complete-guide-with-examples/">String Matching with Finite Automata: Complete Guide with Examples</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/string-matching-with-finite-automata-complete-guide-with-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10877</post-id>	</item>
		<item>
		<title>Rabin-Karp Algorithm: A Detailed Explanation with Implementation</title>
		<link>https://awjunaid.com/algorithm/rabin-karp-algorithm-a-detailed-explanation-with-implementation/</link>
					<comments>https://awjunaid.com/algorithm/rabin-karp-algorithm-a-detailed-explanation-with-implementation/?noamp=mobile#respond</comments>
		
		<dc:creator><![CDATA[Abdul Wahab Junaid]]></dc:creator>
		<pubDate>Fri, 30 May 2025 15:48:27 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[algorithm]]></category>
		<guid isPermaLink="false">https://awjunaid.com/?p=10874</guid>

					<description><![CDATA[<p>I use the Rabin-Karp algorithm whenever I need to search for a pattern within a text using hashing&#8230;</p>
<p>The post <a href="https://awjunaid.com/algorithm/rabin-karp-algorithm-a-detailed-explanation-with-implementation/">Rabin-Karp Algorithm: A Detailed Explanation with Implementation</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I use the Rabin-Karp algorithm whenever I need to search for a pattern within a text using hashing to quickly rule out positions that cannot possibly match, before falling back on direct character comparison only when a hash suggests a genuine match. I find this algorithm particularly elegant because it reframes string matching as a numeric comparison problem, and I especially value it when I need to search for multiple patterns simultaneously, since the hashing approach extends naturally to that case.</p>



<h2 class="wp-block-heading">History and Background</h2>



<p class="wp-block-paragraph">I trace the Rabin-Karp algorithm to a 1987 paper by Richard M. Karp and Michael O. Rabin, titled &#8220;Efficient Randomized Pattern-Matching Algorithms,&#8221; published in the IBM Journal of Research and Development. I note that this algorithm emerged during a period of growing interest in randomized algorithms across computer science, and I regard it as one of the earliest and most influential applications of hashing to string processing. I see its ideas extend directly into later works, including plagiarism detection systems and the broader field of fingerprinting-based document comparison, cementing its practical relevance well beyond the original paper.</p>



<h2 class="wp-block-heading">Problem Statement</h2>



<p class="wp-block-paragraph">I use Rabin-Karp to solve the standard pattern-matching problem: given a text $T$ of length $n$ and a pattern $P$ of length $m$, I want to find all occurrences of $P$ in $T$. Unlike KMP or the automaton method, which avoid redundant comparisons through clever pointer/state management, I want an approach that instead avoids redundant comparisons by using a cheaply updatable numeric fingerprint (a rolling hash) of each substring, comparing hashes first and only verifying character-by-character when hashes match.</p>



<h2 class="wp-block-heading">Core Concepts</h2>



<p class="wp-block-paragraph">I rely on the concept of a <strong>rolling hash function</strong>, which allows me to compute the hash of the next substring in $O(1)$ time given the hash of the current substring, rather than recomputing the hash from scratch. I typically treat each substring as a number in some base $d$ (often related to the alphabet size), and I reduce this number modulo a prime $q$ to keep the values small and avoid overflow. I also rely on the distinction between a <strong>hash collision</strong> — where two different substrings produce the same hash value — and a <strong>true match</strong>, which is why I always perform a direct character verification whenever hashes match, since Rabin-Karp is a heuristic-filtering algorithm rather than one where hash equality alone certifies a match.</p>



<h2 class="wp-block-heading">How It Works</h2>



<p class="wp-block-paragraph">I follow this process when performing Rabin-Karp matching:</p>



<ol class="wp-block-list">
<li>I choose a base $d$ (often the size of the character set) and a prime modulus $q$ to control hash value size and reduce collision probability.</li>



<li>I compute the hash of the pattern $P$ and the hash of the first substring of $T$ of length $m$.</li>



<li>I compare the pattern&#8217;s hash to the current substring&#8217;s hash. If they match, I perform a direct character-by-character comparison to rule out a false positive (hash collision).</li>



<li>I &#8220;roll&#8221; the hash forward: I remove the contribution of the outgoing leftmost character and add the contribution of the new incoming rightmost character, in $O(1)$ time.</li>



<li>I repeat steps 3–4 for every position in the text until I&#8217;ve checked all $n &#8211; m + 1$ possible starting positions.</li>
</ol>



<h2 class="wp-block-heading">Working Principle</h2>



<p class="wp-block-paragraph">I understand the internal logic of Rabin-Karp as trading exact per-character comparison for approximate but extremely cheap numeric comparison, verified only when necessary. The rolling hash mechanism is the key enabler: since I represent a substring as a polynomial evaluated at base $d$, shifting the window by one character corresponds to a simple linear transformation of the hash value — multiply by $d$, subtract the outgoing character&#8217;s contribution (scaled appropriately), and add the incoming character. This lets me maintain an always-current fingerprint of the current window in constant time per step, which is what allows the algorithm to scan the whole text in linear time on average, deferring the more expensive $O(m)$ character comparison to only the rare cases where hash values coincide.</p>



<h2 class="wp-block-heading">Mathematical Foundation</h2>



<p class="wp-block-paragraph">I represent the pattern $P = p_0 p_1 \cdots p_{m-1}$ as a number in base $d$:</p>



<p class="wp-block-paragraph">$$ h(P) = \left( \sum_{i=0}^{m-1} p_i \cdot d^{m-1-i} \right) \bmod q $$</p>



<p class="wp-block-paragraph">I compute the hash of the text window starting at position $s$, $T[s..s+m-1]$, the same way, and I maintain it incrementally. Given the hash of the window starting at $s$, I compute the hash of the window starting at $s+1$ using:</p>



<p class="wp-block-paragraph">$$ h(T[s+1..s+m]) = \left( d \cdot \big(h(T[s..s+m-1]) &#8211; T[s] \cdot d^{m-1}\big) + T[s+m] \right) \bmod q $$</p>



<p class="wp-block-paragraph">I precompute $d^{m-1} \bmod q$ once, so this update takes $O(1)$ time per shift.</p>



<p class="wp-block-paragraph">I analyze the probability of a hash collision (a &#8220;spurious hit&#8221;) using the properties of modular arithmetic: for a randomly and appropriately chosen prime $q$, the number of false collisions across all $n-m+1$ positions is bounded, in expectation, by:</p>



<p class="wp-block-paragraph">$$ E[\text{false hits}] \le \frac{n}{q} \cdot O(m) $$</p>



<p class="wp-block-paragraph">which I keep small by choosing $q$ sufficiently large (typically larger than $n \cdot m$) or by choosing $q$ randomly from a suitably large range of primes, following the Rabin-Karp fingerprinting analysis, ensuring the expected number of collisions remains a small constant.</p>



<p class="wp-block-paragraph">I state the resulting expected time complexity of the algorithm:</p>



<p class="wp-block-paragraph">$$ E[T(n)] = O(n + m) $$</p>



<p class="wp-block-paragraph">while explicitly noting the worst-case time complexity, arising when many spurious hash collisions occur:</p>



<p class="wp-block-paragraph">$$ T_{\text{worst}}(n) = O(nm) $$</p>



<h2 class="wp-block-heading">Diagrams</h2>



<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">flowchart TD
    A[Input: text T, pattern P, base d, prime q] --> B[Compute hash of P and first window of T]
    B --> C{Hash of window equals hash of P?}
    C -->|Yes| D[Verify with direct character comparison]
    D --> E{Characters actually match?}
    E -->|Yes| F[Record true match]
    E -->|No| G[Spurious hit, discard]
    C -->|No| H[Skip verification]
    F --> I{More text remaining?}
    G --> I
    H --> I
    I -->|Yes| J[Roll hash forward to next window]
    J --> C
    I -->|No| K[Return all matches]
</pre></div>



<h2 class="wp-block-heading">Pseudocode</h2>



<p class="wp-block-paragraph">I write the pseudocode for the Rabin-Karp algorithm:</p>



<pre class="wp-block-code"><code>function RABIN_KARP(T, P, d, q):
    n = length(T)
    m = length(P)
    h = d^(m-1) mod q          // precomputed for rolling hash updates
    pHash = 0
    tHash = 0
    matches = empty list

    // I compute the initial hash values for P and the first window of T
    for i from 0 to m - 1:
        pHash = (d * pHash + P&#91;i]) mod q
        tHash = (d * tHash + T&#91;i]) mod q

    for s from 0 to n - m:
        if pHash == tHash:
            if T&#91;s..s+m-1] == P:          // direct verification
                matches.append(s)

        if s &lt; n - m:
            // I roll the hash forward by one position
            tHash = (d * (tHash - T&#91;s] * h) + T&#91;s + m]) mod q
            if tHash &lt; 0:
                tHash = tHash + q          // I correct for negative modulo

    return matches
</code></pre>



<h2 class="wp-block-heading">Step-by-Step Example</h2>



<p class="wp-block-paragraph">I search for pattern $P = \text{&#8220;26&#8221;}$ in text $T = \text{&#8220;3141592653589793&#8221;}$, using $d = 10$ (decimal digits) and $q = 101$ (a small prime for illustration).</p>



<p class="wp-block-paragraph">I compute $h(P) = (2 \cdot 10 + 6) \bmod 101 = 26$.</p>



<p class="wp-block-paragraph">I compute the hash of the first window &#8220;31&#8221;: $(3 \cdot 10 + 1) \bmod 101 = 31$. Not equal to 26, so I skip verification.</p>



<p class="wp-block-paragraph">I roll forward to &#8220;14&#8221;: using the rolling formula, I compute $(10 \cdot (31 &#8211; 3\cdot10) + 4) \bmod 101 = (10 \cdot 1 + 4) \bmod 101 = 14$. Not equal to 26.</p>



<p class="wp-block-paragraph">I continue rolling through &#8220;41&#8221;, &#8220;15&#8221;, &#8220;59&#8221;, &#8220;92&#8221;, &#8220;26&#8221; — and upon reaching the window &#8220;26&#8221; (starting at index 6 in &#8220;3141592653589793&#8221;), I compute its hash as 26, matching $h(P)$. I then verify directly: &#8220;26&#8221; equals &#8220;26&#8221;, confirming a true match at index 6.</p>



<p class="wp-block-paragraph">I continue scanning the rest of the text similarly, checking each subsequent window, and I find no further occurrences of &#8220;26&#8221; in this particular text.</p>



<h2 class="wp-block-heading">Time Complexity</h2>



<p class="wp-block-paragraph">I establish the expected-case time complexity of Rabin-Karp as $O(n + m)$, since the rolling hash update takes $O(1)$ per position and direct verification is triggered only rarely (in expectation, a small constant number of times) due to the low collision probability with a well-chosen modulus. I note the worst-case time complexity remains $O(nm)$, occurring when many or all hash comparisons happen to collide (either due to adversarial input or a poorly chosen modulus), forcing an $O(m)$ verification at nearly every position. I emphasize that, unlike KMP or the automaton method, Rabin-Karp&#8217;s strong performance guarantee is probabilistic/average-case rather than a guaranteed worst-case linear bound, which I consider its central theoretical trade-off.</p>



<h2 class="wp-block-heading">Space Complexity</h2>



<p class="wp-block-paragraph">I require only $O(1)$ additional space beyond the input text and pattern, since I maintain just a few numeric variables (the current hash values, the precomputed power $d^{m-1} \bmod q$) regardless of $n$ or $m$. This compares favorably to the automaton method&#8217;s $O(m|\Sigma|)$ requirement, and is comparable to KMP&#8217;s $O(m)$ failure-function space, though I note Rabin-Karp needs even less since no auxiliary table is required at all.</p>



<h2 class="wp-block-heading">Correctness Analysis</h2>



<p class="wp-block-paragraph">I justify the correctness of Rabin-Karp in two parts: <strong>soundness</strong>, since I never report a match unless the direct character-by-character verification succeeds, guaranteeing no false positives are ever returned regardless of hash collisions; and <strong>completeness</strong>, since I check every single position from $0$ to $n-m$ without skipping any, guaranteeing that if the hash comparison at a true-match position ever fails to trigger (which cannot happen, since identical substrings always produce identical hashes under a fixed hash function), no match would be missed — but because identical strings always hash identically, every true match&#8217;s hash will match the pattern&#8217;s hash, ensuring verification is always triggered at true-match positions. I therefore conclude the algorithm always finds every true occurrence and never reports a false one, with only its running time (not its correctness) affected by collision frequency.</p>



<h2 class="wp-block-heading">Advantages</h2>



<ul class="wp-block-list">
<li>I gain the ability to extend Rabin-Karp naturally to multi-pattern search, checking a text window&#8217;s hash against a set of pattern hashes stored in a hash table, all in roughly the same asymptotic time as single-pattern search.</li>



<li>The algorithm&#8217;s core idea (rolling hashes) is broadly reusable in other contexts, such as plagiarism detection, duplicate substring detection, and even the foundation of some compression schemes.</li>



<li>I find the implementation conceptually simple and easy to reason about compared to KMP&#8217;s failure function or automaton construction.</li>



<li>Average-case performance is excellent in practice, especially with well-chosen hash parameters.</li>
</ul>



<h2 class="wp-block-heading">Disadvantages</h2>



<ul class="wp-block-list">
<li>I accept a worst-case time complexity of $O(nm)$, which can occur with unlucky hash collisions, unlike KMP&#8217;s guaranteed $O(n+m)$ worst case.</li>



<li>I must carefully choose the modulus $q$ and base $d$ to keep collision probability low; poor choices can degrade performance significantly.</li>



<li>Handling integer overflow in the rolling hash computation requires careful modular arithmetic, which adds implementation complexity.</li>



<li>The reliance on hashing introduces a probabilistic element that some applications (especially those needing hard real-time worst-case guarantees) may find undesirable compared to deterministic algorithms like KMP.</li>
</ul>



<h2 class="wp-block-heading">Applications</h2>



<p class="wp-block-paragraph">I apply Rabin-Karp in:</p>



<ul class="wp-block-list">
<li><strong>Plagiarism detection</strong>: comparing large numbers of document fingerprints for overlapping content.</li>



<li><strong>Multi-pattern search</strong>: searching for multiple patterns (like a dictionary of banned words) simultaneously using a hash table of pattern hashes.</li>



<li><strong>Bioinformatics</strong>: searching for repeated or matching DNA subsequences using rolling hash techniques.</li>



<li><strong>Version control and diff tools</strong>: identifying common substrings between file versions.</li>



<li><strong>Distributed systems</strong>: content-based chunking (rolling hash boundaries) for deduplication in storage systems.</li>
</ul>



<h2 class="wp-block-heading">Implementation in C</h2>



<p class="wp-block-paragraph">I implement the Rabin-Karp algorithm in C, with comments:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include &lt;stdio.h>
#include &lt;string.h>

#define D 256   // number of characters in the input alphabet
#define Q 101   // a prime number used for the modulus

// I implement Rabin-Karp search for pattern P within text T
void rabinKarpSearch(char* T, char* P) {
    int n = strlen(T);
    int m = strlen(P);
    int h = 1;
    int pHash = 0, tHash = 0;

    // I precompute d^(m-1) mod q, used to remove the leading digit when rolling
    for (int i = 0; i &lt; m - 1; i++) {
        h = (h * D) % Q;
    }

    // I compute the initial hash values for the pattern and the first window
    for (int i = 0; i &lt; m; i++) {
        pHash = (D * pHash + P&#91;i&#93;) % Q;
        tHash = (D * tHash + T&#91;i&#93;) % Q;
    }

    for (int s = 0; s &lt;= n - m; s++) {
        if (pHash == tHash) {
            // I verify directly to rule out a spurious hash collision
            if (strncmp(T + s, P, m) == 0) {
                printf("Match found at index %d\n", s);
            }
        }

        if (s &lt; n - m) {
            // I roll the hash forward by removing T&#91;s&#93; and adding T&#91;s+m&#93;
            tHash = (D * (tHash - T&#91;s&#93; * h) + T&#91;s + m&#93;) % Q;
            if (tHash &lt; 0) {
                tHash += Q; // I correct for a negative result from the modulo operation
            }
        }
    }
}

int main() {
    char T[] = "3141592653589793";
    char P[] = "26";

    rabinKarpSearch(T, P);

    return 0;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">stdio.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">include</span><span style="color: #8FBCBB"> </span><span style="color: #ECEFF4">&lt;</span><span style="color: #8FBCBB">string.h</span><span style="color: #ECEFF4">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">D</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">256</span><span style="color: #616E88">   // number of characters in the input alphabet</span></span>
<span class="line"><span style="color: #5E81AC; font-weight: bold">#</span><span style="color: #81A1C1">define</span><span style="color: #5E81AC"> </span><span style="color: #88C0D0">Q</span><span style="color: #5E81AC"> </span><span style="color: #B48EAD">101</span><span style="color: #616E88">   // a prime number used for the modulus</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// I implement Rabin-Karp search for pattern P within text T</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">rabinKarpSearch</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">char*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">P</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">P</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> h </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> pHash </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> tHash </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I precompute d^(m-1) mod q, used to remove the leading digit when rolling</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        h </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">h </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> D</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> Q</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// I compute the initial hash values for the pattern and the first window</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> i</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        pHash </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">D </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> pHash </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> Q</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        tHash </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">D </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> tHash </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">i</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> Q</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> s </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> s </span><span style="color: #81A1C1">&lt;=</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> m</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> s</span><span style="color: #81A1C1">++</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">pHash </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> tHash</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// I verify directly to rule out a spurious hash collision</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">strncmp</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> s</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #88C0D0">printf</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Match found at index %d</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> s</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">s </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> n </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// I roll the hash forward by removing T&#91;s&#93; and adding T&#91;s+m&#93;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            tHash </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">D </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">tHash </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">s</span><span style="color: #ECEFF4">&#93;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> h</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> T</span><span style="color: #ECEFF4">&#91;</span><span style="color: #D8DEE9FF">s </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> m</span><span style="color: #ECEFF4">&#93;)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">%</span><span style="color: #D8DEE9FF"> Q</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">tHash </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                tHash </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> Q</span><span style="color: #81A1C1">;</span><span style="color: #616E88"> // I correct for a negative result from the modulo operation</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">main</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">char</span><span style="color: #D8DEE9FF"> T</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">3141592653589793</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">char</span><span style="color: #D8DEE9FF"> P</span><span style="color: #81A1C1">[]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">26</span><span style="color: #ECEFF4">&quot;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">rabinKarpSearch</span><span style="color: #ECEFF4">(</span><span style="color: #D8DEE9FF">T</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> P</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h2 class="wp-block-heading">Sample Input and Output</h2>



<p class="wp-block-paragraph">I use <code>T = "3141592653589793"</code> and <code>P = "26"</code> as input, and I expect:</p>



<pre class="wp-block-code"><code>Match found at index 6
</code></pre>



<h2 class="wp-block-heading">Optimization Techniques</h2>



<ul class="wp-block-list">
<li>I choose a large prime modulus $q$ (or randomly select from a set of large primes) to minimize the expected number of hash collisions, keeping average-case performance close to linear.</li>



<li>I use double hashing (maintaining two independent hash values with different moduli) to further reduce the probability of spurious collisions in security-sensitive or high-throughput applications.</li>



<li>I extend the algorithm to multi-pattern search by storing all pattern hashes in a hash set, allowing me to check a single text window&#8217;s hash against many patterns in expected $O(1)$ time per window.</li>



<li>I use fixed-size integer types with careful overflow handling, or 64-bit arithmetic, to safely support larger moduli and reduce collision rates without overflow issues.</li>



<li>I apply the rolling hash technique independently in other algorithms, such as suffix array construction and longest common substring detection, wherever repeated substring fingerprinting is useful.</li>
</ul>



<h2 class="wp-block-heading">Common Mistakes</h2>



<ul class="wp-block-list">
<li>I sometimes forget to verify a hash match with a direct character comparison, mistakenly treating hash equality as proof of a true match rather than just a strong candidate.</li>



<li>I mishandle negative results from the modulo operation when rolling the hash backward-subtraction step, producing incorrect hash values in languages like C where the modulo of a negative number can be negative.</li>



<li>I choose a modulus $q$ that is too small relative to the input size, causing excessive spurious collisions and degrading performance toward the worst case.</li>



<li>I forget to precompute $d^{m-1} \bmod q$ once outside the main loop, instead recomputing it unnecessarily and losing the algorithm&#8217;s efficiency advantage.</li>



<li>I overlook integer overflow when computing hash values directly (without modular reduction at each multiplication step), producing incorrect hashes for longer patterns.</li>
</ul>



<h2 class="wp-block-heading">Further Reading</h2>



<ul class="wp-block-list">
<li>Karp, R. M., &amp; Rabin, M. O. (1987). &#8220;Efficient Randomized Pattern-Matching Algorithms.&#8221; IBM Journal of Research and Development: https://ieeexplore.ieee.org/document/5390394</li>



<li>Cormen, T. H., Leiserson, C. E., Rivest, R. L., &amp; Stein, C. <em>Introduction to Algorithms</em> (Rabin-Karp chapter): https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/</li>



<li>Gusfield, D. <em>Algorithms on Strings, Trees, and Sequences</em>: https://www.cambridge.org/core/books/algorithms-on-strings-trees-and-sequences/F0B095049C7E62D2FF6746DE39D65D22</li>



<li>MIT OpenCourseWare, 6.006 Introduction to Algorithms (string matching lecture): https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/</li>



<li>GeeksforGeeks, &#8220;Rabin-Karp Algorithm for Pattern Searching&#8221;: https://www.geeksforgeeks.org/dsa/rabin-karp-algorithm-for-pattern-searching/</li>
</ul>
<p>The post <a href="https://awjunaid.com/algorithm/rabin-karp-algorithm-a-detailed-explanation-with-implementation/">Rabin-Karp Algorithm: A Detailed Explanation with Implementation</a> appeared first on <a href="https://awjunaid.com">Abdul Wahab Junaid</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://awjunaid.com/algorithm/rabin-karp-algorithm-a-detailed-explanation-with-implementation/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">10874</post-id>	</item>
	</channel>
</rss>
