From 6308a0af70d21a64970cdcd87d1211494f042a30 Mon Sep 17 00:00:00 2001 From: sriyansh Date: Mon, 17 Nov 2025 00:13:06 +0530 Subject: [PATCH] yes --- algorithms/BellmanFord.typ | 118 ++++++++++++++++++++++++ algorithms/TreeHeight.typ | 180 +++++++++++++++++++++++++++++++++++++ main.typ | 5 ++ 3 files changed, 303 insertions(+) create mode 100644 algorithms/BellmanFord.typ create mode 100644 algorithms/TreeHeight.typ diff --git a/algorithms/BellmanFord.typ b/algorithms/BellmanFord.typ new file mode 100644 index 0000000..3af25ca --- /dev/null +++ b/algorithms/BellmanFord.typ @@ -0,0 +1,118 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Bellman-Ford Shortest Path Algorithm + +Compute shortest paths from a source vertex to all other vertices in a weighted graph, handling negative edge weights (assuming no negative cycle). + +Formal definition: +$ +"dist"^((k))(v) = cases( + 0 & "if " v = s and k = 0, + infinity & "if " v != s and k = 0, + min("dist"^((k-1))(v), min_(u,v,w in E)("dist"^((k-1))(u) + w)) & "otherwise" +) +$ + +*As mapcode:* + +_primitives_: `min`(min), `add`($+$) + +$ +I = n:NN times "edges": ("Vertex" times "Vertex" times ZZ)^* times s:"Vertex" quad quad\ +X & = ([0..n-1] -> (NN union {infinity})_bot) times "edges" quad quad\ +A = [0..n-1] -> (NN union {infinity})_bot\ + +rho(n, "edges", s) & = ("dist", "edges") "where" "dist" = cases( + 0 & "if" v = s, + bot & "if" v != s +) \ + +F("dist", "edges") & = ("dist"', "edges") "where for each edge" (u,v,w) in "edges":\ +& "dist"'[v] = cases( + "dist"[v] & "if" "dist"[u] = bot, + "dist"[u] + w & "if" "dist"[v] = bot, + min("dist"[v], "dist"[u] + w) & "if" "dist"[u] != bot and "dist"[v] != bot +)\ + +pi("dist", "edges") & = "dist" +$ + +#let inst_n = 5; +#let inst_edges = ( + (0, 1, 6), (0, 3, 7), (1, 2, 5), + (1, 3, 8), (1, 4, -4), (2, 1, -2), + (3, 2, -3), (3, 4, 9), (4, 2, 7) +); +#let inst_src = 0; + +#figure( + caption: [Bellman-Ford shortest path computation from vertex #inst_src], +$#{ + // Implement rho function + let rho = ((n, edges, src)) => { + // Initialize distance array with all BOTTOM (none) except source + let dist = () + for i in range(0, n) { + if i == src { + dist.push(0) + } else { + dist.push(none) + } + } + (dist, edges) // State is (distance array, edges) + } + + // Implement F_i function - edge relaxation + let F_i = (edges) => (dist) => ((v,)) => { + let current = dist.at(v) + + // Try to relax edges ending at vertex v + for edge in edges { + let (u, vtx, w) = edge + if vtx == v and dist.at(u) != none { + let new_cost = dist.at(u) + w + if current == none or new_cost < current { + current = new_cost + } + } + } + current + } + + let F = (edges) => (state) => { + let (dist, e) = state + let new_dist = map_tensor(F_i(edges), dim: 1)(dist) + (new_dist, e) + } + + let pi = (state) => { + // Return final distances + let (dist, edges) = state + dist + } + + // Visualization helper + let x_h(state, diff_mask:none) = { + let (dist, edges) = state + let cells = dist.enumerate().map(((i, d)) => { + let val = if d != none {[$#d$]} else {[$bot$]} + if diff_mask != none and diff_mask.at(0).at(i) { + // changed element: highlight + rect(fill: yellow.transparentize(70%), inset: 2pt)[$v_#i: #val$] + } else { + rect(stroke: none, inset: 2pt)[$v_#i: #val$] + } + }) + $vec(delim: "[", ..cells)$ + } + + mapcode-viz( + rho, F(inst_edges), pi, + X_h: x_h, + pi_name: [$mpi$], + dim: 2, // Explicitly set dimension: tuple of (array, edges) + group-size: calc.min(4, inst_n + 1), + cell-size: 30mm, scale-fig: 75% + )((inst_n, inst_edges, inst_src)) +}$) \ No newline at end of file diff --git a/algorithms/TreeHeight.typ b/algorithms/TreeHeight.typ new file mode 100644 index 0000000..109402a --- /dev/null +++ b/algorithms/TreeHeight.typ @@ -0,0 +1,180 @@ +#import "../lib/style.typ": * +#import "../lib/mapcode.typ": * + +== Tree Height + +Compute the height of a rooted tree. The height of a tree is the maximum distance from the root to any leaf node. + +Formal definition: +$ +"height"(v) = cases( + 0 & "if " v "is a leaf", + 1 + max_(c in "children"(v)) "height"(c) & "otherwise" +) +$ + +Example: +``` + 0 + / \ + 1 2 + / \ + 3 4 +``` +- height(1) = 0 (leaf) +- height(3) = 0 (leaf) +- height(4) = 0 (leaf) +- height(2) = 1 + max(0, 0) = 1 +- height(0) = 1 + max(0, 1) = 2 + +*As mapcode:* + +_primitives_: `max`(max), `add`($+$) + +Let: +- $"Node" = NN$ (node identifiers) +- $"Children" = "Node" -> "Node"^*$ (adjacency list) +- $"Heights" = "Node" -> NN_bot$ (height map) + +$ +I & = "Children" \ +X & = "Heights" \ +A & = NN\ + +rho("children") & = "heights" "where" "heights"[v] = bot quad forall v\ + +F("heights") & = "heights"' "where for each node" v:\ +& "heights"'[v] = cases( + 0 & "if" "children"[v] = emptyset, + 1 + max_(c in "children"[v]) "heights"[c] & "if" forall c in "children"[v]: "heights"[c] != bot, + "heights"[v] & "otherwise (preserve old value)" +)\ + +pi("heights") & = "heights"[0] quad "(root is node 0)" +$ + +#let inst_children = ( + (1, 2), // 0: root + (), // 1: leaf + (3, 4), // 2: branch + (), // 3: leaf + (), // 4: leaf +); + +#figure( + caption: [Tree height computation using mapcode], +$ +#{ + // rho: Initialize all heights to BOTTOM + let rho = (children) => { + let n = children.len() + let heights = () + for i in range(0, n) { + heights.push(none) + } + heights // State is just the heights array + } + + // F_i: Compute height for node i + let F_i = (children) => (heights) => ((i,)) => { + let current = heights.at(i) + + // If already computed, keep it + if current != none { + return current + } + + // Get children of node i + let node_children = children.at(i) + + // Leaf node: height = 0 + if node_children.len() == 0 { + return 0 + } + + // Branch node: check if all children have known heights + let child_heights = () + let all_known = true + for child in node_children { + let child_height = heights.at(child) + if child_height == none { + all_known = false + break + } + child_heights.push(child_height) + } + + // If all children heights are known, compute this node's height + if all_known and child_heights.len() > 0 { + return 1 + calc.max(..child_heights) + } + + // Otherwise, keep as BOTTOM + return none + } + + let F = (children) => (heights) => { + map_tensor(F_i(children), dim: 1)(heights) + } + + let pi = (heights) => { + heights.at(0) // Return height of root (node 0) + } + + // Visualization helper + let X_h = (heights, diff_mask: none) => { + let cells = heights.enumerate().map(((i, h)) => { + let val = if h != none {[$#h$]} else {[$bot$]} + let node_children = inst_children.at(i) + let children_str = if node_children.len() == 0 { + "(leaf)" + } else { + let child_list = node_children.map(c => str(c)).join(",") + "→{" + child_list + "}" + } + + if diff_mask != none and diff_mask.at(i) { + // changed element: highlight + rect(fill: yellow.transparentize(70%), inset: 2pt)[ + $v_#i#text(size: 8pt)[#children_str]: #val$ + ] + } else { + rect(stroke: none, inset: 2pt)[ + $v_#i#text(size: 8pt)[#children_str]: #val$ + ] + } + }) + $vec(delim: "[", ..cells)$ + } + + // Tree visualization + let I_h = (children) => { + // Simple tree representation showing the structure + let nodes = children.enumerate().map(((i, c)) => { + if c.len() == 0 { + [$v_#i$ (leaf)] + } else { + let child_list = c.map(ch => [$v_#ch$]).join([, ]) + [$v_#i -> {#child_list}$] + } + }) + table( + columns: 1, + align: left, + stroke: none, + ..nodes + ) + } + + mapcode-viz( + rho, F(inst_children), pi, + I_h: I_h, + X_h: X_h, + pi_name: [$mpi$], + group-size: calc.min(5, inst_children.len() + 1), + cell-size: 35mm, + scale-fig: 70% + )(inst_children) +} +$ +) diff --git a/main.typ b/main.typ index 9952d9b..d44e422 100644 --- a/main.typ +++ b/main.typ @@ -52,3 +52,8 @@ 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/BellmanFord.typ" +#pagebreak() +#include "algorithms/TreeHeight.typ" +