From dad69f2c98b008b012f44764197d4ec6b4a9f1e0 Mon Sep 17 00:00:00 2001
From: STEVAN Antoine <antoine.stevan@isae-supaero.fr>
Date: Fri, 12 Jul 2024 09:43:13 +0000
Subject: [PATCH] refactor the Nushell modules (dragoon/komodo!158)

this MR is two-fold
- it restructures the two main Nushell modules so that they are easier to read and use
- it improves the "run" and "plot" modules for the benchmarks

## changelog
- `.nushell/` is now renamed to `nu-utils/`
- `benchmarks/` is now a valid Nushell module which exports a bunch of modules
  - `benchmarks linalg`: measure and plot linear algebra operations
  - `benchmarks setup`: measure and plot trusted setup building
  - `benchmarks commit`: measure and plot crafting commitments
  - `benchmarks recoding`: measure and plot the recoding of shards
  - `benchmarks fec`: measure and plot FEC operations, such as encoding and recoding, and allow combining these results with the pure recoding ones
- the submodules of `benchmarks` typically have a `run` and a `plot` command, whith the exception of `benchmarks fec` which has a `run` module and multiple "plot" commands in `benchmarks fec plot`
- the "run" commands will create a random temp file by default and ask for confirmation otherwise if the output file already exists, unless `--force` is used
- snippetds in `benchmarks/README.md` have been updated
---
 .env.nu                                       |   7 +-
 README.md                                     |   2 +-
 benchmarks/.nushell/commit/plot.nu            |  56 --------
 benchmarks/.nushell/commit/run.nu             |  20 ---
 benchmarks/.nushell/fec/run.nu                |  28 ----
 benchmarks/.nushell/recoding/plot.nu          |  31 -----
 benchmarks/.nushell/recoding/run.nu           |  27 ----
 benchmarks/.nushell/setup/run.nu              |  20 ---
 benchmarks/README.md                          | 111 ++++-----------
 benchmarks/mod.nu                             |   5 +
 benchmarks/nu-lib/commit.nu                   | 106 +++++++++++++++
 benchmarks/nu-lib/fec/mod.nu                  |   2 +
 benchmarks/{.nushell => nu-lib}/fec/plot.nu   |  63 ++++++---
 benchmarks/nu-lib/fec/run.nu                  |  54 ++++++++
 benchmarks/nu-lib/linalg.nu                   | 127 ++++++++++++++++++
 benchmarks/nu-lib/recoding.nu                 |  88 ++++++++++++
 .../setup/plot.nu => nu-lib/setup.nu}         |  60 ++++++++-
 examples/cli.nu                               |   2 +-
 komodo.nu                                     |   2 +-
 {.nushell => nu-utils}/binary.nu              |   0
 {.nushell => nu-utils}/cargo.nu               |   0
 {.nushell => nu-utils}/color.nu               |   0
 {.nushell => nu-utils}/error.nu               |   0
 {.nushell => nu-utils}/formats.nu             |   0
 {.nushell => nu-utils}/fs.nu                  |   0
 nu-utils/log.nu                               |   7 +
 {.nushell => nu-utils}/math.nu                |   0
 {.nushell => nu-utils}/mod.nu                 |   1 +
 {.nushell => nu-utils}/parse.nu               |   0
 {.nushell => nu-utils}/plot.nu                |   0
 tests/binary.nu                               |   2 +-
 tests/cli.nu                                  |   2 +-
 tests/color.nu                                |   2 +-
 33 files changed, 526 insertions(+), 299 deletions(-)
 delete mode 100644 benchmarks/.nushell/commit/plot.nu
 delete mode 100644 benchmarks/.nushell/commit/run.nu
 delete mode 100644 benchmarks/.nushell/fec/run.nu
 delete mode 100644 benchmarks/.nushell/recoding/plot.nu
 delete mode 100644 benchmarks/.nushell/recoding/run.nu
 delete mode 100644 benchmarks/.nushell/setup/run.nu
 create mode 100644 benchmarks/mod.nu
 create mode 100644 benchmarks/nu-lib/commit.nu
 create mode 100644 benchmarks/nu-lib/fec/mod.nu
 rename benchmarks/{.nushell => nu-lib}/fec/plot.nu (79%)
 create mode 100644 benchmarks/nu-lib/fec/run.nu
 create mode 100644 benchmarks/nu-lib/linalg.nu
 create mode 100644 benchmarks/nu-lib/recoding.nu
 rename benchmarks/{.nushell/setup/plot.nu => nu-lib/setup.nu} (51%)
 rename {.nushell => nu-utils}/binary.nu (100%)
 rename {.nushell => nu-utils}/cargo.nu (100%)
 rename {.nushell => nu-utils}/color.nu (100%)
 rename {.nushell => nu-utils}/error.nu (100%)
 rename {.nushell => nu-utils}/formats.nu (100%)
 rename {.nushell => nu-utils}/fs.nu (100%)
 create mode 100644 nu-utils/log.nu
 rename {.nushell => nu-utils}/math.nu (100%)
 rename {.nushell => nu-utils}/mod.nu (90%)
 rename {.nushell => nu-utils}/parse.nu (100%)
 rename {.nushell => nu-utils}/plot.nu (100%)

