Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions algorithms/binary-exponentiation.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#import "../lib/style.typ": *
#import "../lib/mapcode.typ": *

== Binary Exponentiation
#set math.equation(numbering: none)

Compute $"base"^"exp"$ for a non-negative integer exponent.

Formal definition:
$
"pow"("base", "exp") &= cases(
1 & "if " exp = 0,
("pow"("base", "exp"/2))^2 & "if " "exp" " is even",
"base" * ("pow"("base", "exp"/2))^2 & "if " "exp" " is odd"
)
$

Examples:
- $"pow"(2, 10) -> 1024$
- $"pow"(3, 5) -> 243$

*As mapcode:*

_primitives_: `mult`($*$) is strict.

$ I = ("base", "exp"): NN times NN quad quad quad X_"exp" &= "Map"(NN -> NN_bot) quad quad quad A = NN\
rho("base", "exp") & = {e -> bot | e " is a required subproblem for " "exp"}\
F(x_"exp") & = cases(
1 & "if " e = 0,
(x_(e/2))^2 & "if " e " is even",
"base" * (x_(e/2))^2 & "if " e " is odd"
)\
pi(x) & = x_"exp"
$


#let inst_base = 2;
#let inst_exp = 10;
#figure(
caption: [Binary Exponentiation computation using mapcode for $#inst_base^#inst_exp$],
$
#{
let get_val = (x, key) => {
let item = x.find(p => p.at(0) == key)
if item != none {
item.at(1)
} else {
none
}
}

let rho = ((base, exp)) => {
let keys = ()
let current_exp = exp
while true {
keys.push(current_exp)
if current_exp == 0 {
break
}
current_exp = calc.floor(current_exp / 2)
}
keys.sorted().map(k => (k, none))
}

let F_i = ((base, exp)) => (x) => (elem) => {
let e = elem.at(0)
let val = elem.at(1)
if val != none {
return (e, val)
}

if e == 0 {
(e, 1)
} else if calc.rem(e, 2) == 0 {
let half_e = calc.floor(e/2);
let half_val = get_val(x, half_e)
if half_val != none {
(e, half_val * half_val)
} else {
(e, none)
}
} else {
let half_e = calc.floor(e/2);
let half_val = get_val(x, half_e)
if half_val != none {
(e, base * half_val * half_val)
} else {
(e, none)
}
}
}

let F = ((base, exp)) => (x) => {
x.map(elem => F_i((base, exp))(x)(elem))
}

let pi_func = ((base, exp)) => (x) => get_val(x, exp)

let X_h = (base) => (x, diff_mask: none) => {
let base_info = [$"base": #base$]
let cells = x.enumerate().map(((i, p)) => {
let key = p.at(0)
let val = p.at(1)
let val_str = if val != none {[$#val$]} else {[$bot$]}
let cell_content = [$#key -> #val_str$]
if diff_mask != none and diff_mask.at(i).at(1) {
rect(fill: yellow.transparentize(70%), inset: 2pt)[#cell_content]
} else {
rect(stroke: none, inset: 2pt)[#cell_content]
}
})
stack(dir: ttb, spacing: 0.5em, base_info, $vec(delim: "{", ..cells)$)
}

mapcode-viz(
rho, F((inst_base, inst_exp)), pi_func((inst_base, inst_exp)),
I_h: ((b,e)) => [$#b^#e$],
X_h: X_h(inst_base),
pi_name: [$pi((#inst_base, #inst_exp))$],
group-size: 2,
cell-size: 30mm,
scale-fig: 95%
)((inst_base, inst_exp))
}
$
)
112 changes: 112 additions & 0 deletions algorithms/gcd.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#import "../lib/style.typ": *
#import "../lib/mapcode.typ": *

== Greatest Common Divisor (GCD)
#set math.equation(numbering: none)

Computes the greatest common divisor of two non-negative integers using the Euclidean algorithm.

Formal definition:
$
"gcd"(a, b) &= cases(
a & "if " b = 0,
"gcd"(b, a mod b) & "otherwise"
)
$

Examples:
- $`gcd`(48, 18) -> 6$
- $`gcd`(101, 103) -> 1$

*As mapcode:*

_primitives_: `mod` (modulo operator)

$
I = ("a", "b"): NN times NN \
X = "Map"(("a","b") -> NN_bot) \
A = NN\
\
rho("a", "b") & = { ("x","y") -> bot | ("x","y") " is a pair in the GCD chain"}\
F(x) & = cases(
"a" & "if " "b" = 0,
x_("b", "a" " mod " "b") & "otherwise"
)\
pi(x) & = x_((a,b)) " where " b=0
$

#let inst_a = 48;
#let inst_b = 18;

#figure(
caption: [GCD computation using mapcode for $`gcd`(#inst_a, #inst_b)$],
$
#{
let get_pairs = (a_start, b_start) => {
let pairs = ()
let a = a_start
let b = b_start
while true {
pairs.push((a, b))
if b == 0 {
break
}
let temp = b
b = calc.rem(a, b)
a = temp
}
pairs
}

let pairs = get_pairs(inst_a, inst_b)
let num_steps = pairs.len()

let rho = (inst) => {
let x = ()
for i in range(0, num_steps) {
x.push(none)
}
x
}

let F_i = (x) => ((i,)) => {
if i == num_steps - 1 {
// Base case: gcd(a, 0) = a
let (a, b) = pairs.at(i)
a
} else if x.at(i + 1) != none {
x.at(i + 1)
} else {
none
}
}
let F = map_tensor(F_i, dim: 1)

let pi_func = (x) => x.at(0)

let X_h = (x, diff_mask: none) => {
let cells = x.enumerate().map(((i, x_i)) => {
let (a, b) = pairs.at(i)
let val = if x_i != none {[#x_i]} else {[$bot$]}
let cell_content = [$"gcd"(#a, #b) -> #val$]
if diff_mask != none and diff_mask.at(i) {
rect(fill: yellow.transparentize(70%), inset: 2pt)[#cell_content]
} else {
rect(stroke: none, inset: 2pt)[#cell_content]
}
})
$vec(delim: "{", ..cells)$
}

mapcode-viz(
rho, F, pi_func,
I_h: ((a,b)) => [$"gcd"(#a, #b)$],
X_h: X_h,
pi_name: [$pi((#inst_a, #inst_b))$],
group-size: 2,
cell-size: 40mm,
scale-fig: 95%
)((inst_a, inst_b))
}
$
)
4 changes: 4 additions & 0 deletions main.typ
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ 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/binary-exponentiation.typ"
#pagebreak()
#include "algorithms/gcd.typ"