From 462a3b82cdc5a44918751360675a13a8ac3a3a7e Mon Sep 17 00:00:00 2001 From: alifarahbakhsh <139010854+alifarahbakhsh@users.noreply.github.com> Date: Wed, 30 Aug 2023 13:28:54 +0000 Subject: [PATCH 01/13] Added palindrome benchmark Benchmark for 6120'23 task 2 --- benchmarks/core/palindrome.bril | 80 +++++++++++++++++++++++++++++++++ benchmarks/core/palindrome.out | 1 + docs/tools/bench.md | 2 + 3 files changed, 83 insertions(+) create mode 100644 benchmarks/core/palindrome.bril create mode 100644 benchmarks/core/palindrome.out diff --git a/benchmarks/core/palindrome.bril b/benchmarks/core/palindrome.bril new file mode 100644 index 000000000..bbfcbdcb3 --- /dev/null +++ b/benchmarks/core/palindrome.bril @@ -0,0 +1,80 @@ +# ARGS: 12321 +@main(in: int) { +#in: int = const 2343553432; +ten: int = const 10; +zero: int = const 0; +one: int = const 1; +index: int = const 1; +not_finished: bool = const true; +.for.cond: + br not_finished .for.body .for.end; +.for.body: + power: int = call @pow ten index; + d: int = div in power; + check: bool = eq d zero; + br check .if.true .if.false; + .if.true: + not_finished: bool = const false; + jmp .for.cond; + .if.false: + index: int = add index one; + jmp .for.cond; +.for.end: + exp: int = sub index one; + is_palindrome: bool = call @palindrome in exp; + print is_palindrome; +} + +@pow(base: int, exp: int): int { +res: int = const 1; +zero: int = const 0; +one: int = const 1; +not_finished: bool = const true; +.for.cond.pow: + br not_finished .for.body.pow .for.end.pow; +.for.body.pow: + finished: bool = eq exp zero; + br finished .if.true.pow .if.false.pow; + .if.true.pow: + not_finished: bool = const false; + jmp .for.cond.pow; + .if.false.pow: + res: int = mul res base; + exp: int = sub exp one; + jmp .for.cond.pow; +.for.end.pow: + ret res; +} + +@palindrome(in: int, len: int): bool { + is_palindrome: bool = const false; + zero: int = const 0; + two: int = const 2; + ten: int = const 10; + check: bool = le len zero; + br check .if.true.palindrome .if.false.palindrome; + .if.true.palindrome: + is_palindrome: bool = const true; + jmp .if.end.palindrome; + .if.false.palindrome: + power: int = call @pow ten len; + left: int = div in power; + v1: int = div in ten; + v2: int = mul v1 ten; + right: int = sub in v2; + is_equal: bool = eq left right; + br is_equal .if.true.mirror .if.false.mirror; + .if.true.mirror: + temp: int = mul power left; + temp: int = sub in temp; + temp: int = sub temp right; + next_in: int = div temp ten; + next_len: int = sub len two; + is_palindrome: bool = call @palindrome next_in next_len; + jmp .if.end.palindrome; + .if.false.mirror: + is_palindrome: bool = const false; + jmp .if.end.palindrome; + .if.end.palindrome: + ret is_palindrome; +} \ No newline at end of file diff --git a/benchmarks/core/palindrome.out b/benchmarks/core/palindrome.out new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/benchmarks/core/palindrome.out @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 95445b416..7ed5e25ae 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -36,6 +36,7 @@ The current benchmarks are: * `n_root`: Calculate nth root of a float using newton's method. * `orders`: Compute the order ord(u) for each u in a cyclic group [][cgroup] of integers modulo *n* under the group operation + (modulo *n*). Set the second argument *is_lcm* to true if you would like to compute the orders using the lowest common multiple and otherwise the program will use the greatest common divisor. * `pascals-row`: Computes a row in Pascal's Triangle. +* `palindrome`: Outputs a 0-1 value indicating whether the input is a [palindrome][palindrome] number. * `perfect`: Check if input argument is a perfect number. Returns output as Unix style return code. * `pow`: Computes the n^th power of a given (float) number. * `primes-between`: Print the primes in the interval `[a, b]`. @@ -77,3 +78,4 @@ Credit for several of these benchmarks goes to Alexa VanHattum and Gregory Yaune [uparrow]: https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation [riemann]: https://en.wikipedia.org/wiki/Riemann_sum [mandelbrot]: https://en.wikipedia.org/wiki/Mandelbrot_set +[palindrome]: https://en.wikipedia.org/wiki/Palindrome From b34083c9f37b3bf359ffc895216018d82b473f11 Mon Sep 17 00:00:00 2001 From: alifarahbakhsh <139010854+alifarahbakhsh@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:43:44 +0000 Subject: [PATCH 02/13] Add newline at the end of palindrome.out --- benchmarks/core/palindrome.out | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/core/palindrome.out b/benchmarks/core/palindrome.out index f32a5804e..27ba77dda 100644 --- a/benchmarks/core/palindrome.out +++ b/benchmarks/core/palindrome.out @@ -1 +1 @@ -true \ No newline at end of file +true From cbd6407b931ef1ec95c96bc5fc8b657300ea55bb Mon Sep 17 00:00:00 2001 From: Omkar Bhalerao Date: Wed, 30 Aug 2023 15:19:20 -0400 Subject: [PATCH 03/13] add euler's totient function benchmark --- benchmarks/core/totient.bril | 66 ++++++++++++++++++++++++++++++++++++ benchmarks/core/totient.out | 2 ++ benchmarks/core/totient.prof | 1 + 3 files changed, 69 insertions(+) create mode 100644 benchmarks/core/totient.bril create mode 100644 benchmarks/core/totient.out create mode 100644 benchmarks/core/totient.prof diff --git a/benchmarks/core/totient.bril b/benchmarks/core/totient.bril new file mode 100644 index 000000000..02ac090e2 --- /dev/null +++ b/benchmarks/core/totient.bril @@ -0,0 +1,66 @@ +# ARGS: 2023 +@main (n: int) { + print n; + tot: int = call @totient n; + print tot; +} + +@totient (n: int): int { + result: int = id n; + p: int = const 2; + one: int = const 1; + zero: int = const 0; + +.for.set.cond: + pp: int = mul p p; + cond: bool = le pp n; + br cond .for.set.body .for.set.end; + +.for.set.body: + + npmod: int = call @mod n p; + if_cond: bool = eq npmod zero; + br if_cond .if_lbl .else_lbl; +.if_lbl: + +.while.set.cond: + + npmod: int = call @mod n p; + while_cond: bool = eq npmod zero; + br while_cond .while.body .while.end; + +.while.body: + npdiv: int = div n p; + n: int = id npdiv; + jmp .while.set.cond; + +.while.end: + + resdiv: int = div result p; + result: int = sub result resdiv; + +.else_lbl: + + p: int = add p one; + jmp .for.set.cond; + +.for.set.end: + + final_if_cond: bool = gt n one; + br final_if_cond .final_if_label .final_else_label; + +.final_if_label: + resdiv: int = div result n; + result: int = sub result resdiv; + +.final_else_label: + + ret result; +} + +@mod (a: int, b: int): int { + ad: int = div a b; + mad: int = mul b ad; + ans: int = sub a mad; + ret ans; +} diff --git a/benchmarks/core/totient.out b/benchmarks/core/totient.out new file mode 100644 index 000000000..0dd06b31d --- /dev/null +++ b/benchmarks/core/totient.out @@ -0,0 +1,2 @@ +2023 +1632 diff --git a/benchmarks/core/totient.prof b/benchmarks/core/totient.prof new file mode 100644 index 000000000..d8c8e70f1 --- /dev/null +++ b/benchmarks/core/totient.prof @@ -0,0 +1 @@ +total_dyn_inst: 253 From f5ca8c5982e9823dfe59105b314ff454cc21068c Mon Sep 17 00:00:00 2001 From: Omkar Bhalerao Date: Wed, 30 Aug 2023 16:44:12 -0400 Subject: [PATCH 04/13] add entry to docs --- docs/tools/bench.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 32eb021bf..152866ae1 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -54,6 +54,7 @@ The current benchmarks are: * `sum-bit`: Print the number of 1-bits in the binary representation of the input integer. * `sum-divisors`: Prints the positive integer divisors of the input integer, followed by the sum of the divisors. * `sum-sq-diff`: Output the difference between the sum of the squares of the first *n* natural numbers and the square of their sum. +* `totient`: Computes [Euler's totient function][totient] on an input integer *n*. * `up-arrow`: Computes [Knuth's up arrow][uparrow] notation, with the first argument being the number, the second argument being the number of Knuth's up arrows, and the third argument being the number of repeats. * `reverse`: Compute number with reversed digits (e.g. 123 -> 321). @@ -84,3 +85,4 @@ Credit for several of these benchmarks goes to Alexa VanHattum and Gregory Yaune [mandelbrot]: https://en.wikipedia.org/wiki/Mandelbrot_set [hanoi]: https://en.wikipedia.org/wiki/Tower_of_Hanoi [euler]: https://en.wikipedia.org/wiki/E_(mathematical_constant) +[totient]: https://en.wikipedia.org/wiki/Euler's_totient_function \ No newline at end of file From 8ca9dbb13a008e35e63c0038e2b815e8ccb23a59 Mon Sep 17 00:00:00 2001 From: Yi Date: Wed, 30 Aug 2023 17:48:51 -0400 Subject: [PATCH 05/13] add mod inv --- benchmarks/core/mod_inv.bril | 85 ++++++++++++++++++++++++++++++++++++ benchmarks/core/mod_inv.out | 1 + benchmarks/core/mod_inv.prof | 1 + docs/tools/bench.md | 2 + 4 files changed, 89 insertions(+) create mode 100644 benchmarks/core/mod_inv.bril create mode 100644 benchmarks/core/mod_inv.out create mode 100644 benchmarks/core/mod_inv.prof diff --git a/benchmarks/core/mod_inv.bril b/benchmarks/core/mod_inv.bril new file mode 100644 index 000000000..14463fa2b --- /dev/null +++ b/benchmarks/core/mod_inv.bril @@ -0,0 +1,85 @@ +# ARGS: 46, 10007 +@main(n: int, p: int) { + v0: int = const 2; + two: int = id v0; + v1: int = id p; + v2: int = id two; + v3: int = sub v1 v2; + m: int = id v3; + v4: int = const 1; + ans: int = id v4; + v5: int = id n; + a: int = id v5; + v7: int = const 1; + i: int = id v7; +.for.cond.6: + v8: int = id m; + v9: int = const 0; + v10: bool = gt v8 v9; + br v10 .for.body.6 .for.end.6; +.for.body.6: + v12: int = id m; + v13: int = id m; + v14: int = id two; + v15: int = div v13 v14; + v16: int = id two; + v17: int = mul v15 v16; + v18: bool = eq v12 v17; + br v18 .then.11 .else.11; +.then.11: + jmp .endif.11; +.else.11: + v19: int = id ans; + v20: int = id a; + v21: int = mul v19 v20; + v22: int = id p; + v23: int = call @mod v21 v22; + ans: int = id v23; +.endif.11: + v24: int = id a; + v25: int = id a; + v26: int = mul v24 v25; + v27: int = id p; + v28: int = call @mod v26 v27; + a: int = id v28; + v29: int = id m; + v30: int = id two; + v31: int = div v29 v30; + m: int = id v31; + jmp .for.cond.6; +.for.end.6: + v32: int = id ans; + print v32; + v33: int = const 0; +} +@mod(n: int, p: int): int { + v0: int = id n; + v1: int = id n; + v2: int = id p; + v3: int = div v1 v2; + v4: int = id p; + v5: int = mul v3 v4; + v6: int = sub v0 v5; + ret v6; +} + +# function main(n: bigint, p: bigint) { +# var two: bigint = 2; +# var m: bigint = p - two; +# var ans: bigint = 1; +# var a: bigint = n; +# for (let i = 1; m > 0; m = m / two) { +# if (m == m / two * two) { +# } +# else { +# ans = mod(ans * a, p); +# } +# a = mod(a * a, p); +# } +# console.log(ans); +# } +# +# function mod(n: bigint, p: bigint): bigint { +# return n - n / p * p; +# } + diff --git a/benchmarks/core/mod_inv.out b/benchmarks/core/mod_inv.out new file mode 100644 index 000000000..6726ecf8d --- /dev/null +++ b/benchmarks/core/mod_inv.out @@ -0,0 +1 @@ +2393 diff --git a/benchmarks/core/mod_inv.prof b/benchmarks/core/mod_inv.prof new file mode 100644 index 000000000..d62b26752 --- /dev/null +++ b/benchmarks/core/mod_inv.prof @@ -0,0 +1 @@ +total_dyn_inst: 558 diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 162264752..1f8543c8b 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -35,6 +35,7 @@ The current benchmarks are: * `mat-inv` : Calculates the inverse of a 3x3 matrix and prints it out. * `mat-mul`: Multiplies two `nxn` matrices using the [naive][matmul] matrix multiplication algorithm. The matrices are randomly generated using a [linear congruential generator][rng]. * `max-subarray`: solution to the classic Maximum Subarray problem. +* `mod_inv`: Calculates the [modular inverse][modinv] of `n` under to a prime modulus p. * `newton`: Calculate the square root of 99,999 using the [newton method][newton] * `n_root`: Calculate nth root of a float using newton's method. * `orders`: Compute the order ord(u) for each u in a cyclic group [][cgroup] of integers modulo *n* under the group operation + (modulo *n*). Set the second argument *is_lcm* to true if you would like to compute the orders using the lowest common multiple and otherwise the program will use the greatest common divisor. @@ -83,3 +84,4 @@ Credit for several of these benchmarks goes to Alexa VanHattum and Gregory Yaune [mandelbrot]: https://en.wikipedia.org/wiki/Mandelbrot_set [hanoi]: https://en.wikipedia.org/wiki/Tower_of_Hanoi [euler]: https://en.wikipedia.org/wiki/E_(mathematical_constant) +[modinv]: https://en.wikipedia.org/wiki/Modular_multiplicative_inverse From e85e4794e7e0fa1c44d404ef957365f790b2c5a0 Mon Sep 17 00:00:00 2001 From: Yi Date: Wed, 30 Aug 2023 17:53:13 -0400 Subject: [PATCH 06/13] add some comments --- benchmarks/core/mod_inv.bril | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/benchmarks/core/mod_inv.bril b/benchmarks/core/mod_inv.bril index 14463fa2b..f5ee57cf6 100644 --- a/benchmarks/core/mod_inv.bril +++ b/benchmarks/core/mod_inv.bril @@ -63,6 +63,9 @@ ret v6; } +# ts2bril inv.ts | bril2txt | tail +3 | sed -E 's/float/int/g' | sed -E 's/fgt/gt/g' > inv.bril +# generated by typescript code below: +# # function main(n: bigint, p: bigint) { # var two: bigint = 2; # var m: bigint = p - two; @@ -82,4 +85,6 @@ # function mod(n: bigint, p: bigint): bigint { # return n - n / p * p; # } +# + From 9eadf4b6e95f77cee4eaf1c7a86fcef984967554 Mon Sep 17 00:00:00 2001 From: SanjitBasker <64987259+SanjitBasker@users.noreply.github.com> Date: Wed, 30 Aug 2023 19:48:06 -0400 Subject: [PATCH 07/13] first pass at implementing primitive root --- new-bench/primes.bril | 213 ++++++ new-bench/primes.json | 1512 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1725 insertions(+) create mode 100644 new-bench/primes.bril create mode 100644 new-bench/primes.json diff --git a/new-bench/primes.bril b/new-bench/primes.bril new file mode 100644 index 000000000..09e31b1b5 --- /dev/null +++ b/new-bench/primes.bril @@ -0,0 +1,213 @@ +@rem(a: int, b: int): int { + quotient : int = div a b; + guess : int = mul b quotient; + rem : int = sub a guess; + ret rem; +} + +# returns m | n +@divides(m: int, n: int): bool { + zero : int = const 0; + quotient : int = div n m; + guess : int = mul m quotient; + rem : int = sub n guess; + res : bool = eq rem zero; + ret res; +} + +# prepends n to ns, assuming that ns is an array of length l +@prepend(n : int, ns: ptr, l : int) : ptr { + one: int = const 1; + new : int = add l one; + out : ptr = alloc new; + + i : int = const 0; + store out n; + curr : ptr = id ns; + curr2 : ptr = ptradd out one; + .repeat: + stop : bool = lt i l; + br stop .next .exit; + .next: + tmp : int = load curr; + store curr2 tmp; + i : int = add i one; + curr : ptr = ptradd curr one; + curr2 : ptr = ptradd curr2 one; + jmp .repeat; + .exit: + free ns; + ret out; +} + +# returns the smallest prime factor of n. requires n > 1. +@prime_factor(n: int): int { + guess : int = const 2; + inc : int = const 1; + + # max : int = const 100; + + .continue: + square: int = mul guess guess; + continue : bool = lt square n; + works : bool = call @divides guess n; + br works .yay .inc; + .yay: + ret guess; + .inc: + guess : int = add guess inc; + br continue .continue .giveup; + + .giveup: + ret n; +} + +# stores the number of prime factors in num_factors and returns an array of them +# ans is padded by 0 due to alloc difficulties +@prime_factors(n: int, num_factors: ptr): ptr { + count : int = const 1; + zero : int = const 0; + one : int = const 1; + ans : ptr = alloc count; + store ans zero; + + .continue: + exit : bool = eq n one; + br exit .exit .next; + .next: + prime : int = call @prime_factor n; + .repeat: + n : int = div n prime; + divides : bool = call @divides prime n; + br divides .repeat .divided; + .divided: + tmp : int = sub count one; + ans : ptr = call @prepend prime ans count; + count : int = add count one; + jmp .continue; + .exit: + store num_factors count; + ret ans; + +} + +@modexp(a : int, k : int, m : int) : int { + zero : int = const 0; + one : int = const 1; + two : int = const 2; + a : int = call @rem a m; + + + eq_zero : bool = eq zero k; + br eq_zero .exp_zero .not_zero; + + .exp_zero: + ret one; + + .not_zero: + eq_one : bool = eq one k; + br eq_one .exp_one .not_one; + + .exp_one: + ret a; + + .not_one: + rem_two : int = call @rem k two; + post_mul : bool = eq rem_two one; + + half_exp : int = div k two; + sqrt : int = call @modexp a half_exp m; + res : int = mul sqrt sqrt; + res : int = call @rem res m; + + br post_mul .post_multiply .no_post; + + .post_multiply: + res : int = mul res a; + res : int = call @rem res m; + .no_post: + + .exit: + ret res; +} + +@check_ord(p : int, phi_p : int, factors : ptr, guess : int) : bool { + count : int = const 0; + zero : int = const 0; + one : int = const 1; + ptr : ptr = id factors; + + .check_power: + factor : int = load ptr; + stop = eq factor zero; + br stop .ret_true .next1; + + .next1: + power : int = div phi_p factor; + exp : int = call @modexp guess power p; + is_one : bool = eq exp one; + br is_one .ret_false .next2; + + .next2: + ptr : ptr = ptradd ptr one; + count : int = add count one; + jmp .check_power; + + .ret_true: + t : bool = const true; + ret t; + + .ret_false: + t : bool = const false; + ret t; +} + + +@search_primitive(p : int, phi_p : int, factors : ptr, start : int) : int { + fallback : int = const -999; + one : int = const 1; + + guess : int = id start; + + .eval: + too_big : int = ge guess p; + br too_big .done_guess .keep_trying; + + .keep_trying: + works : bool = call @check_ord p phi_p factors guess; + br works .ret .inc; + + .ret: + ret guess; + + .inc: + guess : int = add guess one; + jmp .eval; + + + .done_guess: + ret fallback; +} + + +@phi(p : int) : int { + one : int = const 1; + q : int = sub p one; + ret q; +} + +# +@main() { + p : int = const 1151; + one : int = const 1; + phi_p : int = call @phi p; + count_result : ptr = alloc one; + prime_factors : ptr = call @prime_factors phi_p count_result; + num_factors : int = load count_result; + + res : int = call @search_primitive p phi_p prime_factors one; + print res; + + free count_result; + free prime_factors; +} diff --git a/new-bench/primes.json b/new-bench/primes.json new file mode 100644 index 000000000..a423aa403 --- /dev/null +++ b/new-bench/primes.json @@ -0,0 +1,1512 @@ +{ + "functions": [ + { + "args": [ + { + "name": "a", + "type": "int" + }, + { + "name": "b", + "type": "int" + } + ], + "instrs": [ + { + "args": [ + "a", + "b" + ], + "dest": "quotient", + "op": "div", + "type": "int" + }, + { + "args": [ + "b", + "quotient" + ], + "dest": "guess", + "op": "mul", + "type": "int" + }, + { + "args": [ + "a", + "guess" + ], + "dest": "rem", + "op": "sub", + "type": "int" + }, + { + "args": [ + "rem" + ], + "op": "ret" + } + ], + "name": "rem", + "type": "int" + }, + { + "args": [ + { + "name": "m", + "type": "int" + }, + { + "name": "n", + "type": "int" + } + ], + "instrs": [ + { + "dest": "zero", + "op": "const", + "type": "int", + "value": 0 + }, + { + "args": [ + "n", + "m" + ], + "dest": "quotient", + "op": "div", + "type": "int" + }, + { + "args": [ + "m", + "quotient" + ], + "dest": "guess", + "op": "mul", + "type": "int" + }, + { + "args": [ + "n", + "guess" + ], + "dest": "rem", + "op": "sub", + "type": "int" + }, + { + "args": [ + "rem", + "zero" + ], + "dest": "res", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "res" + ], + "op": "ret" + } + ], + "name": "divides", + "type": "bool" + }, + { + "args": [ + { + "name": "n", + "type": "int" + }, + { + "name": "ns", + "type": { + "ptr": "int" + } + }, + { + "name": "l", + "type": "int" + } + ], + "instrs": [ + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "l", + "one" + ], + "dest": "new", + "op": "add", + "type": "int" + }, + { + "args": [ + "new" + ], + "dest": "out", + "op": "alloc", + "type": { + "ptr": "int" + } + }, + { + "dest": "i", + "op": "const", + "type": "int", + "value": 0 + }, + { + "args": [ + "out", + "n" + ], + "op": "store" + }, + { + "args": [ + "ns" + ], + "dest": "curr", + "op": "id", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "out", + "one" + ], + "dest": "curr2", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "label": "repeat" + }, + { + "args": [ + "i", + "l" + ], + "dest": "stop", + "op": "lt", + "type": "bool" + }, + { + "args": [ + "stop" + ], + "labels": [ + "next", + "exit" + ], + "op": "br" + }, + { + "label": "next" + }, + { + "args": [ + "curr" + ], + "dest": "tmp", + "op": "load", + "type": "int" + }, + { + "args": [ + "curr2", + "tmp" + ], + "op": "store" + }, + { + "args": [ + "i", + "one" + ], + "dest": "i", + "op": "add", + "type": "int" + }, + { + "args": [ + "curr", + "one" + ], + "dest": "curr", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "curr2", + "one" + ], + "dest": "curr2", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "labels": [ + "repeat" + ], + "op": "jmp" + }, + { + "label": "exit" + }, + { + "args": [ + "ns" + ], + "op": "free" + }, + { + "args": [ + "out" + ], + "op": "ret" + } + ], + "name": "prepend", + "type": { + "ptr": "int" + } + }, + { + "args": [ + { + "name": "n", + "type": "int" + } + ], + "instrs": [ + { + "dest": "guess", + "op": "const", + "type": "int", + "value": 2 + }, + { + "dest": "inc", + "op": "const", + "type": "int", + "value": 1 + }, + { + "label": "continue" + }, + { + "args": [ + "guess", + "guess" + ], + "dest": "square", + "op": "mul", + "type": "int" + }, + { + "args": [ + "square", + "n" + ], + "dest": "continue", + "op": "lt", + "type": "bool" + }, + { + "args": [ + "guess", + "n" + ], + "dest": "works", + "funcs": [ + "divides" + ], + "op": "call", + "type": "bool" + }, + { + "args": [ + "works" + ], + "labels": [ + "yay", + "inc" + ], + "op": "br" + }, + { + "label": "yay" + }, + { + "args": [ + "guess" + ], + "op": "ret" + }, + { + "label": "inc" + }, + { + "args": [ + "guess", + "inc" + ], + "dest": "guess", + "op": "add", + "type": "int" + }, + { + "args": [ + "continue" + ], + "labels": [ + "continue", + "giveup" + ], + "op": "br" + }, + { + "label": "giveup" + }, + { + "args": [ + "n" + ], + "op": "ret" + } + ], + "name": "prime_factor", + "type": "int" + }, + { + "args": [ + { + "name": "n", + "type": "int" + }, + { + "name": "num_factors", + "type": { + "ptr": "int" + } + } + ], + "instrs": [ + { + "dest": "count", + "op": "const", + "type": "int", + "value": 1 + }, + { + "dest": "zero", + "op": "const", + "type": "int", + "value": 0 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "count" + ], + "dest": "ans", + "op": "alloc", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "ans", + "zero" + ], + "op": "store" + }, + { + "label": "continue" + }, + { + "args": [ + "n", + "one" + ], + "dest": "exit", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "exit" + ], + "labels": [ + "exit", + "next" + ], + "op": "br" + }, + { + "label": "next" + }, + { + "args": [ + "n" + ], + "dest": "prime", + "funcs": [ + "prime_factor" + ], + "op": "call", + "type": "int" + }, + { + "label": "repeat" + }, + { + "args": [ + "n", + "prime" + ], + "dest": "n", + "op": "div", + "type": "int" + }, + { + "args": [ + "prime", + "n" + ], + "dest": "divides", + "funcs": [ + "divides" + ], + "op": "call", + "type": "bool" + }, + { + "args": [ + "divides" + ], + "labels": [ + "repeat", + "divided" + ], + "op": "br" + }, + { + "label": "divided" + }, + { + "args": [ + "count", + "one" + ], + "dest": "tmp", + "op": "sub", + "type": "int" + }, + { + "args": [ + "prime", + "ans", + "count" + ], + "dest": "ans", + "funcs": [ + "prepend" + ], + "op": "call", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "count", + "one" + ], + "dest": "count", + "op": "add", + "type": "int" + }, + { + "labels": [ + "continue" + ], + "op": "jmp" + }, + { + "label": "exit" + }, + { + "args": [ + "num_factors", + "count" + ], + "op": "store" + }, + { + "args": [ + "ans" + ], + "op": "ret" + } + ], + "name": "prime_factors", + "type": { + "ptr": "int" + } + }, + { + "args": [ + { + "name": "a", + "type": "int" + }, + { + "name": "k", + "type": "int" + }, + { + "name": "m", + "type": "int" + } + ], + "instrs": [ + { + "dest": "zero", + "op": "const", + "type": "int", + "value": 0 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "dest": "two", + "op": "const", + "type": "int", + "value": 2 + }, + { + "args": [ + "a", + "m" + ], + "dest": "a", + "funcs": [ + "rem" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "zero", + "k" + ], + "dest": "eq_zero", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "eq_zero" + ], + "labels": [ + "exp_zero", + "not_zero" + ], + "op": "br" + }, + { + "label": "exp_zero" + }, + { + "args": [ + "one" + ], + "op": "ret" + }, + { + "label": "not_zero" + }, + { + "args": [ + "one", + "k" + ], + "dest": "eq_one", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "eq_one" + ], + "labels": [ + "exp_one", + "not_one" + ], + "op": "br" + }, + { + "label": "exp_one" + }, + { + "args": [ + "a" + ], + "op": "ret" + }, + { + "label": "not_one" + }, + { + "args": [ + "k", + "two" + ], + "dest": "rem_two", + "funcs": [ + "rem" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "rem_two", + "one" + ], + "dest": "post_mul", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "k", + "two" + ], + "dest": "half_exp", + "op": "div", + "type": "int" + }, + { + "args": [ + "a", + "half_exp", + "m" + ], + "dest": "sqrt", + "funcs": [ + "modexp" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "sqrt", + "sqrt" + ], + "dest": "res", + "op": "mul", + "type": "int" + }, + { + "args": [ + "res", + "m" + ], + "dest": "res", + "funcs": [ + "rem" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "post_mul" + ], + "labels": [ + "post_multiply", + "no_post" + ], + "op": "br" + }, + { + "label": "post_multiply" + }, + { + "args": [ + "res", + "a" + ], + "dest": "res", + "op": "mul", + "type": "int" + }, + { + "args": [ + "res", + "m" + ], + "dest": "res", + "funcs": [ + "rem" + ], + "op": "call", + "type": "int" + }, + { + "label": "no_post" + }, + { + "label": "exit" + }, + { + "args": [ + "res" + ], + "op": "ret" + } + ], + "name": "modexp", + "type": "int" + }, + { + "args": [ + { + "name": "p", + "type": "int" + }, + { + "name": "phi_p", + "type": "int" + }, + { + "name": "factors", + "type": { + "ptr": "int" + } + }, + { + "name": "guess", + "type": "int" + } + ], + "instrs": [ + { + "dest": "count", + "op": "const", + "type": "int", + "value": 0 + }, + { + "dest": "zero", + "op": "const", + "type": "int", + "value": 0 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "factors" + ], + "dest": "ptr", + "op": "id", + "type": { + "ptr": "int" + } + }, + { + "label": "check_power" + }, + { + "args": [ + "ptr" + ], + "dest": "factor", + "op": "load", + "type": "int" + }, + { + "args": [ + "factor", + "zero" + ], + "dest": "stop", + "op": "eq" + }, + { + "args": [ + "stop" + ], + "labels": [ + "ret_true", + "next1" + ], + "op": "br" + }, + { + "label": "next1" + }, + { + "args": [ + "phi_p", + "factor" + ], + "dest": "power", + "op": "div", + "type": "int" + }, + { + "args": [ + "guess", + "power", + "p" + ], + "dest": "exp", + "funcs": [ + "modexp" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "exp", + "one" + ], + "dest": "is_one", + "op": "eq", + "type": "bool" + }, + { + "args": [ + "is_one" + ], + "labels": [ + "ret_false", + "next2" + ], + "op": "br" + }, + { + "label": "next2" + }, + { + "args": [ + "ptr", + "one" + ], + "dest": "ptr", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "count", + "one" + ], + "dest": "count", + "op": "add", + "type": "int" + }, + { + "labels": [ + "check_power" + ], + "op": "jmp" + }, + { + "label": "ret_true" + }, + { + "dest": "t", + "op": "const", + "type": "bool", + "value": true + }, + { + "args": [ + "t" + ], + "op": "ret" + }, + { + "label": "ret_false" + }, + { + "dest": "t", + "op": "const", + "type": "bool", + "value": false + }, + { + "args": [ + "t" + ], + "op": "ret" + } + ], + "name": "check_ord", + "type": "bool" + }, + { + "args": [ + { + "name": "p", + "type": "int" + }, + { + "name": "phi_p", + "type": "int" + }, + { + "name": "factors", + "type": { + "ptr": "int" + } + }, + { + "name": "start", + "type": "int" + } + ], + "instrs": [ + { + "dest": "fallback", + "op": "const", + "type": "int", + "value": -999 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "start" + ], + "dest": "guess", + "op": "id", + "type": "int" + }, + { + "label": "eval" + }, + { + "args": [ + "guess", + "p" + ], + "dest": "too_big", + "op": "ge", + "type": "int" + }, + { + "args": [ + "too_big" + ], + "labels": [ + "done_guess", + "keep_trying" + ], + "op": "br" + }, + { + "label": "keep_trying" + }, + { + "args": [ + "p", + "phi_p", + "factors", + "guess" + ], + "dest": "works", + "funcs": [ + "check_ord" + ], + "op": "call", + "type": "bool" + }, + { + "args": [ + "works" + ], + "labels": [ + "ret", + "inc" + ], + "op": "br" + }, + { + "label": "ret" + }, + { + "args": [ + "guess" + ], + "op": "ret" + }, + { + "label": "inc" + }, + { + "args": [ + "guess", + "one" + ], + "dest": "guess", + "op": "add", + "type": "int" + }, + { + "labels": [ + "eval" + ], + "op": "jmp" + }, + { + "label": "done_guess" + }, + { + "args": [ + "fallback" + ], + "op": "ret" + } + ], + "name": "search_primitive", + "type": "int" + }, + { + "args": [ + { + "name": "p", + "type": "int" + } + ], + "instrs": [ + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "p", + "one" + ], + "dest": "q", + "op": "sub", + "type": "int" + }, + { + "args": [ + "q" + ], + "op": "ret" + } + ], + "name": "phi", + "type": "int" + }, + { + "instrs": [ + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "dest": "zero", + "op": "const", + "type": "int", + "value": 0 + }, + { + "args": [ + "zero", + "one" + ], + "dest": "mone", + "op": "sub", + "type": "int" + }, + { + "dest": "x", + "op": "const", + "type": "int", + "value": 12 + }, + { + "dest": "y", + "op": "const", + "type": "int", + "value": 23 + }, + { + "args": [ + "one" + ], + "dest": "arr", + "op": "alloc", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "arr", + "y" + ], + "op": "store" + }, + { + "args": [ + "x", + "arr", + "one" + ], + "dest": "arr", + "funcs": [ + "prepend" + ], + "op": "call", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "arr" + ], + "dest": "tmp1", + "op": "load", + "type": "int" + }, + { + "args": [ + "arr", + "one" + ], + "dest": "arr", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "arr" + ], + "dest": "tmp2", + "op": "load", + "type": "int" + }, + { + "args": [ + "arr", + "mone" + ], + "dest": "arr", + "op": "ptradd", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "tmp1" + ], + "op": "print" + }, + { + "args": [ + "tmp2" + ], + "op": "print" + }, + { + "args": [ + "arr" + ], + "op": "free" + } + ], + "name": "main_test_prepend" + }, + { + "instrs": [ + { + "dest": "x", + "op": "const", + "type": "int", + "value": 23 + }, + { + "dest": "y", + "op": "const", + "type": "int", + "value": 4 + }, + { + "dest": "n", + "op": "const", + "type": "int", + "value": 50 + }, + { + "args": [ + "x", + "y", + "n" + ], + "dest": "res", + "funcs": [ + "modexp" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "res" + ], + "op": "print" + } + ], + "name": "main2" + }, + { + "instrs": [ + { + "dest": "p", + "op": "const", + "type": "int", + "value": 1151 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "p" + ], + "dest": "phi_p", + "funcs": [ + "phi" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "one" + ], + "dest": "count_result", + "op": "alloc", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "phi_p", + "count_result" + ], + "dest": "prime_factors", + "funcs": [ + "prime_factors" + ], + "op": "call", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "count_result" + ], + "dest": "num_factors", + "op": "load", + "type": "int" + }, + { + "dest": "guess", + "op": "const", + "type": "int", + "value": 121 + }, + { + "args": [ + "p", + "phi_p", + "prime_factors", + "guess" + ], + "dest": "res", + "funcs": [ + "check_ord" + ], + "op": "call", + "type": "bool" + }, + { + "args": [ + "res" + ], + "op": "print" + }, + { + "args": [ + "count_result" + ], + "op": "free" + }, + { + "args": [ + "prime_factors" + ], + "op": "free" + } + ], + "name": "main_test" + }, + { + "instrs": [ + { + "dest": "p", + "op": "const", + "type": "int", + "value": 1151 + }, + { + "dest": "one", + "op": "const", + "type": "int", + "value": 1 + }, + { + "args": [ + "p" + ], + "dest": "phi_p", + "funcs": [ + "phi" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "one" + ], + "dest": "count_result", + "op": "alloc", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "phi_p", + "count_result" + ], + "dest": "prime_factors", + "funcs": [ + "prime_factors" + ], + "op": "call", + "type": { + "ptr": "int" + } + }, + { + "args": [ + "count_result" + ], + "dest": "num_factors", + "op": "load", + "type": "int" + }, + { + "args": [ + "p", + "phi_p", + "prime_factors", + "one" + ], + "dest": "res", + "funcs": [ + "search_primitive" + ], + "op": "call", + "type": "int" + }, + { + "args": [ + "res" + ], + "op": "print" + }, + { + "args": [ + "count_result" + ], + "op": "free" + }, + { + "args": [ + "prime_factors" + ], + "op": "free" + } + ], + "name": "main" + } + ] +} From 489d6b106425612a1b8f6076e236673f82223fb0 Mon Sep 17 00:00:00 2001 From: SanjitBasker <64987259+SanjitBasker@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:01:25 -0400 Subject: [PATCH 08/13] added new benchmark --- .../mem/primitive-root.bril | 6 +- benchmarks/mem/primitive-root.out | 1 + benchmarks/mem/primitive-root.prof | 1 + docs/tools/bench.md | 2 + new-bench/primes.json | 1512 ----------------- 5 files changed, 7 insertions(+), 1515 deletions(-) rename new-bench/primes.bril => benchmarks/mem/primitive-root.bril (98%) create mode 100644 benchmarks/mem/primitive-root.out create mode 100644 benchmarks/mem/primitive-root.prof delete mode 100644 new-bench/primes.json diff --git a/new-bench/primes.bril b/benchmarks/mem/primitive-root.bril similarity index 98% rename from new-bench/primes.bril rename to benchmarks/mem/primitive-root.bril index 09e31b1b5..bf9de0e3d 100644 --- a/new-bench/primes.bril +++ b/benchmarks/mem/primitive-root.bril @@ -196,9 +196,9 @@ ret q; } -# -@main() { - p : int = const 1151; +# ARGS: 1151 +@main(p : int) { + zero : int = const 0; one : int = const 1; phi_p : int = call @phi p; count_result : ptr = alloc one; diff --git a/benchmarks/mem/primitive-root.out b/benchmarks/mem/primitive-root.out new file mode 100644 index 000000000..98d9bcb75 --- /dev/null +++ b/benchmarks/mem/primitive-root.out @@ -0,0 +1 @@ +17 diff --git a/benchmarks/mem/primitive-root.prof b/benchmarks/mem/primitive-root.prof new file mode 100644 index 000000000..198c2b3fc --- /dev/null +++ b/benchmarks/mem/primitive-root.prof @@ -0,0 +1 @@ +total_dyn_inst: 11029 diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 4b7ba45ff..a4217f01c 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -37,6 +37,7 @@ The current benchmarks are: * `perfect`: Check if input argument is a perfect number. Returns output as Unix style return code. * `pow`: Computes the n^th power of a given (float) number. * `primes-between`: Print the primes in the interval `[a, b]`. +* `primitive-root`: Computes a [primitive root][primitive_root] modulo a prime number input. * `pythagorean_triple`: Prints all Pythagorean triples with the given c, if such triples exist. An intentionally very naive implementation. * `quadratic`: The [quadratic formula][qf], including a hand-rolled implementation of square root. * `recfact`: Compute *n!* using recursive function calls. @@ -74,3 +75,4 @@ Credit for several of these benchmarks goes to Alexa VanHattum and Gregory Yaune [adler32]: https://en.wikipedia.org/wiki/Adler-32 [uparrow]: https://en.wikipedia.org/wiki/Knuth%27s_up-arrow_notation [riemann]: https://en.wikipedia.org/wiki/Riemann_sum +[primitive_root]: https://en.wikipedia.org/wiki/Primitive_root_modulo_n diff --git a/new-bench/primes.json b/new-bench/primes.json deleted file mode 100644 index a423aa403..000000000 --- a/new-bench/primes.json +++ /dev/null @@ -1,1512 +0,0 @@ -{ - "functions": [ - { - "args": [ - { - "name": "a", - "type": "int" - }, - { - "name": "b", - "type": "int" - } - ], - "instrs": [ - { - "args": [ - "a", - "b" - ], - "dest": "quotient", - "op": "div", - "type": "int" - }, - { - "args": [ - "b", - "quotient" - ], - "dest": "guess", - "op": "mul", - "type": "int" - }, - { - "args": [ - "a", - "guess" - ], - "dest": "rem", - "op": "sub", - "type": "int" - }, - { - "args": [ - "rem" - ], - "op": "ret" - } - ], - "name": "rem", - "type": "int" - }, - { - "args": [ - { - "name": "m", - "type": "int" - }, - { - "name": "n", - "type": "int" - } - ], - "instrs": [ - { - "dest": "zero", - "op": "const", - "type": "int", - "value": 0 - }, - { - "args": [ - "n", - "m" - ], - "dest": "quotient", - "op": "div", - "type": "int" - }, - { - "args": [ - "m", - "quotient" - ], - "dest": "guess", - "op": "mul", - "type": "int" - }, - { - "args": [ - "n", - "guess" - ], - "dest": "rem", - "op": "sub", - "type": "int" - }, - { - "args": [ - "rem", - "zero" - ], - "dest": "res", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "res" - ], - "op": "ret" - } - ], - "name": "divides", - "type": "bool" - }, - { - "args": [ - { - "name": "n", - "type": "int" - }, - { - "name": "ns", - "type": { - "ptr": "int" - } - }, - { - "name": "l", - "type": "int" - } - ], - "instrs": [ - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "l", - "one" - ], - "dest": "new", - "op": "add", - "type": "int" - }, - { - "args": [ - "new" - ], - "dest": "out", - "op": "alloc", - "type": { - "ptr": "int" - } - }, - { - "dest": "i", - "op": "const", - "type": "int", - "value": 0 - }, - { - "args": [ - "out", - "n" - ], - "op": "store" - }, - { - "args": [ - "ns" - ], - "dest": "curr", - "op": "id", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "out", - "one" - ], - "dest": "curr2", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "label": "repeat" - }, - { - "args": [ - "i", - "l" - ], - "dest": "stop", - "op": "lt", - "type": "bool" - }, - { - "args": [ - "stop" - ], - "labels": [ - "next", - "exit" - ], - "op": "br" - }, - { - "label": "next" - }, - { - "args": [ - "curr" - ], - "dest": "tmp", - "op": "load", - "type": "int" - }, - { - "args": [ - "curr2", - "tmp" - ], - "op": "store" - }, - { - "args": [ - "i", - "one" - ], - "dest": "i", - "op": "add", - "type": "int" - }, - { - "args": [ - "curr", - "one" - ], - "dest": "curr", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "curr2", - "one" - ], - "dest": "curr2", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "labels": [ - "repeat" - ], - "op": "jmp" - }, - { - "label": "exit" - }, - { - "args": [ - "ns" - ], - "op": "free" - }, - { - "args": [ - "out" - ], - "op": "ret" - } - ], - "name": "prepend", - "type": { - "ptr": "int" - } - }, - { - "args": [ - { - "name": "n", - "type": "int" - } - ], - "instrs": [ - { - "dest": "guess", - "op": "const", - "type": "int", - "value": 2 - }, - { - "dest": "inc", - "op": "const", - "type": "int", - "value": 1 - }, - { - "label": "continue" - }, - { - "args": [ - "guess", - "guess" - ], - "dest": "square", - "op": "mul", - "type": "int" - }, - { - "args": [ - "square", - "n" - ], - "dest": "continue", - "op": "lt", - "type": "bool" - }, - { - "args": [ - "guess", - "n" - ], - "dest": "works", - "funcs": [ - "divides" - ], - "op": "call", - "type": "bool" - }, - { - "args": [ - "works" - ], - "labels": [ - "yay", - "inc" - ], - "op": "br" - }, - { - "label": "yay" - }, - { - "args": [ - "guess" - ], - "op": "ret" - }, - { - "label": "inc" - }, - { - "args": [ - "guess", - "inc" - ], - "dest": "guess", - "op": "add", - "type": "int" - }, - { - "args": [ - "continue" - ], - "labels": [ - "continue", - "giveup" - ], - "op": "br" - }, - { - "label": "giveup" - }, - { - "args": [ - "n" - ], - "op": "ret" - } - ], - "name": "prime_factor", - "type": "int" - }, - { - "args": [ - { - "name": "n", - "type": "int" - }, - { - "name": "num_factors", - "type": { - "ptr": "int" - } - } - ], - "instrs": [ - { - "dest": "count", - "op": "const", - "type": "int", - "value": 1 - }, - { - "dest": "zero", - "op": "const", - "type": "int", - "value": 0 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "count" - ], - "dest": "ans", - "op": "alloc", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "ans", - "zero" - ], - "op": "store" - }, - { - "label": "continue" - }, - { - "args": [ - "n", - "one" - ], - "dest": "exit", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "exit" - ], - "labels": [ - "exit", - "next" - ], - "op": "br" - }, - { - "label": "next" - }, - { - "args": [ - "n" - ], - "dest": "prime", - "funcs": [ - "prime_factor" - ], - "op": "call", - "type": "int" - }, - { - "label": "repeat" - }, - { - "args": [ - "n", - "prime" - ], - "dest": "n", - "op": "div", - "type": "int" - }, - { - "args": [ - "prime", - "n" - ], - "dest": "divides", - "funcs": [ - "divides" - ], - "op": "call", - "type": "bool" - }, - { - "args": [ - "divides" - ], - "labels": [ - "repeat", - "divided" - ], - "op": "br" - }, - { - "label": "divided" - }, - { - "args": [ - "count", - "one" - ], - "dest": "tmp", - "op": "sub", - "type": "int" - }, - { - "args": [ - "prime", - "ans", - "count" - ], - "dest": "ans", - "funcs": [ - "prepend" - ], - "op": "call", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "count", - "one" - ], - "dest": "count", - "op": "add", - "type": "int" - }, - { - "labels": [ - "continue" - ], - "op": "jmp" - }, - { - "label": "exit" - }, - { - "args": [ - "num_factors", - "count" - ], - "op": "store" - }, - { - "args": [ - "ans" - ], - "op": "ret" - } - ], - "name": "prime_factors", - "type": { - "ptr": "int" - } - }, - { - "args": [ - { - "name": "a", - "type": "int" - }, - { - "name": "k", - "type": "int" - }, - { - "name": "m", - "type": "int" - } - ], - "instrs": [ - { - "dest": "zero", - "op": "const", - "type": "int", - "value": 0 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "dest": "two", - "op": "const", - "type": "int", - "value": 2 - }, - { - "args": [ - "a", - "m" - ], - "dest": "a", - "funcs": [ - "rem" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "zero", - "k" - ], - "dest": "eq_zero", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "eq_zero" - ], - "labels": [ - "exp_zero", - "not_zero" - ], - "op": "br" - }, - { - "label": "exp_zero" - }, - { - "args": [ - "one" - ], - "op": "ret" - }, - { - "label": "not_zero" - }, - { - "args": [ - "one", - "k" - ], - "dest": "eq_one", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "eq_one" - ], - "labels": [ - "exp_one", - "not_one" - ], - "op": "br" - }, - { - "label": "exp_one" - }, - { - "args": [ - "a" - ], - "op": "ret" - }, - { - "label": "not_one" - }, - { - "args": [ - "k", - "two" - ], - "dest": "rem_two", - "funcs": [ - "rem" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "rem_two", - "one" - ], - "dest": "post_mul", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "k", - "two" - ], - "dest": "half_exp", - "op": "div", - "type": "int" - }, - { - "args": [ - "a", - "half_exp", - "m" - ], - "dest": "sqrt", - "funcs": [ - "modexp" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "sqrt", - "sqrt" - ], - "dest": "res", - "op": "mul", - "type": "int" - }, - { - "args": [ - "res", - "m" - ], - "dest": "res", - "funcs": [ - "rem" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "post_mul" - ], - "labels": [ - "post_multiply", - "no_post" - ], - "op": "br" - }, - { - "label": "post_multiply" - }, - { - "args": [ - "res", - "a" - ], - "dest": "res", - "op": "mul", - "type": "int" - }, - { - "args": [ - "res", - "m" - ], - "dest": "res", - "funcs": [ - "rem" - ], - "op": "call", - "type": "int" - }, - { - "label": "no_post" - }, - { - "label": "exit" - }, - { - "args": [ - "res" - ], - "op": "ret" - } - ], - "name": "modexp", - "type": "int" - }, - { - "args": [ - { - "name": "p", - "type": "int" - }, - { - "name": "phi_p", - "type": "int" - }, - { - "name": "factors", - "type": { - "ptr": "int" - } - }, - { - "name": "guess", - "type": "int" - } - ], - "instrs": [ - { - "dest": "count", - "op": "const", - "type": "int", - "value": 0 - }, - { - "dest": "zero", - "op": "const", - "type": "int", - "value": 0 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "factors" - ], - "dest": "ptr", - "op": "id", - "type": { - "ptr": "int" - } - }, - { - "label": "check_power" - }, - { - "args": [ - "ptr" - ], - "dest": "factor", - "op": "load", - "type": "int" - }, - { - "args": [ - "factor", - "zero" - ], - "dest": "stop", - "op": "eq" - }, - { - "args": [ - "stop" - ], - "labels": [ - "ret_true", - "next1" - ], - "op": "br" - }, - { - "label": "next1" - }, - { - "args": [ - "phi_p", - "factor" - ], - "dest": "power", - "op": "div", - "type": "int" - }, - { - "args": [ - "guess", - "power", - "p" - ], - "dest": "exp", - "funcs": [ - "modexp" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "exp", - "one" - ], - "dest": "is_one", - "op": "eq", - "type": "bool" - }, - { - "args": [ - "is_one" - ], - "labels": [ - "ret_false", - "next2" - ], - "op": "br" - }, - { - "label": "next2" - }, - { - "args": [ - "ptr", - "one" - ], - "dest": "ptr", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "count", - "one" - ], - "dest": "count", - "op": "add", - "type": "int" - }, - { - "labels": [ - "check_power" - ], - "op": "jmp" - }, - { - "label": "ret_true" - }, - { - "dest": "t", - "op": "const", - "type": "bool", - "value": true - }, - { - "args": [ - "t" - ], - "op": "ret" - }, - { - "label": "ret_false" - }, - { - "dest": "t", - "op": "const", - "type": "bool", - "value": false - }, - { - "args": [ - "t" - ], - "op": "ret" - } - ], - "name": "check_ord", - "type": "bool" - }, - { - "args": [ - { - "name": "p", - "type": "int" - }, - { - "name": "phi_p", - "type": "int" - }, - { - "name": "factors", - "type": { - "ptr": "int" - } - }, - { - "name": "start", - "type": "int" - } - ], - "instrs": [ - { - "dest": "fallback", - "op": "const", - "type": "int", - "value": -999 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "start" - ], - "dest": "guess", - "op": "id", - "type": "int" - }, - { - "label": "eval" - }, - { - "args": [ - "guess", - "p" - ], - "dest": "too_big", - "op": "ge", - "type": "int" - }, - { - "args": [ - "too_big" - ], - "labels": [ - "done_guess", - "keep_trying" - ], - "op": "br" - }, - { - "label": "keep_trying" - }, - { - "args": [ - "p", - "phi_p", - "factors", - "guess" - ], - "dest": "works", - "funcs": [ - "check_ord" - ], - "op": "call", - "type": "bool" - }, - { - "args": [ - "works" - ], - "labels": [ - "ret", - "inc" - ], - "op": "br" - }, - { - "label": "ret" - }, - { - "args": [ - "guess" - ], - "op": "ret" - }, - { - "label": "inc" - }, - { - "args": [ - "guess", - "one" - ], - "dest": "guess", - "op": "add", - "type": "int" - }, - { - "labels": [ - "eval" - ], - "op": "jmp" - }, - { - "label": "done_guess" - }, - { - "args": [ - "fallback" - ], - "op": "ret" - } - ], - "name": "search_primitive", - "type": "int" - }, - { - "args": [ - { - "name": "p", - "type": "int" - } - ], - "instrs": [ - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "p", - "one" - ], - "dest": "q", - "op": "sub", - "type": "int" - }, - { - "args": [ - "q" - ], - "op": "ret" - } - ], - "name": "phi", - "type": "int" - }, - { - "instrs": [ - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "dest": "zero", - "op": "const", - "type": "int", - "value": 0 - }, - { - "args": [ - "zero", - "one" - ], - "dest": "mone", - "op": "sub", - "type": "int" - }, - { - "dest": "x", - "op": "const", - "type": "int", - "value": 12 - }, - { - "dest": "y", - "op": "const", - "type": "int", - "value": 23 - }, - { - "args": [ - "one" - ], - "dest": "arr", - "op": "alloc", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "arr", - "y" - ], - "op": "store" - }, - { - "args": [ - "x", - "arr", - "one" - ], - "dest": "arr", - "funcs": [ - "prepend" - ], - "op": "call", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "arr" - ], - "dest": "tmp1", - "op": "load", - "type": "int" - }, - { - "args": [ - "arr", - "one" - ], - "dest": "arr", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "arr" - ], - "dest": "tmp2", - "op": "load", - "type": "int" - }, - { - "args": [ - "arr", - "mone" - ], - "dest": "arr", - "op": "ptradd", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "tmp1" - ], - "op": "print" - }, - { - "args": [ - "tmp2" - ], - "op": "print" - }, - { - "args": [ - "arr" - ], - "op": "free" - } - ], - "name": "main_test_prepend" - }, - { - "instrs": [ - { - "dest": "x", - "op": "const", - "type": "int", - "value": 23 - }, - { - "dest": "y", - "op": "const", - "type": "int", - "value": 4 - }, - { - "dest": "n", - "op": "const", - "type": "int", - "value": 50 - }, - { - "args": [ - "x", - "y", - "n" - ], - "dest": "res", - "funcs": [ - "modexp" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "res" - ], - "op": "print" - } - ], - "name": "main2" - }, - { - "instrs": [ - { - "dest": "p", - "op": "const", - "type": "int", - "value": 1151 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "p" - ], - "dest": "phi_p", - "funcs": [ - "phi" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "one" - ], - "dest": "count_result", - "op": "alloc", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "phi_p", - "count_result" - ], - "dest": "prime_factors", - "funcs": [ - "prime_factors" - ], - "op": "call", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "count_result" - ], - "dest": "num_factors", - "op": "load", - "type": "int" - }, - { - "dest": "guess", - "op": "const", - "type": "int", - "value": 121 - }, - { - "args": [ - "p", - "phi_p", - "prime_factors", - "guess" - ], - "dest": "res", - "funcs": [ - "check_ord" - ], - "op": "call", - "type": "bool" - }, - { - "args": [ - "res" - ], - "op": "print" - }, - { - "args": [ - "count_result" - ], - "op": "free" - }, - { - "args": [ - "prime_factors" - ], - "op": "free" - } - ], - "name": "main_test" - }, - { - "instrs": [ - { - "dest": "p", - "op": "const", - "type": "int", - "value": 1151 - }, - { - "dest": "one", - "op": "const", - "type": "int", - "value": 1 - }, - { - "args": [ - "p" - ], - "dest": "phi_p", - "funcs": [ - "phi" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "one" - ], - "dest": "count_result", - "op": "alloc", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "phi_p", - "count_result" - ], - "dest": "prime_factors", - "funcs": [ - "prime_factors" - ], - "op": "call", - "type": { - "ptr": "int" - } - }, - { - "args": [ - "count_result" - ], - "dest": "num_factors", - "op": "load", - "type": "int" - }, - { - "args": [ - "p", - "phi_p", - "prime_factors", - "one" - ], - "dest": "res", - "funcs": [ - "search_primitive" - ], - "op": "call", - "type": "int" - }, - { - "args": [ - "res" - ], - "op": "print" - }, - { - "args": [ - "count_result" - ], - "op": "free" - }, - { - "args": [ - "prime_factors" - ], - "op": "free" - } - ], - "name": "main" - } - ] -} From f41a0965a04b854a258f1c7fcb5f7c0e1782ec0e Mon Sep 17 00:00:00 2001 From: SanjitBasker <64987259+SanjitBasker@users.noreply.github.com> Date: Wed, 30 Aug 2023 20:04:10 -0400 Subject: [PATCH 09/13] cleanup --- benchmarks/mem/primitive-root.bril | 2 -- 1 file changed, 2 deletions(-) diff --git a/benchmarks/mem/primitive-root.bril b/benchmarks/mem/primitive-root.bril index bf9de0e3d..36b71761a 100644 --- a/benchmarks/mem/primitive-root.bril +++ b/benchmarks/mem/primitive-root.bril @@ -45,8 +45,6 @@ guess : int = const 2; inc : int = const 1; - # max : int = const 100; - .continue: square: int = mul guess guess; continue : bool = lt square n; From 2b42e5863202439c37e9995f0a25472538bdf478 Mon Sep 17 00:00:00 2001 From: Kevin Alarcon Negy Date: Wed, 30 Aug 2023 21:03:00 -0400 Subject: [PATCH 10/13] Added dot-product microbenchmark --- benchmarks/core/dot-product.bril | 65 ++++++++++++++++++++++++++++++++ benchmarks/core/dot-product.out | 1 + benchmarks/core/dot-product.prof | 1 + docs/tools/bench.md | 1 + 4 files changed, 68 insertions(+) create mode 100644 benchmarks/core/dot-product.bril create mode 100644 benchmarks/core/dot-product.out create mode 100644 benchmarks/core/dot-product.prof diff --git a/benchmarks/core/dot-product.bril b/benchmarks/core/dot-product.bril new file mode 100644 index 000000000..0f044b989 --- /dev/null +++ b/benchmarks/core/dot-product.bril @@ -0,0 +1,65 @@ +@dot_product(vectorA: ptr, vectorB: ptr, size: int): int { + one: int = const 1; + index: int = const 0; + answer: int = const 0; +.loop: + ptrA: ptr = ptradd vectorA index; + ptrB: ptr = ptradd vectorB index; + valA: int = load ptrA; + valB: int = load ptrB; + tmp: int = mul valA valB; + answer: int = add answer tmp; + index: int = add index one; + cond: bool = lt index size; + br cond .loop .done; +.done: + ret answer; +} + +@main { + a: int = const 25; + b: int = const 50; + c: int = const 100; + d: int = const 150; + e: int = const 250; + f: int = const 2; + g: int = const 10; + h: int = const 20; + i: int = const 30; + j: int = const 40; + one: int = const 1; + zero: int = const 0; + size: int = const 5; + + # Create and fill vectorA + vectorA: ptr = alloc size; + indexPtr: ptr = ptradd vectorA zero; + store indexPtr a; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr b; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr c; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr d; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr e; + + # Create and fill vectorB + vectorB: ptr = alloc size; + indexPtr: ptr = ptradd vectorB zero; + store indexPtr f; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr g; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr h; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr i; + indexPtr: ptr = ptradd indexPtr one; + store indexPtr j; + + val: int = call @dot_product vectorA vectorB size; + print val; + + free vectorA; + free vectorB; +} diff --git a/benchmarks/core/dot-product.out b/benchmarks/core/dot-product.out new file mode 100644 index 000000000..038b87558 --- /dev/null +++ b/benchmarks/core/dot-product.out @@ -0,0 +1 @@ +17050 diff --git a/benchmarks/core/dot-product.prof b/benchmarks/core/dot-product.prof new file mode 100644 index 000000000..1e1f19cef --- /dev/null +++ b/benchmarks/core/dot-product.prof @@ -0,0 +1 @@ +total_dyn_inst: 88 diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 949923543..6a67b2f22 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -21,6 +21,7 @@ The current benchmarks are: * `conjugate-gradient`: Uses conjugate gradients to solve `Ax=b` for any arbitrary positive semidefinite `A`. * `cordic`: Print an approximation of sine(radians) using 8 iterations of the [CORDIC algorithm](https://en.wikipedia.org/wiki/CORDIC). * `digial-root`: Computes the digital root of the input number. +* `dot-product`: Computes the dot product of two vectors. * `eight-queens`: Counts the number of solutions for *n* queens problem, a generalization of [Eight queens puzzle][eight_queens]. * `euclid`: Calculates the greatest common divisor between two large numbers using the [Euclidean Algorithm][euclid] with a helper function for the modulo operator. * `euler`: Approximates [Euler's number][euler] using the Taylor series. From f1b2b2ca34053d5fcb5a3bc2918bfdcddd5dc80a Mon Sep 17 00:00:00 2001 From: SanjitBasker <64987259+SanjitBasker@users.noreply.github.com> Date: Wed, 30 Aug 2023 21:10:38 -0400 Subject: [PATCH 11/13] fix type annotations --- benchmarks/mem/primitive-root.bril | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/mem/primitive-root.bril b/benchmarks/mem/primitive-root.bril index 36b71761a..c8a514e0e 100644 --- a/benchmarks/mem/primitive-root.bril +++ b/benchmarks/mem/primitive-root.bril @@ -137,7 +137,7 @@ .check_power: factor : int = load ptr; - stop = eq factor zero; + stop : bool = eq factor zero; br stop .ret_true .next1; .next1: @@ -168,7 +168,7 @@ guess : int = id start; .eval: - too_big : int = ge guess p; + too_big : bool = ge guess p; br too_big .done_guess .keep_trying; .keep_trying: From 3743131847d5a4e20ad17f5764febaf583334aa3 Mon Sep 17 00:00:00 2001 From: alifarahbakhsh <139010854+alifarahbakhsh@users.noreply.github.com> Date: Thu, 31 Aug 2023 03:20:14 +0000 Subject: [PATCH 12/13] Add .prof --- benchmarks/core/palindrome.prof | 1 + 1 file changed, 1 insertion(+) create mode 100644 benchmarks/core/palindrome.prof diff --git a/benchmarks/core/palindrome.prof b/benchmarks/core/palindrome.prof new file mode 100644 index 000000000..29ad635b8 --- /dev/null +++ b/benchmarks/core/palindrome.prof @@ -0,0 +1 @@ +total_dyn_inst: 298 From 3b0e74fc899e4b73c8370ed58217f3076d212cfb Mon Sep 17 00:00:00 2001 From: Alice Sze Date: Thu, 31 Aug 2023 09:46:11 -0400 Subject: [PATCH 13/13] Added quicksort as a benchmark --- benchmarks/mem/quicksort.bril | 125 ++++++++++++++++++++++++++++++++++ benchmarks/mem/quicksort.out | 6 ++ benchmarks/mem/quicksort.prof | 1 + docs/tools/bench.md | 2 + 4 files changed, 134 insertions(+) create mode 100644 benchmarks/mem/quicksort.bril create mode 100644 benchmarks/mem/quicksort.out create mode 100644 benchmarks/mem/quicksort.prof diff --git a/benchmarks/mem/quicksort.bril b/benchmarks/mem/quicksort.bril new file mode 100644 index 000000000..b7e0f7f15 --- /dev/null +++ b/benchmarks/mem/quicksort.bril @@ -0,0 +1,125 @@ +# An implementation of Quicksort using the Lomuto partition scheme, adapted from the pseudocode on Wikipedia +# Input: an array of length 6 +# Output: the input array sorted in ascending order +# Adopted two helper functions, pack and print_array, from Jiajie Li's bubble sort benchmark + +# ARGS: 94 21 5 6 82 46 +@main(n1: int, n2: int, n3: int, n4: int, n5: int, n6:int) { + size: int = const 6; + array: ptr = call @pack size n1 n2 n3 n4 n5 n6; + one: int = const 1; + size_minus_one: int = sub size one; + + zero: int = const 0; + call @qsort array zero size_minus_one; + + # Print array + call @print_array array size; + + free array; +} + +@qsort(array : ptr, l: int, r:int) { + # if l >= r or r < 0, return + l_ge_r: bool = ge l r; + zero: int = const 0; + neg_r: bool = lt r zero; + ret_cond: bool = or l_ge_r neg_r; + + br ret_cond .done .continue; + + .continue: + p: int = call @partition array l r; + one: int = const 1; + p_minus_one: int = sub p one; + p_plus_one: int = add p one; + + call @qsort array l p_minus_one; + call @qsort array p_plus_one r; + + .done: + ret; +} + +@partition(array : ptr, l: int, r:int) : int { + # choose the last element as the pivot + pivot_loc: ptr = ptradd array r; + pivot: int = load pivot_loc; + one: int = const 1; + i:int = sub l one; + j:int = id i; + + .loop.init: + j:int = add j one; + cond: bool = lt j r; + br cond .body .post.loop; + + .body: + j_loc: ptr = ptradd array j; + a_j: int = load j_loc; + swap_cond: bool = le a_j pivot; + br swap_cond .swap .loop.init; + + .swap: + # increment i by 1 + i: int = add i one; + + # swap the current element with the element at the temporary pivot index i + i_loc: ptr = ptradd array i; + a_i: int = load i_loc; + store j_loc a_i; + store i_loc a_j; + jmp .loop.init; + + .post.loop: + i:int = add i one; + i_loc: ptr = ptradd array i; + a_i: int = load i_loc; + store i_loc pivot; + store pivot_loc a_i; + ret i; +} + +# allocate an array of the given size and pack the input values into the array +@pack(size: int, n1: int, n2: int, n3: int, n4: int, n5: int, n6: int) : ptr { + one: int = const 1; + i: int = const 0; + array: ptr = alloc size; +# Pack data into array manually. Cannot use loop because of the different var name. + loc: ptr = ptradd array i; + store loc n1; + i: int = add i one; + loc: ptr = ptradd array i; + store loc n2; + i: int = add i one; + loc: ptr = ptradd array i; + store loc n3; + i: int = add i one; + loc: ptr = ptradd array i; + store loc n4; + i: int = add i one; + loc: ptr = ptradd array i; + store loc n5; + i: int = add i one; + loc: ptr = ptradd array i; + store loc n6; + + ret array; +} + +@print_array(array: ptr, size: int) { + i: int = const 0; + one: int = const 1; +.loop: + cond: bool = lt i size; + br cond .body .done; +.body: + loc: ptr = ptradd array i; + val: int = load loc; + print val; +.loop_end: + i: int = add i one; + jmp .loop; +.done: + ret; +} \ No newline at end of file diff --git a/benchmarks/mem/quicksort.out b/benchmarks/mem/quicksort.out new file mode 100644 index 000000000..0ab8cac08 --- /dev/null +++ b/benchmarks/mem/quicksort.out @@ -0,0 +1,6 @@ +5 +6 +21 +46 +82 +94 diff --git a/benchmarks/mem/quicksort.prof b/benchmarks/mem/quicksort.prof new file mode 100644 index 000000000..32b1ccbf7 --- /dev/null +++ b/benchmarks/mem/quicksort.prof @@ -0,0 +1 @@ +total_dyn_inst: 264 diff --git a/docs/tools/bench.md b/docs/tools/bench.md index 949923543..bcf45fe0a 100644 --- a/docs/tools/bench.md +++ b/docs/tools/bench.md @@ -45,6 +45,7 @@ The current benchmarks are: * `primes-between`: Print the primes in the interval `[a, b]`. * `pythagorean_triple`: Prints all Pythagorean triples with the given c, if such triples exist. An intentionally very naive implementation. * `quadratic`: The [quadratic formula][qf], including a hand-rolled implementation of square root. +* `quicksort`: [Quicksort using the Lomuto partition scheme][qsort]. * `recfact`: Compute *n!* using recursive function calls. * `rectangles-area-difference`: Output the difference between the areas of rectangles (as a positive value) given their respective side lengths. * `relative-primes`: Print all numbers relatively prime to *n* using [Euclidean algorithm][euclidean_into]. @@ -85,3 +86,4 @@ Credit for several of these benchmarks goes to Alexa VanHattum and Gregory Yaune [mandelbrot]: https://en.wikipedia.org/wiki/Mandelbrot_set [hanoi]: https://en.wikipedia.org/wiki/Tower_of_Hanoi [euler]: https://en.wikipedia.org/wiki/E_(mathematical_constant) +[qsort]: https://en.wikipedia.org/wiki/Quicksort#Lomuto_partition_scheme