I’m new to Typst, switching from LaTeX, and was wondering whether it’s possible to display elementary row operations like in the image below.
(I used the ‘gauss’ package in LaTeX to make this.)
Thanks for the help!
I didn’t find a package that does this out of the box, but I got something to work with the larrow package:
#import "@preview/larrow:1.2.0": *
#set math.mat(delim: "[")
$
mat(
augment: #3,
gap: #0.8em,
align: #right,
1, 0, -1, 1, 0, 0 #arrow-label(<row1>) ;
0, 1, 2, 0, 1, 0;
2, 1, 0, 0, 0, 1 #arrow-label(<row3>) ;
)
#larw(
<row1>,
<row3>,
bend: ((fx, fy), (tx, ty)) => (
(fx + 15, fy), (fx + 15, ty),
),
from-offset: (0.6em, 0pt),
to-offset: (0.6em, 0pt),
stroke: 0.5pt,
caption: $-2$
)
$
And since rewriting all this boilerplate is tedious, we can write helper functions:
#let mat-counter = counter("mat-counter")
#show math.mat: it => context {
let fields = it.fields()
let rows = fields.remove("rows")
for row in rows {
if not row.last().has("children") {
break
}
if metadata in row.last().children.map(it => it.func()) {
return it
}
}
let rows = rows.enumerate().map(((idx, row)) => {
if row.len() == 0 {
return row
}
let last = row.pop()
let num = numbering("1.1", ..mat-counter.get(), idx)
row + (last + arrow-label(label(num)), )
})
mat-counter.step()
math.mat(
..rows,
..fields,
)
}
#let row-op-arrow(idx1, idx2, amt) = context larw(
label(numbering("1.1", ..mat-counter.get().map(n => n - 1), idx1)),
label(numbering("1.1", ..mat-counter.get().map(n => n - 1), idx2)),
bend: ((fx, fy), (tx, ty)) => (
(fx + 15, fy), (fx + 15, ty),
),
from-offset: (0.6em, 0pt),
to-offset: (0.6em, 0pt),
stroke: 0.5pt,
caption: $amt$,
)
$
mat(
augment: #3,
gap: #0.8em,
align: #right,
1, 0, -1, 1, 0, 0;
0, 1, 2, 0, 1, 0;
2, 1, 0, 0, 0, 1;
)
#row-op-arrow(0, 2, -2)
$
Frankly, your code is so complicated I have trouble understanding it as a beginner to Typst ^^", but the way you turned it all into an easy-to-use row_op_arrow function makes it very user-friendly. Thank you so much!
By copying your code, I was also able to define a new function to represent the row operation of swapping two rows. Here is the code for that in case anyone is interested:
#let row-swap-arrow(idx1, idx2) = context larw(
label(numbering("1.1", ..mat-counter.get().map(n => n - 1), idx1)),
label(numbering("1.1", ..mat-counter.get().map(n => n - 1), idx2)),
bend: ((fx, fy), (tx, ty)) => (
(fx + 15, fy), (fx + 15, ty),
),
from-tip: "straight",
from-offset: (0.6em, 0pt),
to-offset: (0.6em, 0pt),
stroke: 0.5pt
)
$
mat(
augment: #3,
gap: #0.8em,
align: #right,
1, 0, -1, 1, 0, 0;
0, 1, 2, 0, 1, 0;
2, 1, 0, 0, 0, 1;
)
#row-swap-arrow(0, 2)
$
Essentially the show rule adds an arrow-label to each row of the matrix. The reason it’s so complicated is because typst doesn’t allow us to directly modify elements (the matrix), so we have to rebuild it. We also have to deal with recursion (i.e. somehow detect if the matrix is reconstructed or not), because the show rule also matches the reconstructed matrix.
Perhaps it would have been easier to just define a custom auto-label-mat function but oh well ![]()