From 553a801cfaa5bada5b86e70e9137fc976bca000b Mon Sep 17 00:00:00 2001 From: AndyJocy Date: Sun, 16 Nov 2025 17:01:35 +0000 Subject: [PATCH 1/2] Digit Reversal --- algorithms/DigitReversal.typ | 150 +++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 algorithms/DigitReversal.typ diff --git a/algorithms/DigitReversal.typ b/algorithms/DigitReversal.typ new file mode 100644 index 0000000..d1564e3 --- /dev/null +++ b/algorithms/DigitReversal.typ @@ -0,0 +1,150 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Digit Reversal + +Compute the digit reversal of a non-negative integer $n$. +i.e $n in NN_0, n >= 0$ + +Formal definition: +$ +f(n) = h(n, 0) +$ +$ +h(n, a) = cases( + a & "if " n = 0, + h(n " div " 10, a * 10 + n " mod " 10) & "otherwise" +) +$ + +Examples: +- $"rev"(123) -> 321$ +- $"rev"(90) -> 9$ + +*As mapcode:* + +_primitives_: `div`, `mod`, `+`, `*` + +// Put all definitions in one math block. +// Use '&=' to align and '\' for newlines. +$ +I & = (n: NN_0, d: NN) \ +X_d & = [0..d] -> (NN_0 times NN_0)_bot \ +A & = NN_0 \ +rho(n, d) & = { i -> bot | i in [0..d] } +$ + +// Define F(x_i) in its own math block +$ +F(x_i) = cases( + (n, 0) & "if " i = 0, + + // Use line breaks (\\) to wrap long conditions + (n_p " div " 10, a_p * 10 + n_p " mod " 10) & "if " i > 0 and n_p > 0 \\ + & and x_(i-1) != bot, + + (0, a_p) & "if " i > 0 and n_p = 0 \\ + & and x_(i-1) != bot, + + bot & "otherwise" +) +$ +(where $(n_p, a_p) = x_(i-1)$) +$ +pi(x) = x_d.2 quad // Accumulator of the last state +$ + +// --- Implementation --- + +// The number to reverse +#let inst_n = 123; +// The number of steps (digits + 1 for the '0' state) +#let num_steps = 4; +// The instance (n, d), where d is the max index +#let inst = (inst_n, num_steps - 1); + +#figure( + caption: [Digit Reversal computation using mapcode for $n = #inst_n$], +$ +#{ + // inst = (n, d) + let (n_val, d_val) = inst; + + let rho = (inst) => { + let (n, d) = inst; + let x = () + for i in range(0, d + 1) { + x.push(none) // `none` is bot + } + x + } + + // F_i defines the logic for one element x[i] + let F_i = (x) => ((i,)) => { + if i == 0 { + // Base case: (input_n, 0_accumulator) + (n_val, 0) + } else { + let prev_state = x.at(i - 1); + if prev_state == none { + none // Dependency not met + } else { + let (prev_n, prev_acc) = prev_state; + if prev_n == 0 { + // Fixed point reached, propagate this state + (0, prev_acc) + } else { + // Compute the next state + let next_n = calc.floor(prev_n / 10); + let next_acc = prev_acc * 10 + calc.rem(prev_n, 10); + (next_n, next_acc) + } + } + } + } + + // Create the tensor-wide operator + let F = map_tensor(F_i, dim: 1) + + // pi extracts the final answer + let pi = (i) => (x) => { + let (n, acc) = x.at(i); + acc // Return the accumulator part of the last state + } + + // X_h visualizes the state (an array of tuples) + // --- THIS BLOCK IS NOW FIXED --- + let X_h = (x, diff_mask: none) => { + let cells = x.enumerate().map(((i, x_i)) => { + let val = if x_i != none { + let (n, acc) = x_i; + // Format the (n, acc) tuple + [$n: #n, acc: #acc$] + } else { + [$bot$] + } + + if diff_mask != none and diff_mask.at(i) { + // changed element: highlight (style from factorial.typ) + rect(fill: yellow.transparentize(70%), inset: 2pt)[$#val$] + } else { + // (style from factorial.typ) + rect(stroke: none, inset: 2pt)[$#val$] + } + }) + + $vec(delim: "[", ..cells)$ + } + // --- END OF FIX --- + + mapcode-viz( + rho, F, pi(d_val), + X_h: X_h, + pi_name: [$mpi(#repr(inst_n))$], + group-size: calc.min(7, d_val + 1), + cell-size: 30mm, // Wider to fit the tuple + scale-fig: 85% + )(inst) +} +$ +) \ No newline at end of file From 63d4cf516d11d8da8214aa9be5ca20bed98f9fd2 Mon Sep 17 00:00:00 2001 From: AndyJocy Date: Sun, 16 Nov 2025 17:02:22 +0000 Subject: [PATCH 2/2] Longest Increasing Subsequence --- algorithms/LIS.typ | 110 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 algorithms/LIS.typ diff --git a/algorithms/LIS.typ b/algorithms/LIS.typ new file mode 100644 index 0000000..fab23f6 --- /dev/null +++ b/algorithms/LIS.typ @@ -0,0 +1,110 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Longest Increasing Subsequence (LIS) +#set math.equation(numbering: none) + +Compute the length of the longest increasing subsequence (LIS) of a vector of integers. + +Formal definition: +$ +I = "nums" in "vec"[ZZ] \ +X_n = [0..n-1] -> NN_bot " where " n = |"nums"| \ +A = NN +$ + +$ +rho("nums") = { i -> bot | i in [0..n-1] } \ +\ +F(x)_i = 1 + max( {0} union { x_j | j in [0..i-1] " and " "nums"_i > "nums"_j } ) \ +\ +pi(x) = max( {0} union { x_i | i in [0..n-1] } ) +$ +(The $F$ function is strict: if any $x_j$ it depends on is $bot$, $F(x)_i$ remains $bot$.) + +*As mapcode:* + +#let inst = (10, 9, 2, 5, 3, 7, 101, 18); +#figure( + caption: [LIS computation using mapcode for $n = #inst$], +$ +#{ + let rho = (inst) => { + // x_0 = [bot, bot, ..., bot] + let x = () + for i in range(0, inst.len()) { + x.push(none) + } + x + } + + // F_i_gen creates the function for a single element F(x)_i + // It needs the `inst` (nums) to compare values. + let F_i_gen = (inst) => (x) => ((i,)) => { + let max_len = 0 + let all_deps_met = true + + // Loop j from 0 to i-1 + for j in range(0, i) { + if inst.at(i) > inst.at(j) { + // This is a potential predecessor + if x.at(j) == none { + // Dependency not met, this cell remains bot + all_deps_met = false + break + } else if x.at(j) > max_len { + max_len = x.at(j) + } + } + } + + if all_deps_met { + 1 + max_len + } else { + none + } + } + + // F_gen creates the parallel map F(x) + let F = (inst) => map_tensor(F_i_gen(inst), dim: 1) + + // pi finds the maximum value in the final dp array + let pi = (inst) => (x) => { + if x.len() == 0 { + 0 + } else { + let max_val = 0 + for i in range(0, x.len()) { + if x.at(i) != none and x.at(i) > max_val { + max_val = x.at(i) + } + } + max_val + } + } + + // X_h is the helper to visualize the state vector x + let X_h = (x, diff_mask: none) => { + let cells = x.enumerate().map(((i, x_i)) => { + let val = if x_i != none {[$#x_i$]} else {[$bot$]} + if diff_mask != none and diff_mask.at(i) { + // changed element: highlight + rect(fill: yellow.transparentize(70%), inset: 2pt)[$#val$] + } else { + rect(stroke: none, inset: 2pt)[$#val$] + } + }) + $vec(delim: "[", ..cells)$ + } + +mapcode-viz( + rho, F(inst), pi(inst), + X_h: X_h, + pi_name: [$mpi$], + group-size: calc.min(8, inst.len()), + cell-size: 8mm, + scale-fig: 75% + )(inst) +} +$ +) \ No newline at end of file