diff --git a/.env.nu b/.env.nu
index cb49bb3a..300f5abf 100644
--- a/.env.nu
+++ b/.env.nu
@@ -1,6 +1,7 @@
 const MODULES = [
-    ".nushell/math.nu",
-    ".nushell/formats.nu",
+    "nu-utils/math.nu",
+    "nu-utils/formats.nu",
+    "benchmarks/",
 ]
 
 def log-load [m: string] {
@@ -11,3 +12,5 @@ log-load $MODULES.0
 use $MODULES.0 *
 log-load $MODULES.1
 use $MODULES.1 *
+log-load $MODULES.2
+use $MODULES.2
diff --git a/README.md b/README.md
index cbbd5afb..010f179d 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ Komodo provides a bunch of other binaries that might be interesting of useful to
 
 The easiest is to use the `cargo.nu` Nushell module as follows
 ```bash
-use .nushell cargo "cargo bin"
+use nu-utils cargo "cargo bin"
 help cargo bin
 ```
 
diff --git a/benchmarks/.nushell/commit/plot.nu b/benchmarks/.nushell/commit/plot.nu
deleted file mode 100644
index 201f7d5d..00000000
--- a/benchmarks/.nushell/commit/plot.nu
+++ /dev/null
@@ -1,56 +0,0 @@
-use ../../../.nushell math *
-use ../../../.nushell fs check-file
-use ../../../.nushell plot [ into-axis-options, COMMON_OPTIONS, gplt ]
-
-export def main [data: path, --save: path] {
-    check-file $data --span (metadata $data).span
-
-    let raw = open $data
-        | where name !~ '^SEC'
-        | ns-to-ms $.times
-        | compute-stats $.times
-        | insert degree { get label | parse "degree {d}" | into record | get d | into int }
-    let graphs = $raw
-        | rename --column { degree: "x", mean: "y", stddev: "e" }
-        | select name x y e
-        | group-by name --to-table
-        | reject items.name
-        | rename --column { group: "name", items: "points" }
-        | insert style.color {|it|
-            match $it.name {
-                "BLS12-381" => "tab:blue"
-                "PALLAS" => "tab:green"
-                "BN254" => "tab:orange"
-                "CP6-782" => "tab:olive"
-                "ED-MNT4-298" => "tab:pink"
-                "MNT4-753" => "tab:red"
-                _ => "tab:grey"
-            }
-        }
-        | insert style.line.marker.shape {|it|
-            match $it.name {
-                "BLS12-381" => "s"
-                "PALLAS" => "o"
-                "BN254" => "^"
-                "CP6-782" => "*"
-                "ED-MNT4-298" => "X"
-                "MNT4-753" => "d"
-                _ => null
-            }
-        }
-        | insert style.line.marker.size { 10 }
-        | sort-by name
-
-    let options = [
-        # --title "time to create trusted setups for certain curves"
-        --x-label '$\log_2 d$'
-        # --y-label "time"
-        ...($graphs.points | flatten | into-axis-options -x "plain" -y "duration")
-        ...$COMMON_OPTIONS
-        (if $save != null { [ --save $save ] })
-        --x-tick-labels ($raw.degree | uniq | math log 2)
-        --x-ticks-rotation 0
-    ]
-
-    gplt plot ($graphs | to json) ...($options | flatten | compact)
-}
diff --git a/benchmarks/.nushell/commit/run.nu b/benchmarks/.nushell/commit/run.nu
deleted file mode 100644
index dca9727f..00000000
--- a/benchmarks/.nushell/commit/run.nu
+++ /dev/null
@@ -1,20 +0,0 @@
-export def main [
-    --output: path = "./commit.ndjson",
-    --nb-measurements: int = 10,
-    --curves: list<string>,
-]: list<int> -> nothing {
-    let input = $in
-
-    if ($input | is-empty) or ($curves | is-empty) {
-        print "nothing to do"
-        return
-    }
-
-    cargo run --release --package benchmarks --bin commit -- ...[
-        --nb-measurements $nb_measurements
-        ...$input
-        --curves ...$curves
-    ] out> $output
-
-    print $"results saved to `($output)`"
-}
diff --git a/benchmarks/.nushell/fec/run.nu b/benchmarks/.nushell/fec/run.nu
deleted file mode 100644
index ceafe8ad..00000000
--- a/benchmarks/.nushell/fec/run.nu
+++ /dev/null
@@ -1,28 +0,0 @@
-use ../../../.nushell formats *
-
-export def main [
-    --output: path = "./fec.ndjson",
-    --nb-measurements: int = 10,
-    --ks: list<int>,
-    --curves: list<string>,
-]: list<int> -> nothing {
-    let input = $in
-
-    if ($ks | is-empty) or ($input | is-empty) or ($curves | is-empty) {
-        print "nothing to do"
-        return
-    }
-
-    "" out> $output
-
-    for k in $ks {
-        cargo run --release --package benchmarks --bin fec -- ...[
-            --nb-measurements $nb_measurements
-            ...$input
-            --encoding vandermonde
-            -k $k
-            -n 1
-            --curves ...$curves
-        ] | from ndnuon | to ndjson out>> $output
-    }
-}
diff --git a/benchmarks/.nushell/recoding/plot.nu b/benchmarks/.nushell/recoding/plot.nu
deleted file mode 100644
index ccc32ec2..00000000
--- a/benchmarks/.nushell/recoding/plot.nu
+++ /dev/null
@@ -1,31 +0,0 @@
-use ../../../.nushell math *
-use ../../../.nushell plot [ into-axis-options, COMMON_OPTIONS ]
-use ../../../.nushell fs check-file
-use ../../../.nushell plot gplt
-
-export def main [data: path, --save: path] {
-    check-file $data --span (metadata $data).span
-
-    let graphs = open $data
-        | ns-to-ms $.times
-        | compute-stats $.times
-        | update label { from nuon }
-        | flatten --all label
-        | where name == "BLS12-381"
-        | rename --column { bytes: "x", mean: "y", stddev: "e" }
-        | select shards x y e
-        | group-by shards --to-table
-        | reject items.shards
-        | rename --column { group: "name", items: "points" }
-        | update name { $"$k = ($in)$"}
-
-    let options = [
-        # --y-label "time (in ms)"
-        ...($graphs.points | flatten | into-axis-options -x "filesize" -y "duration")
-        --no-legend
-        ...$COMMON_OPTIONS
-        (if $save != null { [ --save $save ] })
-    ]
-
-    gplt plot ($graphs | to json) ...($options | flatten | compact)
-}
diff --git a/benchmarks/.nushell/recoding/run.nu b/benchmarks/.nushell/recoding/run.nu
deleted file mode 100644
index 9b42ae72..00000000
--- a/benchmarks/.nushell/recoding/run.nu
+++ /dev/null
@@ -1,27 +0,0 @@
-use ../../../.nushell formats *
-
-export def main [
-    --output: path = "./recoding.ndjson",
-    --nb-measurements: int = 10,
-    --ks: list<int>,
-    --curves: list<string>,
-]: list<int> -> nothing {
-    let input = $in
-
-    if ($ks | is-empty) or ($input | is-empty) or ($curves | is-empty) {
-        print "nothing to do"
-        return
-    }
-
-    "" out> $output
-
-    for k in $ks {
-        cargo run --release --package benchmarks --bin recoding -- ...[
-            --nb-measurements $nb_measurements
-            ...$input
-            --shards $k
-            --ks $k
-            --curves ...$curves
-        ] | from ndnuon | to ndjson out>> $output
-    }
-}
diff --git a/benchmarks/.nushell/setup/run.nu b/benchmarks/.nushell/setup/run.nu
deleted file mode 100644
index 50862c3d..00000000
--- a/benchmarks/.nushell/setup/run.nu
+++ /dev/null
@@ -1,20 +0,0 @@
-export def main [
-    --output: path = "./setup.ndjson",
-    --nb-measurements: int = 10,
-    --curves: list<string>,
-]: list<int> -> nothing {
-    let input = $in
-
-    if ($input | is-empty) or ($curves | is-empty) {
-        print "nothing to do"
-        return
-    }
-
-    cargo run --release --package benchmarks --bin setup -- ...[
-        --nb-measurements $nb_measurements
-        ...$input
-        --curves ...$curves
-    ] out> $output
-
-    print $"results saved to `($output)`"
-}
diff --git a/benchmarks/README.md b/benchmarks/README.md
index a99b6dfe..d9445e8d 100644
--- a/benchmarks/README.md
+++ b/benchmarks/README.md
@@ -39,108 +39,43 @@ gplt multi_bar --title "complex curve group operations" -l "time (in ns)" (
 ## linear algebra
 ```nushell
 let sizes = seq 0 7 | each { 2 ** $in }
-cargo run --release --package benchmarks --bin linalg -- --nb-measurements 10 ...$sizes out> linalg.ndjson
-```
-```nushell
-use .nushell/plot.nu [ "into-axis-options", COMMON_OPTIONS ]
-
-let linalg = open linalg.ndjson
-    | ns-to-ms $.times
-    | compute-stats $.times
-    | update label { parse "{op} {n}"}
-    | flatten --all label
-    | into int n
 
-for graph in [
-    [op, title];
+let out_linalg = $sizes | benchmarks linalg run
 
-    ["inverse", "time to inverse an $n \\times n$ matrix"],
-    ["transpose", "time to transpose an $n \\times n$ matrix"],
-    ["mul", "time to multiply two $n \\times n$ matrices"]
-] {
-    let graphs = $linalg
-            | where op == $graph.op
-            | rename --column { n: "x", mean: "y", stddev: "e" }
-            | group-by name --to-table
-            | rename --column { group: "name", items: "points" }
-            | insert style.color {|it|
-                match $it.name {
-                    "BLS12-381" => "tab:blue"
-                    "PALLAS" => "tab:green"
-                    "BN254" => "tab:orange"
-                    "CP6-782" => "tab:olive"
-                    "ED-MNT4-298" => "tab:pink"
-                    "MNT4-753" => "tab:red"
-                    _ => "tab:grey"
-                }
-            }
-            | insert style.line.marker.shape {|it|
-                match $it.name {
-                    "BLS12-381" => "s"
-                    "PALLAS" => "o"
-                    "BN254" => "^"
-                    "CP6-782" => "*"
-                    "ED-MNT4-298" => "X"
-                    "MNT4-753" => "d"
-                    _ => null
-                }
-            }
-            | insert style.line.marker.size { 10 }
-    gplt plot ...[
-        --title $graph.title
-        --x-label "n"
-        --use-tex
-        ($graphs | to json)
-        ...$COMMON_OPTIONS
-        ...($graphs.points | flatten | into-axis-options -x "plain" -y "duration")
-        --x-ticks-rotation 0
-    ]
-}
+benchmarks linalg plot $out_linalg inverse
 ```
 
-## trusted setup
-```nushell
-use .nushell/setup/run.nu; seq 0 13 | each { 2 ** $in } | run --output setup.ndjson --curves [ bls12381, pallas, bn254 ]
-```
+## trusted setup and commit
 ```nushell
-use ./.nushell/setup/plot.nu; plot setup.ndjson
-```
+let degrees = seq 0 13 | each { 2 ** $in }
+let curves = [ bls12381, pallas, bn254 ]
 
-## commit
-```nushell
-use .nushell/commit/run.nu; seq 0 13 | each { 2 ** $in } | run --output commit.ndjson --curves [bls12381, pallas, bn254 ]
-```
-```nushell
-use ./.nushell/commit/plot.nu; plot commit.ndjson
-```
+let out_setup = $degrees | benchmarks setup run --curves $curves
+let out_commit = $degrees | benchmarks commit run --curves $curves
 
-## end-to-end benchmarks
-### recoding
-```nushell
-use .nushell/recoding/run.nu
-seq 0 18 | each { 512 * 2 ** $in } | run --ks [2, 4, 8, 16] --output recoding.ndjson --curves [ bls12381 ]
-```
-```nushell
-use ./.nushell/recoding/plot.nu; plot recoding.ndjson
+benchmarks setup plot $out_setup
+benchmarks commit plot $out_commit
 ```
 
-### FEC
-```nushell
-use .nushell/fec/run.nu
-seq 0 18 | each { 512 * 2 ** $in } | run --ks [2, 4, 8, 16] --output fec.ndjson --curves [ bls12381 ]
-```
+## end-to-end benchmarks
 ```nushell
-use ./.nushell/fec/plot.nu; plot encoding fec.ndjson
-use ./.nushell/fec/plot.nu; plot decoding fec.ndjson
-use ./.nushell/fec/plot.nu; plot e2e fec.ndjson
+let sizes = seq 0 18 | each { 512 * 2 ** $in }
+let ks = [2, 4, 8, 16]
+let curves = [ bls12381 ]
 ```
 
-## combined graph
+### run
 ```nushell
-use ./.nushell/fec/plot.nu; plot combined fec.ndjson --recoding recoding.ndjson
+let out_recoding = $sizes | benchmarks recoding run --ks $ks --curves $curves
+let out_fec = $sizes | benchmarks fec run --ks $ks --curves $curves
 ```
 
-## ratio graph
+### plot
 ```nushell
-use ./.nushell/fec/plot.nu; plot ratio fec.ndjson --recoding recoding.ndjson
+benchmarks recoding plot $out_recoding
+benchmarks fec plot encoding $out_fec
+benchmarks fec plot decoding $out_fec
+benchmarks fec plot e2e $out_fec
+benchmarks fec plot combined $out_fec --recoding $out_recoding
+benchmarks fec plot ratio $out_fec --recoding $out_recoding
 ```
diff --git a/benchmarks/mod.nu b/benchmarks/mod.nu
new file mode 100644
index 00000000..6ea142d0
--- /dev/null
+++ b/benchmarks/mod.nu
@@ -0,0 +1,5 @@
+export module nu-lib/setup.nu
+export module nu-lib/commit.nu
+export module nu-lib/fec/
+export module nu-lib/recoding.nu
+export module nu-lib/linalg.nu
diff --git a/benchmarks/nu-lib/commit.nu b/benchmarks/nu-lib/commit.nu
new file mode 100644
index 00000000..f43ef527
--- /dev/null
+++ b/benchmarks/nu-lib/commit.nu
@@ -0,0 +1,106 @@
+use ../../nu-utils log
+use ../../nu-utils math *
+use ../../nu-utils fs check-file
+use ../../nu-utils plot [ into-axis-options, COMMON_OPTIONS, gplt ]
+
+use std formats *
+
+# run the "commit" benchmarks
+#
+# - input: the list of polynomial degrees
+# - output: the output path, as NDJSON
+export def run [
+    --output: path, # the output path (defaults to a random file in $nu.temp-path)
+    --curves: list<string>, # the curves to benchmark
+    --force, # does not ask for confirmation if the output file already exists, it will be overwritten
+    --nb-measurements: int = 10, # the number of measurements per benchmark run
+]: list<int> -> path {
+    let input = $in
+
+    if ($input | is-empty) or ($curves | is-empty) {
+        print "nothing to do"
+        return
+    }
+
+    let new_file = $output == null
+    let output = $output | default (mktemp --tmpdir komodo_commit.XXXXXX)
+    let pretty_output = $"(ansi purple)($output)(ansi reset)"
+    if ($output | path exists) and not $new_file {
+        log warning $"($pretty_output) already exists"
+        if not $force {
+            let res = ["no", "yes"] | input list $"Do you want to overwrite ($pretty_output)?"
+            if $res == null or $res == "no" {
+                log info "aborting"
+                return
+            }
+
+        }
+    }
+
+    cargo run --release --package benchmarks --bin commit -- ...[
+        --nb-measurements $nb_measurements
+        ...$input
+        --curves ...$curves
+    ] out> $output
+
+    log info $"results saved to ($pretty_output)"
+    $output
+}
+
+# plot the "commit" benchmark results
+export def plot [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
+    check-file $data --span (metadata $data).span
+
+    let raw = open --raw $data
+        | from ndjson
+        | where name !~ '^SEC'
+        | ns-to-ms $.times
+        | compute-stats $.times
+        | insert degree { get label | parse "degree {d}" | into record | get d | into int }
+    let graphs = $raw
+        | rename --column { degree: "x", mean: "y", stddev: "e" }
+        | select name x y e
+        | group-by name --to-table
+        | reject items.name
+        | rename --column { group: "name", items: "points" }
+        | insert style.color {|it|
+            match $it.name {
+                "BLS12-381" => "tab:blue"
+                "PALLAS" => "tab:green"
+                "BN254" => "tab:orange"
+                "CP6-782" => "tab:olive"
+                "ED-MNT4-298" => "tab:pink"
+                "MNT4-753" => "tab:red"
+                _ => "tab:grey"
+            }
+        }
+        | insert style.line.marker.shape {|it|
+            match $it.name {
+                "BLS12-381" => "s"
+                "PALLAS" => "o"
+                "BN254" => "^"
+                "CP6-782" => "*"
+                "ED-MNT4-298" => "X"
+                "MNT4-753" => "d"
+                _ => null
+            }
+        }
+        | insert style.line.marker.size { 10 }
+        | sort-by name
+
+    let options = [
+        # --title "time to create trusted setups for certain curves"
+        --x-label '$\log_2 d$'
+        # --y-label "time"
+        ...($graphs.points | flatten | into-axis-options -x "plain" -y "duration")
+        ...$COMMON_OPTIONS
+        (if $save != null { [ --save $save ] })
+        --x-tick-labels ($raw.degree | uniq | math log 2)
+        --x-ticks-rotation 0
+    ]
+
+    gplt plot ($graphs | to json) ...($options | flatten | compact)
+}
diff --git a/benchmarks/nu-lib/fec/mod.nu b/benchmarks/nu-lib/fec/mod.nu
new file mode 100644
index 00000000..cb999a34
--- /dev/null
+++ b/benchmarks/nu-lib/fec/mod.nu
@@ -0,0 +1,2 @@
+export module run.nu
+export module plot.nu
diff --git a/benchmarks/.nushell/fec/plot.nu b/benchmarks/nu-lib/fec/plot.nu
similarity index 79%
rename from benchmarks/.nushell/fec/plot.nu
rename to benchmarks/nu-lib/fec/plot.nu
index 56147f24..615fc3a9 100644
--- a/benchmarks/.nushell/fec/plot.nu
+++ b/benchmarks/nu-lib/fec/plot.nu
@@ -1,12 +1,19 @@
-use ../../../.nushell math *
-use ../../../.nushell plot [ into-axis-options, COMMON_OPTIONS ]
-use ../../../.nushell fs check-file
-use ../../../.nushell plot gplt
+use ../../../nu-utils math *
+use ../../../nu-utils plot [ into-axis-options, COMMON_OPTIONS ]
+use ../../../nu-utils fs check-file
+use ../../../nu-utils plot gplt
 
-export def encoding [data: path, --save: path] {
+use std formats *
+
+# plot the "encoding" benchmark results
+export def encoding [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
 
-    let graphs = open $data
+    let graphs = open --raw $data
+        | from ndjson
         | update label { from json }
         | flatten label
         | ns-to-ms times
@@ -30,10 +37,15 @@ export def encoding [data: path, --save: path] {
     gplt plot ($graphs | to json) ...($options | flatten | compact)
 }
 
-export def decoding [data: path, --save: path] {
+# plot the "decoding" benchmark results
+export def decoding [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
 
-    let graphs = open $data
+    let graphs = open --raw $data
+        | from ndjson
         | update label { from json }
         | flatten label
         | ns-to-ms times
@@ -58,10 +70,15 @@ export def decoding [data: path, --save: path] {
     gplt plot ($graphs | to json) ...($options | flatten | compact)
 }
 
-export def e2e [data: path, --save: path] {
+# plot the "end to end" benchmark results, i.e. a $k$-decoding and a $1$-encoding
+export def e2e [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
 
-    let graphs = open $data
+    let graphs = open --raw $data
+        | from ndjson
         | update label { from json }
         | flatten label
         | insert foo { $"($in.name) / ($in.k) / ($in.bytes)" }
@@ -96,11 +113,17 @@ export def e2e [data: path, --save: path] {
     gplt plot ($graphs | to json) ...($options | flatten | compact)
 }
 
-export def combined [data: path, --recoding: path, --save: path] {
+# plot the "combined" benchmark results, i.e. the "end to end" and "recoding" plots on the same figure
+export def combined [
+    data: path, # where to load the "fec" data from
+    --recoding: path,  # where to load the "recoding" data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
     check-file $recoding --span (metadata $recoding).span
 
-    let recoding_graphs = open $recoding
+    let recoding_graphs = open --raw $recoding
+        | from ndjson
         | ns-to-ms $.times
         | compute-stats $.times
         | update label { from nuon }
@@ -124,7 +147,8 @@ export def combined [data: path, --recoding: path, --save: path] {
         | rename --column { group: "name", items: "points" }
         | update name { $"$k = ($in)$" }
 
-    let re_encoding_graphs = open $data
+    let re_encoding_graphs = open --raw $data
+        | from ndjson
         | update label { from json }
         | flatten label
         | insert key { $"($in.name) / ($in.k) / ($in.bytes)" }
@@ -199,11 +223,17 @@ export def combined [data: path, --recoding: path, --save: path] {
     gplt plot ($graphs | to json) ...($options | flatten | compact)
 }
 
-export def ratio [data: path, --recoding: path, --save: path] {
+# plot the "ratio" benchmark results, i.e. the ratio between "end to end" and "recoding"
+export def ratio [
+    data: path, # where to load the "fec" data from
+    --recoding: path,  # where to load the "recoding" data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
     check-file $recoding --span (metadata $recoding).span
 
-    let recoding_graphs = open $recoding
+    let recoding_graphs = open --raw $recoding
+        | from ndjson
         | ns-to-ms times
         | compute-stats $.times
         | update label { from nuon }
@@ -212,7 +242,8 @@ export def ratio [data: path, --recoding: path, --save: path] {
         | select shards bytes mean
         | rename --column { shards: "k" }
 
-    let re_encoding_graphs = open $data
+    let re_encoding_graphs = open --raw $data
+        | from ndjson
         | update label { from json }
         | flatten label
         | insert key { $"($in.name) / ($in.k) / ($in.bytes)" }
diff --git a/benchmarks/nu-lib/fec/run.nu b/benchmarks/nu-lib/fec/run.nu
new file mode 100644
index 00000000..1b600189
--- /dev/null
+++ b/benchmarks/nu-lib/fec/run.nu
@@ -0,0 +1,54 @@
+use ../../../nu-utils log
+use ../../../nu-utils formats *
+
+use std formats *
+
+# run the "fec" benchmarks
+#
+# - input: the list of input file sizes
+# - output: the output path, as NDJSON
+export def main [
+    --output: path, # the output path (defaults to a random file in $nu.temp-path)
+    --ks: list<int>, # the values of $k$ to benchmark
+    --curves: list<string>, # the curves to benchmark
+    --force, # does not ask for confirmation if the output file already exists, it will be overwritten
+    --nb-measurements: int = 10, # the number of measurements per benchmark run
+]: list<int> -> path {
+    let input = $in
+
+    if ($ks | is-empty) or ($input | is-empty) or ($curves | is-empty) {
+        print "nothing to do"
+        return
+    }
+
+    let new_file = $output == null
+    let output = $output | default (mktemp --tmpdir komodo_fec.XXXXXX)
+    let pretty_output = $"(ansi purple)($output)(ansi reset)"
+    if ($output | path exists) and not $new_file {
+        log warning $"($pretty_output) already exists"
+        if not $force {
+            let res = ["no", "yes"] | input list $"Do you want to overwrite ($pretty_output)?"
+            if $res == null or $res == "no" {
+                log info "aborting"
+                return
+            }
+
+        }
+    }
+
+    "" out> $output
+
+    for k in $ks {
+        cargo run --release --package benchmarks --bin fec -- ...[
+            --nb-measurements $nb_measurements
+            ...$input
+            --encoding vandermonde
+            -k $k
+            -n 1
+            --curves ...$curves
+        ] | from ndnuon | to ndjson out>> $output
+    }
+
+    log info $"results saved to ($pretty_output)"
+    $output
+}
diff --git a/benchmarks/nu-lib/linalg.nu b/benchmarks/nu-lib/linalg.nu
new file mode 100644
index 00000000..8699334b
--- /dev/null
+++ b/benchmarks/nu-lib/linalg.nu
@@ -0,0 +1,127 @@
+use ../../nu-utils log
+use ../../nu-utils math *
+use ../../nu-utils fs check-file
+use ../../nu-utils plot [ into-axis-options, COMMON_OPTIONS, gplt ]
+
+use std formats *
+
+# run the "linear algebra" benchmarks
+#
+# - input: the list of matrix sizes
+# - output: the output path, as NDJSON
+export def run [
+    --output: path, # the output path (defaults to a random file in $nu.temp-path)
+    --force, # does not ask for confirmation if the output file already exists, it will be overwritten
+    --nb-measurements: int = 10, # the number of measurements per benchmark run
+]: list<int> -> path {
+    let input = $in
+
+    if ($input | is-empty) {
+        print "nothing to do"
+        return
+    }
+
+    let new_file = $output == null
+    let output = $output | default (mktemp --tmpdir komodo_linalg.XXXXXX)
+    let pretty_output = $"(ansi purple)($output)(ansi reset)"
+    if ($output | path exists) and not $new_file {
+        log warning $"($pretty_output) already exists"
+        if not $force {
+            let res = ["no", "yes"] | input list $"Do you want to overwrite ($pretty_output)?"
+            if $res == null or $res == "no" {
+                log info "aborting"
+                return
+            }
+
+        }
+    }
+
+    cargo run --release --package benchmarks --bin linalg -- ...[
+        --nb-measurements $nb_measurements
+        ...$input
+    ] out> $output
+
+    log info $"results saved to ($pretty_output)"
+    $output
+}
+
+def load-linalg-data [data: path, --span: record<start: int, end: int>]: [ nothing -> table ] {
+    check-file $data --span $span
+
+    open --raw $data
+        | from ndjson
+        | ns-to-ms $.times
+        | compute-stats $.times
+        | update label { parse "{op} {n}"}
+        | flatten --all label
+        | into int n
+}
+
+def linalg-operations []: [ nothing -> list<string> ] {
+    [ "inverse", "transpose", "mul" ]
+}
+
+# plot the "linear algebra" benchmark results
+export def plot [
+    data: path, # where to load the data from
+    op: string@linalg-operations,
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
+    check-file $data --span (metadata $data).span
+    if $op not-in (linalg-operations) {
+        error make {
+            msg: $"(ansi red_bold)invalid_linalg_op(ansi reset)",
+            label: {
+                text: $"invalid linear algebra operation '(ansi yellow)($op)(ansi purple)'(ansi reset)",
+                span: (metadata $op).span,
+            },
+            help: $"please choose one of (ansi cyan)(linalg-operations)(ansi reset)"
+        }
+    }
+
+    let graphs = open --raw $data
+        | from ndjson
+        | ns-to-ms $.times
+        | compute-stats $.times
+        | update label { parse "{op} {n}"}
+        | flatten --all label
+        | into int n
+        | where op == $op
+        | rename --column { n: "x", mean: "y", stddev: "e" }
+        | group-by name --to-table
+        | rename --column { group: "name", items: "points" }
+        | insert style.color {|it|
+            match $it.name {
+                "BLS12-381" => "tab:blue"
+                "PALLAS" => "tab:green"
+                "BN254" => "tab:orange"
+                "CP6-782" => "tab:olive"
+                "ED-MNT4-298" => "tab:pink"
+                "MNT4-753" => "tab:red"
+                _ => "tab:grey"
+            }
+        }
+        | insert style.line.marker.shape {|it|
+            match $it.name {
+                "BLS12-381" => "s"
+                "PALLAS" => "o"
+                "BN254" => "^"
+                "CP6-782" => "*"
+                "ED-MNT4-298" => "X"
+                "MNT4-753" => "d"
+                _ => null
+            }
+        }
+        | insert style.line.marker.size { 10 }
+
+    let options = [
+        --x-label "n"
+        --use-tex
+        ...$COMMON_OPTIONS
+        ...($graphs.points | flatten | into-axis-options -x "plain" -y "duration")
+        (if $save != null { [ --save $save ] })
+        --x-ticks-rotation 0
+    ]
+
+    gplt plot ($graphs | to json) ...($options | flatten | compact)
+}
diff --git a/benchmarks/nu-lib/recoding.nu b/benchmarks/nu-lib/recoding.nu
new file mode 100644
index 00000000..34eca661
--- /dev/null
+++ b/benchmarks/nu-lib/recoding.nu
@@ -0,0 +1,88 @@
+use ../../nu-utils log
+use ../../nu-utils formats *
+use ../../nu-utils math *
+use ../../nu-utils plot [ into-axis-options, COMMON_OPTIONS, gplt ]
+use ../../nu-utils fs check-file
+
+use std formats *
+
+# run the "recoding" benchmarks
+#
+# - input: the list of input file sizes
+# - output: the output path, as NDJSON
+export def run [
+    --output: path, # the output path (defaults to a random file in $nu.temp-path)
+    --ks: list<int>, # the values of $k$ to benchmark
+    --curves: list<string>, # the curves to benchmark
+    --force, # does not ask for confirmation if the output file already exists, it will be overwritten
+    --nb-measurements: int = 10, # the number of measurements per benchmark run
+]: list<int> -> path {
+    let input = $in
+
+    if ($ks | is-empty) or ($input | is-empty) or ($curves | is-empty) {
+        print "nothing to do"
+        return
+    }
+
+    let new_file = $output == null
+    let output = $output | default (mktemp --tmpdir komodo_recoding.XXXXXX)
+    let pretty_output = $"(ansi purple)($output)(ansi reset)"
+    if ($output | path exists) and not $new_file {
+        log warning $"($pretty_output) already exists"
+        if not $force {
+            let res = ["no", "yes"] | input list $"Do you want to overwrite ($pretty_output)?"
+            if $res == null or $res == "no" {
+                log info "aborting"
+                return
+            }
+
+        }
+    }
+
+    "" out> $output
+
+    for k in $ks {
+        cargo run --release --package benchmarks --bin recoding -- ...[
+            --nb-measurements $nb_measurements
+            ...$input
+            --shards $k
+            --ks $k
+            --curves ...$curves
+        ] | from ndnuon | to ndjson out>> $output
+    }
+
+    log info $"results saved to ($pretty_output)"
+    $output
+}
+
+# plot the "recoding" benchmark results
+export def plot [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
+    check-file $data --span (metadata $data).span
+
+    let graphs = open --raw $data
+        | from ndjson
+        | ns-to-ms $.times
+        | compute-stats $.times
+        | update label { from nuon }
+        | flatten --all label
+        | where name == "BLS12-381"
+        | rename --column { bytes: "x", mean: "y", stddev: "e" }
+        | select shards x y e
+        | group-by shards --to-table
+        | reject items.shards
+        | rename --column { group: "name", items: "points" }
+        | update name { $"$k = ($in)$"}
+
+    let options = [
+        # --y-label "time (in ms)"
+        ...($graphs.points | flatten | into-axis-options -x "filesize" -y "duration")
+        --no-legend
+        ...$COMMON_OPTIONS
+        (if $save != null { [ --save $save ] })
+    ]
+
+    gplt plot ($graphs | to json) ...($options | flatten | compact)
+}
diff --git a/benchmarks/.nushell/setup/plot.nu b/benchmarks/nu-lib/setup.nu
similarity index 51%
rename from benchmarks/.nushell/setup/plot.nu
rename to benchmarks/nu-lib/setup.nu
index 351ea18d..0cf90357 100644
--- a/benchmarks/.nushell/setup/plot.nu
+++ b/benchmarks/nu-lib/setup.nu
@@ -1,11 +1,61 @@
-use ../../../.nushell math *
-use ../../../.nushell fs check-file
-use ../../../.nushell plot [ into-axis-options, COMMON_OPTIONS, gplt ]
+use ../../nu-utils log
+use ../../nu-utils math *
+use ../../nu-utils fs check-file
+use ../../nu-utils plot [ into-axis-options, COMMON_OPTIONS, gplt ]
 
-export def main [data: path, --save: path] {
+use std formats *
+
+# run the "trusted setup" benchmarks
+#
+# - input: the list of polynomial degrees
+# - output: the output path, as NDJSON
+export def run [
+    --output: path, # the output path (defaults to a random file in $nu.temp-path)
+    --curves: list<string>, # the curves to benchmark
+    --force, # does not ask for confirmation if the output file already exists, it will be overwritten
+    --nb-measurements: int = 10, # the number of measurements per benchmark run
+]: list<int> -> path {
+    let input = $in
+
+    if ($input | is-empty) or ($curves | is-empty) {
+        print "nothing to do"
+        return
+    }
+
+    let new_file = $output == null
+    let output = $output | default (mktemp --tmpdir komodo_setup.XXXXXX)
+    let pretty_output = $"(ansi purple)($output)(ansi reset)"
+    if ($output | path exists) and not $new_file {
+        log warning $"($pretty_output) already exists"
+        if not $force {
+            let res = ["no", "yes"] | input list $"Do you want to overwrite ($pretty_output)?"
+            if $res == null or $res == "no" {
+                log info "aborting"
+                return
+            }
+
+        }
+    }
+
+    cargo run --release --package benchmarks --bin setup -- ...[
+        --nb-measurements $nb_measurements
+        ...$input
+        --curves ...$curves
+    ] out> $output
+
+    log info $"results saved to ($pretty_output)"
+    $output
+}
+
+# plot the "trusted setup" benchmark results
+export def plot [
+    data: path, # where to load the data from
+    --save: path, # an optional path where to save the figure (defaults to showing the figure interactively)
+] {
     check-file $data --span (metadata $data).span
 
-    let raw = open $data
+    let raw = open --raw $data
+        | from ndjson
         | ns-to-ms times
         | compute-stats times
         | insert degree { get label | parse "degree {d}" | into record | get d | into int }
diff --git a/examples/cli.nu b/examples/cli.nu
index 12b75025..e7765693 100755
--- a/examples/cli.nu
+++ b/examples/cli.nu
@@ -7,7 +7,7 @@ use ../komodo.nu [
     "komodo reconstruct",
     "komodo ls",
 ]
-use ../.nushell binary [ "bytes from_int" ]
+use ../nu-utils binary [ "bytes from_int" ]
 
 use std assert
 
diff --git a/komodo.nu b/komodo.nu
index c23b7929..d1ca5d81 100644
--- a/komodo.nu
+++ b/komodo.nu
@@ -2,7 +2,7 @@
 #
 # please run `komodo --help` or `komodo <tab>` to have a look at more information
 
-use .nushell binary ["bytes from_int"]
+use nu-utils binary ["bytes from_int"]
 
 const KOMODO_BINARY = "./target/release/komodo"
 const DEFAULT_LOG_LEVEL = "INFO"
diff --git a/.nushell/binary.nu b/nu-utils/binary.nu
similarity index 100%
rename from .nushell/binary.nu
rename to nu-utils/binary.nu
diff --git a/.nushell/cargo.nu b/nu-utils/cargo.nu
similarity index 100%
rename from .nushell/cargo.nu
rename to nu-utils/cargo.nu
diff --git a/.nushell/color.nu b/nu-utils/color.nu
similarity index 100%
rename from .nushell/color.nu
rename to nu-utils/color.nu
diff --git a/.nushell/error.nu b/nu-utils/error.nu
similarity index 100%
rename from .nushell/error.nu
rename to nu-utils/error.nu
diff --git a/.nushell/formats.nu b/nu-utils/formats.nu
similarity index 100%
rename from .nushell/formats.nu
rename to nu-utils/formats.nu
diff --git a/.nushell/fs.nu b/nu-utils/fs.nu
similarity index 100%
rename from .nushell/fs.nu
rename to nu-utils/fs.nu
diff --git a/nu-utils/log.nu b/nu-utils/log.nu
new file mode 100644
index 00000000..0a7ee150
--- /dev/null
+++ b/nu-utils/log.nu
@@ -0,0 +1,7 @@
+export def info [msg: string] {
+    print $"[(ansi green_bold)INFO(ansi reset)] ($msg)"
+}
+
+export def warning [msg: string] {
+    print $"[(ansi yellow_bold)WARNING(ansi reset)] ($msg)"
+}
diff --git a/.nushell/math.nu b/nu-utils/math.nu
similarity index 100%
rename from .nushell/math.nu
rename to nu-utils/math.nu
diff --git a/.nushell/mod.nu b/nu-utils/mod.nu
similarity index 90%
rename from .nushell/mod.nu
rename to nu-utils/mod.nu
index c6e1c6a9..69f677bf 100644
--- a/.nushell/mod.nu
+++ b/nu-utils/mod.nu
@@ -7,3 +7,4 @@ export module fs.nu
 export module math.nu
 export module parse.nu
 export module plot.nu
+export module log.nu
diff --git a/.nushell/parse.nu b/nu-utils/parse.nu
similarity index 100%
rename from .nushell/parse.nu
rename to nu-utils/parse.nu
diff --git a/.nushell/plot.nu b/nu-utils/plot.nu
similarity index 100%
rename from .nushell/plot.nu
rename to nu-utils/plot.nu
diff --git a/tests/binary.nu b/tests/binary.nu
index 21a5a736..def39bc4 100644
--- a/tests/binary.nu
+++ b/tests/binary.nu
@@ -1,4 +1,4 @@
-use ../.nushell binary [ "bytes from_int", "bytes to_int" ]
+use ../nu-utils binary [ "bytes from_int", "bytes to_int" ]
 
 use std assert
 
diff --git a/tests/cli.nu b/tests/cli.nu
index fd149dff..269baf3c 100644
--- a/tests/cli.nu
+++ b/tests/cli.nu
@@ -7,7 +7,7 @@ use ../komodo.nu [
     "komodo ls",
     "komodo clean",
 ]
-use ../.nushell binary [ "bytes from_int" ]
+use ../nu-utils binary [ "bytes from_int" ]
 
 use std assert
 
diff --git a/tests/color.nu b/tests/color.nu
index 27609447..1c1c119f 100644
--- a/tests/color.nu
+++ b/tests/color.nu
@@ -1,4 +1,4 @@
-use ../.nushell color [
+use ../nu-utils color [
     "color from-floats",
     "color from-ints",
     "color from-string",
-- 
GitLab