From 04f9412a0b4a2596da1ac6f2ebb8a10ec51dffb4 Mon Sep 17 00:00:00 2001 From: Harshit Date: Sun, 16 Nov 2025 17:49:41 +0000 Subject: [PATCH] added parity-check, digit-reversal --- algorithms/DigitReversal.typ | 117 +++++++++++++++++++++++++++++++++++ algorithms/parity.typ | 91 +++++++++++++++++++++++++++ main.typ | 4 ++ 3 files changed, 212 insertions(+) create mode 100644 algorithms/DigitReversal.typ create mode 100644 algorithms/parity.typ diff --git a/algorithms/DigitReversal.typ b/algorithms/DigitReversal.typ new file mode 100644 index 0000000..862848f --- /dev/null +++ b/algorithms/DigitReversal.typ @@ -0,0 +1,117 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Digit Reversal + +Reverse the digits of a non-negative integer $n$ using tail-recursive computation. This algorithm demonstrates efficient fixed-point computation with a 2-element state pair $(n_p, a_p)$ representing remaining digits and accumulator. + +Formal definition: +$ +"reverse"(n) = cases( + 0 & "if " n = 0, + 10 dot "reverse"(n div 10) + (n mod 10) & "otherwise" +) +$ + +Examples: +- $"reverse"(123) = 321$ +- $"reverse"(1000) = 1$ +- $"reverse"(12345) = 54321$ + +*As mapcode (2-state pair):* + +$ I = n : NN quad X = NN times NN quad A = NN $ + +$ rho(n) = (n, 0) $ + +$ F((n_p, a_p)) = cases( + (n_p div 10, a_p dot 10 + n_p mod 10) & "if " n_p > 0, + (0, a_p) & "if " n_p = 0 +) $ + +$ pi((n_p, a_p)) = a_p $ + +#let inst = 123; +#figure( + caption: [Digit reversal using mapcode for reverse(#inst) = 321], +$ +#{ + let rho = (inst) => { + (inst, 0) + } + + let F = (x) => { + let (n_p, a_p) = x + if n_p == 0 { + (0, a_p) + } else { + let n_i = int(n_p / 10) + let a_i = a_p * 10 + int(n_p) - n_i * 10 + (n_i, a_i) + } + } + + let pi = (x) => { + x.at(1) + } + + let X_h = (x, diff_mask: none) => { + let (n_p, a_p) = x + let n_box = if diff_mask != none and diff_mask.at(0) { + rect(fill: yellow.transparentize(70%), inset: 1pt)[$ #n_p $] + } else { + rect(stroke: none, inset: 1pt)[$ #n_p $] + } + let a_box = if diff_mask != none and diff_mask.at(1) { + rect(fill: yellow.transparentize(70%), inset: 1pt)[$ #a_p $] + } else { + rect(stroke: none, inset: 1pt)[$ #a_p $] + } + $lr((#n_box, #a_box))$ + } + + // Build history + let x0 = rho(inst) + let xs = (x0,) + let xn = x0 + let prev = none + let iters = 0 + while prev != xn and iters < 10 { + prev = xn + xn = F(xn) + if xn != xs.at(-1) { + xs.push(xn) + } + iters += 1 + } + let ans = pi(xn) + + // Compute diffs + let get_diff = (a, b) => { + let (n_a, a_a) = a + let (n_b, a_b) = b + (n_a != n_b, a_a != a_b) + } + + let diffs = xs.windows(2).map(((prev, next)) => { + get_diff(prev, next) + }) + diffs.insert(0, (false, false)) + + // Format trace + let trace_items = xs.enumerate().map(((idx, x_i)) => { + let label = if idx == 0 { $rho$ } else { $F$ } + let state = X_h(x_i, diff_mask: diffs.at(idx)) + $(#label): #state$ + }) + + box(inset: 5pt)[ + Trace: + #h(1em) + #trace_items.join([ $arrow.r$ ]) + #h(1em) + $pi = #ans$ + ] +} +$ +) diff --git a/algorithms/parity.typ b/algorithms/parity.typ new file mode 100644 index 0000000..3362d60 --- /dev/null +++ b/algorithms/parity.typ @@ -0,0 +1,91 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Parity + +Determine whether a non-negative integer $n$ is even or odd using mutually recursive functions. + +Formal definition: +$ +"is_even"(0) &= "true",\ +"is_odd"(0) &= "false",\ +"is_even"(n) &= "is_odd"(n-1) quad "for " n > 0,\ +"is_odd"(n) &= "is_even"(n-1) quad "for " n > 0 +$ + +Examples: +- $"parity"(0) -> ("T", "F")$ +- $"parity"(1) -> ("F", "T")$ +- $"parity"(3) -> ("F", "T")$ + +*As mapcode:* + +$ I = n : NN quad X_n = [0..n] -> (BB times BB)_bot quad A = BB times BB $ + +$ rho(n) = {i |-> bot | i in {0 dots n}} $ + +$ F(x_n) = cases( + ("T", "F") & "if " n = 0, + (x_(n-1)[1], x_(n-1)[0]) & "if " n > 0 "and" x_(n-1) != bot, + bot & "otherwise" +) $ + +$ pi(x) = x_(|x| - 1) $ + +#let inst = 3; +#figure( + caption: [Parity computation using mapcode for $n = #inst$], +$ +#{ + let rho = (inst) => { + let x = () + for i in range(0, inst + 1) { + x.push(none) + } + x + } + + let F_i = (x) => ((i,)) => { + if i == 0 { + (true, false) + } else if x.at(i - 1) != none { + let (even_prev, odd_prev) = x.at(i - 1) + (odd_prev, even_prev) + } else { + none + } + } + let F = map_tensor(F_i, dim: 1) + + let pi = (i) => (x) => x.at(i) + + let X_h = (x, diff_mask: none) => { + let cells = x.enumerate().map(((i, x_i)) => { + let val = if x_i != none { + let (e, o) = x_i + let e_str = if e { "T" } else { "F" } + let o_str = if o { "T" } else { "F" } + $#e_str#o_str$ + } else { + $bot$ + } + if diff_mask != none and diff_mask.at(i) { + rect(fill: yellow.transparentize(70%), inset: 1pt)[$#val$] + } else { + rect(stroke: none, inset: 1pt)[$#val$] + } + }) + $vec(delim: "[", ..cells)$ + } + + mapcode-viz( + rho, F, pi(inst), + X_h: X_h, + pi_name: [$pi(#inst)$], + group-size: 4, + cell-size: 8mm, + scale-fig: 75% + )(inst) +} +$ +) diff --git a/main.typ b/main.typ index 9952d9b..1882467 100644 --- a/main.typ +++ b/main.typ @@ -47,6 +47,10 @@ All primitives are _strict_ meaning they do not allow for undefined values (i.e. #pagebreak() #include "algorithms/fibonacci.typ" #pagebreak() +#include "algorithms/parity.typ" +#pagebreak() +#include "algorithms/DigitReversal.typ" +#pagebreak() #include "algorithms/BinomialCoefficients.typ" #pagebreak() #include "algorithms/LongestCommonSubsequence.typ"