From 2e7af1ff74a5dff575dadf822307d5d1e9f871be Mon Sep 17 00:00:00 2001 From: Sama Walke Date: Wed, 19 Nov 2025 12:24:12 +0300 Subject: [PATCH 1/2] Catalan Numbers --- algorithms/catalan.typ | 89 ++++++++++++++++++++++++++++++++++++++++++ main.typ | 2 + 2 files changed, 91 insertions(+) create mode 100644 algorithms/catalan.typ diff --git a/algorithms/catalan.typ b/algorithms/catalan.typ new file mode 100644 index 0000000..1bbb9b5 --- /dev/null +++ b/algorithms/catalan.typ @@ -0,0 +1,89 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Catalan Numbers +#set math.equation(numbering: none) + +Compute the $n$-th Catalan number. +Formal definition: +$ +C_0 &= 1\ +C_{n+1} &= sum_(i=0)^n C_i C_{n-i} quad "for " n >= 0 +$ + +Examples: +- $"Cat"(0) -> 1$ +- $"Cat"(3) -> 5$ +- $"Cat"(6) -> 132$ + +*As mapcode:* + +_primitives_: `sum`($+$), `product`($*$) + +$ I = n:NN quad quad quad X_n &= [0..n] -> NN_bot quad quad quad A = NN\ +rho(n) & = {i -> bot | i in {0 dots n}}\ +F(n)(x) & = cases( + 1 & "if " k = 0, + sum_(i=0)^(k-1) x[i] dot x[k-1-i] & "if " k > 0 and forall i: x[i] != bot, + bot & "otherwise" + )\ + pi(n)(x) & = x[n] +$ + +#let inst = 6; +#figure( + caption: [Catalan number 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) => ((k,)) => { + if k == 0 {1} + else { + let sum = 0 + let possible = true + for i in range(0, k) { + let left = x.at(i) + let right = x.at(k - 1 - i) + if left != none and right != none { + sum += left * right + } else { + possible = false + break + } + } + if possible { sum } else { none } + } + } + let F = map_tensor(F_i, dim: 1) + + let pi = (inst) => (x) => x.at(inst) + + 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) { + rect(fill: yellow.transparentize(70%), inset: 2pt)[$#val$] + } else { + rect(stroke: none, inset: 2pt)[$#val$] + } + }) + $vec(delim: "[", ..cells)$ + } + + mapcode-viz( + rho, F, pi(inst), + X_h: X_h, + pi_name: [$mpi (inst)$], + group-size: calc.min(7, inst + 1), + cell-size: 10mm, scale-fig: 85% + )(inst) +} +$ +) \ No newline at end of file diff --git a/main.typ b/main.typ index 9952d9b..c5cd8cb 100644 --- a/main.typ +++ b/main.typ @@ -52,3 +52,5 @@ All primitives are _strict_ meaning they do not allow for undefined values (i.e. #include "algorithms/LongestCommonSubsequence.typ" #pagebreak() #include "algorithms/leetcode/P2_add-two-numbers.typ" +#pagebreak() +#include "algorithms/catalan.typ" \ No newline at end of file From d469acc7dfc860e61726be27a77a23e7b16d32a4 Mon Sep 17 00:00:00 2001 From: Sama Walke Date: Wed, 19 Nov 2025 12:46:04 +0300 Subject: [PATCH 2/2] LIS and TOH --- algorithms/lis.typ | 93 ++++++++++++++++++++++++++++++++++++++++++++++ algorithms/toh.typ | 76 +++++++++++++++++++++++++++++++++++++ main.typ | 6 ++- 3 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 algorithms/lis.typ create mode 100644 algorithms/toh.typ diff --git a/algorithms/lis.typ b/algorithms/lis.typ new file mode 100644 index 0000000..0a4e1be --- /dev/null +++ b/algorithms/lis.typ @@ -0,0 +1,93 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Longest Increasing Subsequence (LIS) +#set math.equation(numbering: none) + +Compute the length of the LIS for a sequence $A$. +Formal definition: +$ +L(i) = 1 + max(\{L(j) | j < i, A[j] < A[i]\} union \{0\}) +$ + +Example: +- $A = [10, 9, 2, 5, 3, 7, 101, 18]$ +- LIS Length: 4 (e.g., $[2, 3, 7, 18]$) + +*As mapcode:* + +_primitives_: `sum`($+$), `max` + +$ I = A:NN^* quad quad quad X = NN -> NN_bot quad quad quad A = NN\ +rho(A) & = {i -> bot | i in {0 dots |A|-1}}\ +F(A)(x) & = cases( + 1 & "if no valid " j < i, + max{x[j] + 1 | j < i and A[j] < A[i]} & "if deps satisfied", + bot & "otherwise" + )\ + pi(A)(x) & = max(x) +$ + +#let inst = (10, 9, 2, 5, 3, 7, 101, 18); +#figure( + caption: [LIS computation using mapcode for $A = #inst$], +$ +#{ + let rho = (inst) => { + let x = () + for i in range(0, inst.len()) { + x.push(none) + } + x + } + + // F depends on the instance A + let F_i = (A) => (x) => ((i,)) => { + let max_lis = 1 + let possible = true + + for j in range(0, i) { + if A.at(j) < A.at(i) { + if x.at(j) == none { + possible = false + break + } + max_lis = calc.max(max_lis, x.at(j) + 1) + } + } + + if possible { max_lis } else { none } + } + // We bind the instance A to F + let F = (A) => map_tensor(F_i(A), dim: 1) + + let pi = (A) => (x) => { + let m = 0 + for val in x { + if val != none { m = calc.max(m, val) } + } + m + } + + 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) { + 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 (A)$], + group-size: calc.min(8, inst.len()), + cell-size: 10mm, scale-fig: 85% + )(inst) +} +$ +) \ No newline at end of file diff --git a/algorithms/toh.typ b/algorithms/toh.typ new file mode 100644 index 0000000..734b115 --- /dev/null +++ b/algorithms/toh.typ @@ -0,0 +1,76 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Tower of Hanoi +#set math.equation(numbering: none) + +Compute the minimum moves to solve the Tower of Hanoi puzzle with $n$ disks. +Formal definition: +$ +T_0 &= 0\ +T_n &= 2 T_{n-1} + 1 quad "for " n >= 1 +$ + +Example: +- $"Hanoi"(0) -> 0$ +- $"Hanoi"(1) -> 1$ +- $"Hanoi"(3) -> 7$ + +*As mapcode:* + +_primitives_: `sum`($+$), `product`($*$) + +$ I = n:NN quad quad quad X_n &= [0..n] -> NN_bot quad quad quad A = NN\ +rho(n) & = {k -> bot | k in {0 dots n}}\ +F(n)(x) & = cases( + 0 & "if " k = 0, + 2 dot x[k-1] + 1 & "if " k > 0 and x[k-1] != bot, + bot & "otherwise" + )\ + pi(n)(x) & = x[n] +$ + +#let inst = 4; +#figure( + caption: [Tower of Hanoi 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) => ((k,)) => { + if k == 0 { 0 } + else if x.at(k - 1) != none { 2 * x.at(k - 1) + 1 } + else { none } + } + let F = map_tensor(F_i, dim: 1) + + let pi = (inst) => (x) => x.at(inst) + + 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) { + rect(fill: yellow.transparentize(70%), inset: 2pt)[$#val$] + } else { + rect(stroke: none, inset: 2pt)[$#val$] + } + }) + $vec(delim: "[", ..cells)$ + } + + mapcode-viz( + rho, F, pi(inst), + X_h: X_h, + pi_name: [$mpi (inst)$], + group-size: calc.min(6, inst + 1), + cell-size: 10mm, scale-fig: 90% + )(inst) +} +$ +) \ No newline at end of file diff --git a/main.typ b/main.typ index c5cd8cb..58658fa 100644 --- a/main.typ +++ b/main.typ @@ -53,4 +53,8 @@ All primitives are _strict_ meaning they do not allow for undefined values (i.e. #pagebreak() #include "algorithms/leetcode/P2_add-two-numbers.typ" #pagebreak() -#include "algorithms/catalan.typ" \ No newline at end of file +#include "algorithms/catalan.typ" +#pagebreak() +#include "algorithms/lis.typ" +#pagebreak() +#include "algorithms/toh.typ" \ No newline at end of file