diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 076b00a..17aa0d1 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -32,7 +32,7 @@ jobs: - name: Setup typst uses: yusancky/setup-typst@v2 with: - version: 'v0.10.0' + version: 'v0.11.0' - name: Run test suite run: typst-test run \ No newline at end of file diff --git a/examples/fault-tolerant-measurement.typ b/examples/fault-tolerant-measurement.typ index 207fe8b..c5f560f 100644 --- a/examples/fault-tolerant-measurement.typ +++ b/examples/fault-tolerant-measurement.typ @@ -4,6 +4,7 @@ #quantum-circuit( row-spacing: 6pt, + fill-wires: false, lstick($|0〉$), 10pt, group(3, 2, label: (content: "Prepare")), $H$, ctrl(2), 3pt, group(4, 2, label: (content: "Verify")), 3, group(7, 3, label: (content: [Controlled-$M$])), diff --git a/examples/fault-tolerant-toffoli1.typ b/examples/fault-tolerant-toffoli1.typ index ef01844..3444fa2 100644 --- a/examples/fault-tolerant-toffoli1.typ +++ b/examples/fault-tolerant-toffoli1.typ @@ -1,6 +1,7 @@ #import "../src/quill.typ": * #quantum-circuit( + fill-wires: false, lstick($|0〉$), $H$, ctrl(3), 5, $X$, ctrl(2), rstick($|x〉$), [\ ], lstick($|0〉$), $H$, 1, ctrl(3), 3, $X$, 1, ctrl(0), rstick($|y〉$), [\ ], lstick($|0〉$), 3, targ(), 1, $Z$, 2, targ(), rstick($|z plus.circle x y〉$), [\ ], diff --git a/examples/fault-tolerant-toffoli2.typ b/examples/fault-tolerant-toffoli2.typ index 8426f15..325e897 100644 --- a/examples/fault-tolerant-toffoli2.typ +++ b/examples/fault-tolerant-toffoli2.typ @@ -3,6 +3,7 @@ #let group = gategroup.with(stroke: (dash: "dotted", thickness: .5pt)) #quantum-circuit( + fill-wires: false, group(3, 3, padding: (left: 1.5em)), lstick($|0〉$), $H$, ctrl(2), ctrl(3), 3, group(2, 1),ctrl(1), 1, group(3, 1), ctrl(2), $X$, 1, rstick($|x〉$), [\ ], lstick($|0〉$), $H$, ctrl(0), 1, ctrl(3), 2, $Z$, $X$, 2, group(2, 1), diff --git a/examples/phase-estimation.typ b/examples/phase-estimation.typ index b6703a6..ea6e068 100644 --- a/examples/phase-estimation.typ +++ b/examples/phase-estimation.typ @@ -1,7 +1,7 @@ #import "../src/quill.typ": * #quantum-circuit( - setwire(0), lstick(align(center)[First register\ $t$ qubits], n: 4), lstick($|0〉$), + setwire(0), lstick(align(center)[First register\ $t$ qubits], n: 4, pad: 10.5pt), lstick($|0〉$), setwire(1), $H$, 4, midstick($ dots $), ctrl(4), rstick($|0〉$), [\ ], 10pt, setwire(0), phantom(width: 13pt), lstick($|0〉$), setwire(1), $H$, 2, ctrl(3), 1, midstick($ dots $), 1, rstick($|0〉$), [\ ], @@ -9,7 +9,7 @@ midstick($ dots $), 1, rstick($|0〉$), [\ ], setwire(0), 1, lstick($|0〉$), setwire(1), $H$, ctrl(1), 3, midstick($ dots $), 1, rstick($|0〉$), [\ ], - setwire(0), lstick([Second register], n: 1, brace: "{"), lstick($|u〉$), + setwire(0), lstick([Second register], n: 1, brace: "{", pad: 10.5pt), lstick($|u〉$), setwire(4, wire-distance: 1.3pt), 1, $ U^2^0 $, $ U^2^1 $, $ U^2^2 $, 1, midstick($ dots $), $ U^2^(t-1) $, rstick($|u〉$) ) \ No newline at end of file diff --git a/src/decorations.typ b/src/decorations.typ index 2cca7c2..680d143 100644 --- a/src/decorations.typ +++ b/src/decorations.typ @@ -3,8 +3,10 @@ // align: "left" (for rstick) or "right" (for lstick) // brace: auto, none, "{", "}", "|", "[", ... -#let lrstick(content, n, align, brace, label) = gate( +#let lrstick(content, n, align, brace, label, pad: 0pt, x: auto, y: auto) = gate( content, + x: x, + y: y, draw-function: draw-functions.draw-lrstick, size-hint: layout.lrstick-size-hint, box: false, @@ -20,6 +22,7 @@ data: ( brace: brace, align: align, + pad: pad ), label: label ) @@ -34,33 +37,57 @@ /// is shown only if `n > 1`. A brace is always shown when /// explicitly given, e.g., `"}"`, `"["` or `"|"`. No brace is shown for /// `brace: none` +/// - pad (length): Adds a padding between the label and the connected wire to the right. /// - label (array, string, content, dictionary): One or more labels to add to the gate. -/// See @@gate(). . -#let lstick(content, n: 1, brace: auto, label: none) = lrstick(content, n, right, brace, label) +/// See @@gate(). +#let lstick( + content, + n: 1, + brace: auto, + pad: 0pt, + label: none, + x: auto, + y: auto +) = lrstick(content, n, right, brace, label, pad: pad, x: x, y: y) /// Basic command for labelling a wire at the end. /// - content (content): Label to display, e.g., `$|0〉$`. /// - n (content): How many wires the `rstick` should span. +/// - pad (length): Adds a padding between the label and the connected wire to the left. /// - brace (auto, none, string): If `brace` is `auto`, then a default `}` brace /// is shown only if `n > 1`. A brace is always shown when /// explicitly given, e.g., `"}"`, `"["` or `"|"`. No brace is shown for /// `brace: none`. /// - label (array, string, content, dictionary): One or more labels to add to the gate. /// See @@gate(). -#let rstick(content, n: 1, brace: auto, label: none) = lrstick(content, n, left, brace, label) +#let rstick( + content, + n: 1, + brace: auto, + pad: 0pt, + label: none, + x: auto, + y: auto +) = lrstick(content, n, left, brace, label, pad: pad, x: x, y: y) /// Create a midstick, i.e., a mid-circuit text. /// - content (content): Label to display, e.g., `$|0〉$`. /// - label (array, string, content, dictionary): One or more labels to add to the gate. -#let midstick(content, fill: none, label: none) = gate(content, draw-function: draw-functions.draw-unboxed-gate, label: label, fill: fill) +#let midstick( + content, + fill: none, + label: none, + x: auto, + y: auto +) = gate(content, draw-function: draw-functions.draw-unboxed-gate, label: label, fill: fill, x: x, y: y) /// Creates a symbol similar to `\qwbundle` on `quantikz`. Annotates a wire to /// be a bundle of quantum or classical wires. -/// - label (integer, content): -#let nwire(label) = gate([#label], draw-function: draw-functions.draw-nwire, box: false) +/// - label (int, content): +#let nwire(label, x: auto, y: auto) = gate([#label], draw-function: draw-functions.draw-nwire, box: false, x: x, y: y) @@ -69,11 +96,11 @@ /// /// The wire style is reset for each row. /// -/// - wire-count (integer): Number of wires to display. -/// - stroke (none, stroke): When given, the stroke is applied to the wire. +/// - wire-count (int): Number of wires to display. +/// - stroke (auto, none, stroke): When given, the stroke is applied to the wire. /// Otherwise the current stroke is kept. /// - wire-distance (length): Distance between wires. -#let setwire(wire-count, stroke: none, wire-distance: 1pt) = ( +#let setwire(wire-count, stroke: auto, wire-distance: auto) = ( qc-instr: "setwire", wire-count: wire-count, stroke: stroke, @@ -83,8 +110,11 @@ /// Highlight a group of circuit elements by drawing a rectangular box around /// them. /// -/// - wires (integer): Number of wires to include. -/// - steps (integer): Number of columns to include. +/// - wires (int): Number of wires to include. +/// - steps (int): Number of columns to include. +/// - x (auto, int): The starting column of the gategroup. +/// - y (auto, int): The starting wire of the gategroup. +/// - z (string): The gategroup can be placed `"below"` or `"above"` the circuit. /// - padding (length, dictionary): Padding of rectangle. May be one length /// for all sides or a dictionary with the keys `left`, `right`, `top`, /// `bottom` and `default`. Not all keys need to be specified. The value @@ -98,6 +128,9 @@ #let gategroup( wires, steps, + x: auto, + y: auto, + z: "below", padding: 0pt, stroke: .7pt, fill: none, @@ -107,6 +140,9 @@ qc-instr: "gategroup", wires: wires, steps: steps, + x: x, + y: y, + z: z, padding: process-args.process-padding-arg(padding), style: (fill: fill, stroke: stroke, radius: radius), labels: process-args.process-label-arg(label, default-pos: top) @@ -114,17 +150,26 @@ /// Slice the circuit vertically, showing a separation line between columns. /// -/// - n (integer): Number of wires to slice. +/// - n (int): Number of wires to slice. +/// - x (auto, int): The starting column of the slice. +/// - y (auto, int): The starting wire of the slice. +/// - z (string): The slice can be placed `"below"` or `"above"` the circuit. /// - stroke (stroke): Line style for the slice. /// - label (array, string, content, dictionary): One or more labels to add to the /// slice. See @@gate(). #let slice( n: 0, + x: auto, + y: auto, + z: "below", stroke: (paint: red, thickness: .7pt, dash: "dashed"), label: none ) = ( qc-instr: "slice", wires: n, + x: x, + y: y, + z: z, style: (stroke: stroke), labels: process-args.process-label-arg(label, default-pos: top) ) @@ -135,19 +180,24 @@ /// This function is passed the coordinates of the specified cell rows /// and columns. /// -/// - columns (integer, array): Column indices for which to obtain coordinates. -/// - rows (integer, array): Row indices for which to obtain coordinates. +/// - columns (int, array): Column indices for which to obtain coordinates. +/// - rows (int, array): Row indices for which to obtain coordinates. /// - callback (function): Function to call with the obtained coordinates. The /// signature should be with signature `(col-coords, row-coords) => {}`. /// This function is expected to display the content to draw in absolute /// coordinates within the circuit. +/// - z (string): The annotation can be placed `"below"` or `"above"` the circuit. #let annotate( columns, rows, - callback + callback, + z: "below", ) = ( qc-instr: "annotate", rows: rows, + x: none, + y: none, + z: z, columns: columns, callback: callback ) diff --git a/src/draw-functions.typ b/src/draw-functions.typ index f4c1681..ff8ad10 100644 --- a/src/draw-functions.typ +++ b/src/draw-functions.typ @@ -227,7 +227,7 @@ } let brace-size = measure(brace, draw-params.styles) - let width = size.width + brace-size.width + let width = size.width + brace-size.width + gate.data.pad let height = size.height let brace-offset-y let content-offset-y = 0pt @@ -243,8 +243,8 @@ brace-offset-y = -.25em } - let brace-pos-x = if isleftstick { size.width } else { 0pt } - let content-pos-x = if isleftstick { 0pt } else { brace-size.width } + let brace-pos-x = if isleftstick { size.width } else { gate.data.pad } + let content-pos-x = if isleftstick { 0pt } else { width - size.width} box( width: width, diff --git a/src/gates.typ b/src/gates.typ index bd4e6ce..6522ed3 100644 --- a/src/gates.typ +++ b/src/gates.typ @@ -13,6 +13,8 @@ /// //#example(`quill.quantum-circuit(1, quill.gate($H$), 1)`) /// /// - content (content): What to show in the gate (may be none for special gates like @@ctrl() ). +/// - x (auto, int): The column to put the gate in. +/// - y (auto, int): The row to put the gate in. /// - fill (none, color): Gate backgrond fill color. /// - radius (length, dictionary): Gate rectangle border radius. /// Allows the same values as the builtin `rect()` function. @@ -41,6 +43,8 @@ /// `draw-function`. #let gate( content, + x: auto, + y: auto, fill: none, radius: 0pt, width: auto, @@ -54,6 +58,8 @@ label: none ) = ( content: content, + x: x, + y: y, fill: fill, radius: radius, width: width, @@ -72,8 +78,10 @@ /// Basic command for creating multi-qubit or controlled gates. See also @@ctrl() and @@swap(). /// /// - content (content): -/// - n (integer): Number of wires the multi-qubit gate spans. -/// - target (none, integer): If specified, a control wire is drawn from the gate up +/// - n (int): Number of wires the multi-qubit gate spans. +/// - x (auto, int): The column to put the gate in. +/// - y (auto, int): The row to put the gate in. +/// - target (none, int): If specified, a control wire is drawn from the gate up /// or down this many wires counted from the wire this `mqgate()` is placed on. /// - fill (none, color): Gate backgrond fill color. /// - radius (length, dictionary): Gate rectangle border radius. @@ -81,7 +89,7 @@ /// - width (auto, length): The width of the gate can be specified manually with this property. /// - box (boolean): Whether this is a boxed gate (determines whether the /// outgoing wire will be drawn all through the gate (`box: false`) or not). -/// - wire-count (integer): Wire count for control wires. +/// - wire-count (int): Wire count for control wires. /// - inputs (none, array): You can put labels inside the gate to label the input wires with /// this argument. It accepts a list of labels, each of which has to be a dictionary /// with the keys `qubit` (denoting the qubit to label, starting at 0) and `content` @@ -107,6 +115,8 @@ /// `draw-function`. #let mqgate( content, + x: auto, + y: auto, n: 1, target: none, fill: none, @@ -124,6 +134,8 @@ data: none, ) = gate( content, + x: x, + y: y, fill: fill, box: box, width: width, radius: radius, @@ -148,18 +160,27 @@ // SPECIAL GATES /// Draw a meter box representing a measurement. -/// - target (none, integer): If given, draw a control wire to the given target +/// - target (none, int): If given, draw a control wire to the given target /// qubit the specified number of wires up or down. -/// - wire-count (integer): Wire count for the (optional) control wire. -/// - n (integer): Number of wires to span this meter across. +/// - wire-count (int): Wire count for the (optional) control wire. +/// - n (int): Number of wires to span this meter across. /// - label (array, string, content, dictionary): One or more labels to add to the gate. /// See @@gate(). -#let meter(target: none, n: 1, wire-count: 2, label: none, fill: none, radius: 0pt) = { +#let meter( + target: none, + n: 1, + x: auto, + y: auto, + wire-count: 2, + label: none, + fill: none, + radius: 0pt +) = { label = if label != none {(content: label, pos: top, dy: -0.5em)} else { () } if target == none and n == 1 { - gate(none, fill: fill, radius: radius, draw-function: draw-functions.draw-meter, data: (meter-label: label), label: label) + gate(none, x: x, y: y, fill: fill, radius: radius, draw-function: draw-functions.draw-meter, data: (meter-label: label), label: label) } else { - mqgate(none, n: n, target: target, fill: fill, radius: radius, box: true, wire-count: wire-count, draw-function: draw-functions.draw-meter, data: (meter-label: label), label: label) + mqgate(none, x: x, y: y, n: n, target: target, fill: fill, radius: radius, box: true, wire-count: wire-count, draw-function: draw-functions.draw-meter, data: (meter-label: label), label: label) } } @@ -180,7 +201,14 @@ /// - width (length): Width of the permutation gate. /// - bend (ratio): How much to bend the wires. With `0%`, the wires are straight. /// - separation (auto, none, length, color, stroke): Overlapping wires are separated by drawing a thicker line below. With this option, this line can be customized in color or thickness. -#let permute(..qubits, width: 30pt, bend: 100%, separation: auto) = { +#let permute( + ..qubits, + width: 30pt, + bend: 100%, + separation: auto, + x: auto, + y: auto, +) = { if qubits.named().len() != 0 { assert(false, message: "Unexpected named argument `" + qubits.named().keys().first() + "` in function `permute()`") } @@ -208,7 +236,13 @@ /// - fill (none, color, boolean): Fill color for the target circle. If set /// to `true`, the target is filled with the circuits background color. /// - size (length): Size of the target symbol. -#let targ(fill: none, size: 4.3pt, label: none) = gate(none, box: false, draw-function: draw-functions.draw-targ, fill: fill, data: (size: size), label: label) +#let targ( + fill: none, + size: 4.3pt, + label: none, + x: auto, + y: auto, +) = gate(none, x: x, y: y, box: false, draw-function: draw-functions.draw-targ, fill: fill, data: (size: size), label: label) /// Target element for controlled-Z operations (#sym.bullet). /// @@ -220,7 +254,7 @@ /// Target element for #smallcaps("swap") operations (#sym.times) without vertical wire). /// - size (length): Size of the target symbol. -#let targX(size: 7pt, label: none) = gate(none, box: false, draw-function: draw-functions.draw-swap, data: (size: size), label: label) +#let targX(size: 7pt, label: none, x: auto, y: auto) = gate(none, x: x, y: y, box: false, draw-function: draw-functions.draw-swap, data: (size: size), label: label) /// Create a phase gate shown as a point on the wire together with a label. /// @@ -229,8 +263,17 @@ /// - fill (none, color): Fill color for the circle or stroke color if /// `open: true`. /// - size (length): Size of the circle. -#let phase(label, open: false, fill: none, size: 2.3pt) = gate( +#let phase( + label, + open: false, + fill: none, + size: 2.3pt, + x: auto, + y: auto +) = gate( none, + x: x, + y: y, box: false, draw-function: (gate, draw-params) => box( inset: (x: .6em), @@ -245,12 +288,22 @@ /// Creates a #smallcaps("swap") operation with another qubit. /// -/// - n (integer): How many wires up or down the target wire lives. +/// - n (int): How many wires up or down the target wire lives. /// - size (length): Size of the target symbol. /// - wire-label (array, string, content, dictionary): One or more labels /// to add to the control wire. See @@mqgate(). -#let swap(n, wire-count: 1, size: 7pt, label: none, wire-label: none) = mqgate( +#let swap( + n, + wire-count: 1, + size: 7pt, + label: none, + wire-label: none, + x: auto, + y: auto +) = mqgate( none, + x: x, + y: y, target: n, box: false, draw-function: draw-functions.draw-swap, @@ -264,8 +317,8 @@ /// Creates a control with a vertical wire to another qubit. /// -/// - n (integer): How many wires up or down the target wire lives. -/// - wire-count (integer): Wire count for the control wire. +/// - n (int): How many wires up or down the target wire lives. +/// - wire-count (int): Wire count for the control wire. /// - open (boolean): Whether to draw an open dot. /// - fill (none, color): Fill color for the circle or stroke color if /// `open: true`. @@ -283,8 +336,12 @@ show-dot: true, label: none, wire-label: none, + x: auto, + y: auto ) = mqgate( none, + x: x, + y: y, target: n, box: false, draw-function: draw-functions.draw-ctrl, diff --git a/src/layout.typ b/src/layout.typ index 8e9022d..cdc345d 100644 --- a/src/layout.typ +++ b/src/layout.typ @@ -51,8 +51,8 @@ #let default-size-hint(item, draw-params) = { - let func = item.draw-function - let hint = measure(func(item, draw-params), draw-params.styles) + let content = (item.draw-function)(item, draw-params) + let hint = measure(content, draw-params.styles) hint.offset = auto return hint } @@ -61,10 +61,11 @@ -#let lrstick-size-hint(gate, draw-params) = { - let hint = measure((gate.draw-function)(gate, draw-params), draw-params.styles) +#let lrstick-size-hint(item, draw-params) = { + let content = (item.draw-function)(item, draw-params) + let hint = measure(content, draw-params.styles) let dx = 0pt - if gate.data.align == right { dx = hint.width } + if item.data.align == right { dx = hint.width } hint.offset = (x: dx, y: auto) return hint } @@ -105,7 +106,6 @@ return (place(content, dx: dx, dy: dy), bounds) } - let offset = (dx, dy) let placed-labels = place(dx: dx, dy: dy, box({ for label in labels { diff --git a/src/quill.typ b/src/quill.typ index 57273fc..ed30c5c 100644 --- a/src/quill.typ +++ b/src/quill.typ @@ -414,4 +414,7 @@ ) }) -} \ No newline at end of file +} + + +#import "quill2.typ": * \ No newline at end of file diff --git a/src/quill2.typ b/src/quill2.typ new file mode 100644 index 0000000..94ed2d8 --- /dev/null +++ b/src/quill2.typ @@ -0,0 +1,527 @@ +#import "utility.typ" +#import "verifications.typ" +#import "length-helpers.typ" +#import "decorations.typ": * + +#let signum(x) = if x >= 0. { 1. } else { -1. } + + + +/// Create a quantum circuit diagram. Children may be +/// - gates created by one of the many gate commands (@@gate(), +/// @@mqgate(), @@meter(), ...), +/// - `[\ ]` for creating a new wire/row, +/// - commands like @@setwire(), @@slice() or @@gategroup(), +/// - integers for creating cells filled with the current wire setting, +/// - lengths for creating space between rows or columns, +/// - plain content or strings to be placed on the wire, and +/// - @@lstick(), @@midstick() or @@rstick() for placement next to the wire. +/// +/// +/// - wire (stroke): Style for drawing the circuit wires. This can take anything +/// that is valid for the stroke of the builtin `line()` function. +/// - row-spacing (length): Spacing between rows. +/// - column-spacing (length): Spacing between columns. +/// - min-row-height (length): Minimum height of a row (e.g., when no +/// gates are given). +/// - min-column-width (length): Minimum width of a column. +/// - gate-padding (length): General padding setting including the inset for +/// gate boxes and the distance of @@lstick() and co. to the wire. +/// - equal-row-heights (boolean): If true, then all rows will have the same +/// height and the wires will have equal distances orienting on the +/// highest row. +/// - color (color): Foreground color, default for strokes, text, controls +/// etc. If you want to have dark-themed circuits, set this to white +/// for instance and update `wire` and `fill` accordingly. +/// - fill (color): Default fill color for gates. +/// - font-size (length): Default font size for text in the circuit. +/// - scale (ratio): Total scale factor applied to the entire +/// circuit without changing proportions +/// - baseline (length, content, string): Set the baseline for the circuit. If a +/// content or a string is given, the baseline will be adjusted auto- +/// matically to align with the center of it. One useful application is +/// `"="` so the circuit aligns with the equals symbol. +/// - circuit-padding (dictionary): Padding for the circuit (e.g., to accomodate +/// for annotations) in form of a dictionary with possible keys +/// `left`, `right`, `top` and `bottom`. Not all of those need to be +/// specified. +/// +/// This setting basically just changes the size of the bounding box +/// for the circuit and can be used to increase it when labels or +/// annotations extend beyond the actual circuit. +/// - fill-wires (boolean): Whether to automatically fill up all wires until the end. +/// - ..children (array): Items, gates and circuit commands (see description). +#let quantum-circuit( + wire: .7pt + black, + row-spacing: 12pt, + column-spacing: 12pt, + min-row-height: 10pt, + min-column-width: 0pt, + gate-padding: .4em, + equal-row-heights: false, + color: black, + fill: white, + font-size: 10pt, + scale: 100%, + scale-factor: 100%, + baseline: 0pt, + circuit-padding: .4em, + fill-wires: true, + ..children +) = { + if children.pos().len() == 0 { return } + if children.named().len() > 0 { + panic("Unexpected named argument '" + children.named().keys().at(0) + "' for quantum-circuit()") + } + set text(color, size: font-size) + set math.equation(numbering: none) + + style(styles => { + + // Parameter object to pass to draw-function containing current style info + let draw-params = ( + wire: wire, + padding: measure(line(length: gate-padding), styles).width, + background: fill, + color: color, + styles: styles, + x-gate-size: none, + multi: (wire-distance: 0pt), + em: measure(line(length: 1em), styles).width + ) + + draw-params.x-gate-size = layout.default-size-hint(gate($X$), draw-params) + + let items = children.pos().map( x => { + if type(x) in ("content", "string") and x != [\ ] { return gate(x) } + return x + }) + + /////////// First part: Layout (and spacing) /////////// + + let column-spacing = length-helpers.convert-em-length(column-spacing, draw-params.em) + let row-spacing = length-helpers.convert-em-length(row-spacing, draw-params.em) + let min-row-height = length-helpers.convert-em-length(min-row-height, draw-params.em) + let min-column-width = length-helpers.convert-em-length(min-column-width, draw-params.em) + + // All these arrays are gonna be filled up in the loop over `items` + let matrix = ((),) + let row-gutter = (0pt,) + let single-qubit-gates = () + let multi-qubit-gates = () + let meta-instructions = () + + let auto-cell = (empty: true, size: (width: 0pt, height: 0pt), gutter: 0pt) + + let default-wire-style = ( + count: 1, + distance: 1pt, + stroke: wire + ) + let wire-style = default-wire-style + let wire-instructions = () + + let (row, col) = (0, 0) + let prev-col = 0 + let wire-ended = false + + for item in items { + if item == [\ ] { + if fill-wires { + wire-instructions.push((row, prev-col, -1)) + } + row += 1; col = 0; prev-col = 0 + + if row >= matrix.len() { + matrix.push(()) + row-gutter.push(0pt) + } + wire-style = default-wire-style + wire-instructions.push(wire-style) + wire-ended = true + } else if utility.is-circuit-meta-instruction(item) { + if item.qc-instr == "setwire" { + wire-style.count = item.wire-count + + wire-style.distance = utility.if-auto(item.wire-distance, wire-style.distance) + wire-style.stroke = utility.if-auto(utility.update-stroke(wire-style.stroke, item.stroke), wire-style.stroke) + wire-instructions.push(wire-style) + } else { + // Visual meta instructions are handled later + let (x, y) = (item.x, item.y) + if x == auto { x = col } + if y == auto { y = row } + meta-instructions.push((x: x, y: y, item: item)) + } + } else if utility.is-circuit-drawable(item) { + let gate = item + let (x, y) = (gate.x, gate.y) + if x == auto { + x = col + if y == auto { + if col != prev-col { + wire-instructions.push((row, prev-col, col)) + } + prev-col = col + col += 1 + } + } + if y == auto { y = row } + + if y >= matrix.len() { matrix += ((),) * (y - matrix.len() + 1) } + if x >= matrix.at(y).len() { + matrix.at(y) += (auto-cell,) * (x - matrix.at(y).len() + 1) + } + + assert(matrix.at(y).at(x).empty, message: "Attempted to place a second gate at column " + str(x) + ", row " + str(y)) + + let size-hint = utility.get-size-hint(item, draw-params) + let gate-size = size-hint + if item.floating { size-hint.width = 0pt } // floating items don't take width in the layout + + matrix.at(y).at(x) = ( + size: size-hint, + gutter: 0pt, + box: item.box, + empty: false + ) + let gate-info = ( + gate: gate, + size: gate-size, + x: x, + y: y + ) + if gate.multi != none { multi-qubit-gates.push(gate-info) } + else { single-qubit-gates.push(gate-info) } + wire-ended = false + } else if type(item) == int { + wire-instructions.push((row, prev-col, col + item - 1)) + col += item + prev-col = col - 1 + if col >= matrix.at(row).len() { + matrix.at(row) += (auto-cell,) * (col - matrix.at(row).len()) + } + wire-ended = false + } else if type(item) == length { + if wire-ended { + row-gutter.at(row - 1) = calc.max(row-gutter.at(row - 1), item) + } else if col > 0 { + matrix.at(row).at(col - 1).gutter = calc.max(matrix.at(row).at(col - 1).gutter, item) + } + } + } + + // finish up matrix + let num-rows = matrix.len() + let num-cols = calc.max(0, ..matrix.map(array.len)) + if num-rows == 0 or num-cols == 0 { return none } + + + for i in range(num-rows) { + matrix.at(i) += (auto-cell,) * (num-cols - matrix.at(i).len()) + } + row-gutter += (0pt,) * (matrix.len() - row-gutter.len()) + + if fill-wires { + wire-instructions.push((row, prev-col, -1)) // fill current wire + wire-instructions += range(row + 1, num-rows).map(row => (row, 0, -1)) // we may not have visited all wires due to manual placement. Fill all remaining wires. + } + + let vertical-wires = () + // Treat multi-qubit gates (and controlled gates) + // - extract and store all necessary vertical control wires + // - Apply same size-hints to all cells that a mqgate spans (without the control wire). + for gate in multi-qubit-gates { + let (x, y) = gate + let size = matrix.at(y).at(x).size + let multi = gate.gate.multi + + if multi.target != none and multi.target != 0 { + verifications.verify-controlled-gate(gate.gate, x, y, num-rows, num-cols) + + let diff = if multi.target > 0 {multi.num-qubits - 1} else {0} + vertical-wires.push(( + x: x, + y: y + diff, + target: multi.target - diff, + wire-style: (count: multi.wire-count), + labels: multi.wire-label + )) + } + let nq = multi.num-qubits + if nq == 1 { continue } + + verifications.verify-mqgate(gate.gate, x, y, num-rows, num-cols) + + for qubit in range(y, y + nq) { + matrix.at(qubit).at(x).size.width = size.width + } + let start = y + if multi.size-all-wires != none { + if not multi.size-all-wires { + start = calc.max(0, y + nq - 1) + } + for qubit in range(start, y + nq) { + matrix.at(qubit).at(x).size = size + } + } + } + + + let row-heights = matrix.map(row => + calc.max(min-row-height, ..row.map(item => item.size.height)) + row-spacing + ) + if equal-row-heights { + let max-row-height = calc.max(..row-heights) + row-heights = (max-row-height,) * row-heights.len() + } + + let col-widths = range(num-cols).map(j => + calc.max(min-column-width, ..range(num-rows).map(i => { + matrix.at(i).at(j).size.width + })) + column-spacing + ) + + let col-gutter = range(num-cols).map(j => + calc.max(0pt, ..range(num-rows).map(i => { + matrix.at(i).at(j).gutter + })) + ) + + let center-x-coords = layout.compute-center-coords(col-widths, col-gutter).map(x => x - 0.5 * column-spacing) + let center-y-coords = layout.compute-center-coords(row-heights, row-gutter).map(x => x - 0.5 * row-spacing) + draw-params.center-y-coords = center-y-coords + + let circuit-width = col-widths.sum() + col-gutter.slice(0, -1).sum(default: 0pt) - column-spacing + let circuit-height = row-heights.sum() + row-gutter.sum() - row-spacing + + + + /////////// Second part: Generation /////////// + + let bounds = (0pt, 0pt, circuit-width, circuit-height) + + let circuit = block( + width: circuit-width, height: circuit-height, { + set align(top + left) // quantum-circuit could be called in a scope where these have been changed which would mess up everything + + let layer-below-circuit + let layer-above-circuit + for (item, x, y) in meta-instructions { + let (content, decoration-bounds) = (none, none) + if item.qc-instr == "gategroup" { + verifications.verify-gategroup(item, x, y, num-rows, num-cols) + let (dy1, dy2) = layout.get-cell-coords(center-y-coords, row-heights, (y, y + item.wires - 1e-9)) + let (dx1, dx2) = layout.get-cell-coords(center-x-coords, col-widths, (x, x + item.steps - 1e-9)) + (content, decoration-bounds) = draw-functions.draw-gategroup(dx1, dx2, dy1, dy2, item, draw-params) + } else if item.qc-instr == "slice" { + verifications.verify-slice(item, x, y, num-rows, num-cols) + let end = if item.wires == 0 { row-heights.len() } else { y + item.wires } + let (dy1, dy2) = layout.get-cell-coords(center-y-coords, row-heights, (y, end)) + let dx = layout.get-cell-coords(center-x-coords, col-widths, x) + (content, decoration-bounds) = draw-functions.draw-slice(dx, dy1, dy2, item, draw-params) + } else if item.qc-instr == "annotate" { + let rows = layout.get-cell-coords(center-y-coords, row-heights, item.rows) + let cols = layout.get-cell-coords(center-x-coords, col-widths, item.columns) + let annotation = (item.callback)(cols, rows) + verifications.verify-annotation-content(annotation) + if type(annotation) == "dictionary" { + (content, decoration-bounds) = layout.place-with-labels( + annotation.content, + dx: annotation.at("dx", default: 0pt), + dy: annotation.at("dy", default: 0pt), + draw-params: draw-params + ) + } else if type(annotation) in ("content", "string") { + layer-below-circuit += place(annotation) + } + } + if decoration-bounds != none { + bounds = layout.update-bounds(bounds, decoration-bounds, draw-params.em) + } + if item.at("z", default: "below") == "below" { layer-below-circuit += content } + else { layer-above-circuit += content } + } + + layer-below-circuit + + + let get-gate-pos(x, y, size-hint) = { + let dx = center-x-coords.at(x) + let dy = center-y-coords.at(y) + let (width, height) = size-hint + let offset = size-hint.at("offset", default: auto) + + if offset == auto { return (dx - width / 2, dy - height / 2) } + + assert(type(offset) == "dictionary", message: "Unexpected type `" + type(offset) + "` for parameter `offset`") + + let offset-x = offset.at("x", default: auto) + let offset-y = offset.at("y", default: auto) + if offset-x == auto { dx -= width / 2} + else if type(offset-x) == "length" { dx -= offset-x } + if offset-y == auto { dy -= height / 2} + else if type(offset-y) == "length" { dy -= offset-y } + return (dx, dy) + } + + + let get-anchor-width(x, y) = { + if x == num-cols { return 0pt } + let el = matrix.at(y).at(x) + if "box" in el and not el.box { return 0pt } + return el.size.width + } + + let get-anchor-height(x, y) = { + let el = matrix.at(y).at(x) + if "box" in el and not el.box { return 0pt } + return el.size.height + } + + + let wire-style = default-wire-style + for wire-piece in wire-instructions { + if type(wire-piece) == dictionary { + wire-style = wire-piece + } else { + if wire-style.count == 0 { continue } + let (row, start-x, end-x) = wire-piece + + let draw-subwire(x1, x2) = { + let dx1 = center-x-coords.at(x1) + let dx2 = center-x-coords.at(x2, default: circuit-width) + let dy = center-y-coords.at(row) + dx1 += get-anchor-width(x1, row) / 2 + dx2 -= get-anchor-width(x2, row) / 2 + draw-functions.draw-horizontal-wire(dx1, dx2, dy, wire-style.stroke, wire-style.count, wire-distance: wire-style.distance) + } + // Draw wire pieces and take care not to draw through gates. + for x in range(start-x + 1, end-x) { + let anchor-width = get-anchor-width(x, row) + if anchor-width == 0pt { continue } // no gate or `box: false` gate. + draw-subwire(start-x, x) + start-x = x + } + draw-subwire(start-x, end-x) + } + } + + for (x, y, target, wire-style, labels) in vertical-wires { + let dx = center-x-coords.at(x) + let (dy1, dy2) = (center-y-coords.at(y), center-y-coords.at(y + target)) + dy1 += get-anchor-height(x, y) / 2 * signum(target) + dy2 -= get-anchor-height(x, y + target) / 2 * signum(target) + + if labels.len() == 0 { + draw-functions.draw-vertical-wire( + dy1, dy2, dx, + wire, wire-count: wire-style.count, + ) + } else { + let (result, gate-bounds) = draw-functions.draw-vertical-wire-with-labels( + dy1, dy2, dx, + wire, wire-count: wire-style.count, + wire-labels: labels, + draw-params: draw-params + ) + result + bounds = layout.update-bounds(bounds, gate-bounds, draw-params.em) + } + } + + + for gate-info in single-qubit-gates { + let (gate, size, x, y) = gate-info + let (dx, dy) = get-gate-pos(x, y, size) + let content = utility.get-content(gate, draw-params) + + let (result, gate-bounds) = layout.place-with-labels( + content, + size: size, + dx: dx, dy: dy, + labels: gate.labels, draw-params: draw-params + ) + bounds = layout.update-bounds(bounds, gate-bounds, draw-params.em) + result + } + + for gate-info in multi-qubit-gates { + let (gate, size, x, y) = gate-info + let draw-params = draw-params + gate.qubit = y + if gate.multi.num-qubits > 1 { + let dy1 = center-y-coords.at(y + gate.multi.num-qubits - 1) + let dy2 = center-y-coords.at(y) + draw-params.multi.wire-distance = dy1 - dy2 + } + + // lsticks need their offset to be updated again (but don't update the height!) + let content = utility.get-content(gate, draw-params) + let new-size = utility.get-size-hint(gate, draw-params) + size.offset = new-size.offset + size.width = new-size.width + + let (dx, dy) = get-gate-pos(x, y, size) + let (result, gate-bounds) = layout.place-with-labels( + content, + size: if gate.multi != none and gate.multi.num-qubits > 1 {auto} else {size}, + dx: dx, dy: dy, + labels: gate.labels, draw-params: draw-params + ) + bounds = layout.update-bounds(bounds, gate-bounds, draw-params.em) + result + } + + layer-above-circuit + + // show matrix + // for (i, row) in matrix.enumerate() { + // for (j, entry) in row.enumerate() { + // let (dx, dy) = (center-x-coords.at(j), center-y-coords.at(i)) + // place( + // dx: dx - entry.size.width / 2, dy: dy - entry.size.height / 2, + // box(stroke: green, width: entry.size.width, height: entry.size.height) + // ) + // } + // } + + }) // end circuit = block(..., { + + /////////// END Second pass: Generation /////////// + // grace period backwards-compatibility: + let scale = scale + if scale-factor != 100% { scale = scale-factor } + let scale-float = scale / 100% + if circuit-padding != none { + let circuit-padding = process-args.process-padding-arg(circuit-padding) + bounds.at(0) -= circuit-padding.left + bounds.at(1) -= circuit-padding.top + bounds.at(2) += circuit-padding.right + bounds.at(3) += circuit-padding.bottom + } + let final-height = scale-float * (bounds.at(3) - bounds.at(1)) + let final-width = scale-float * (bounds.at(2) - bounds.at(0)) + + let thebaseline = baseline + if type(thebaseline) in ("content", "string") { + thebaseline = height/2 - measure(thebaseline, styles).height/2 + } + if type(thebaseline) == "fraction" { + thebaseline = 100% - layout.get-cell-coords1(center-y-coords, row-heights, thebaseline / 1fr) + bounds.at(1) + } + box(baseline: thebaseline, + width: final-width, + height: final-height, + // stroke: 1pt + gray, + align(left + top, move(dy: -scale-float * bounds.at(1), dx: -scale-float * bounds.at(0), + layout.std-scale( + x: scale, + y: scale, + origin: left + top, + circuit + ))) + ) + +}) +} \ No newline at end of file diff --git a/src/utility.typ b/src/utility.typ index 3012574..4bb4018 100644 --- a/src/utility.typ +++ b/src/utility.typ @@ -1,5 +1,6 @@ #let if-none(a, b) = { if a != none { a } else { b } } +#let if-auto(a, b) = { if a != auto { a } else { b } } #let is-gate(item) = { type(item) == "dictionary" and "gate-type" in item } #let is-circuit-drawable(item) = { is-gate(item) or type(item) in ("string", "content") } #let is-circuit-meta-instruction(item) = { type(item) == "dictionary" and "qc-instr" in item } @@ -10,8 +11,7 @@ #let get-content(item, draw-params) = { if is-gate(item) { if item.draw-function != none { - let func = item.draw-function - return func(item, draw-params) + return (item.draw-function)(item, draw-params) } } else { return item } } @@ -19,8 +19,7 @@ // Get size hint for a gate or plain content item #let get-size-hint(item, draw-params) = { if is-gate(item) { - let func = item.size-hint - return func(item, draw-params) + return (item.size-hint)(item, draw-params) } measure(item, draw-params.styles) } @@ -35,4 +34,23 @@ brace = if alignment == right {"{"} else {"}"} } return $ lr(#brace, size: length) $ -} \ No newline at end of file +} + +/// Updates the first stroke with the second, i.e., returns the second stroke but all +/// fields that are auto are inherited from the first stroke. +/// If the second stroke is none, returns none. +#let update-stroke(stroke1, stroke2) = { + let if-not-auto(a, b) = if b == auto {a} else {b} + if stroke2 == none { return none } + if stroke2 == auto { return stroke1 } + if stroke1 == none { stroke1 = stroke() } + let s1 = stroke(stroke1) + let s2 = stroke(stroke2) + let paint = if-not-auto(s1.paint, s2.paint) + let thickness = if-not-auto(s1.thickness, s2.thickness) + let cap = if-not-auto(s1.cap, s2.cap) + let join = if-not-auto(s1.join, s2.join) + let dash = if-not-auto(s1.dash, s2.dash) + let miter-limit = if-not-auto(s1.miter-limit, s2.miter-limit) + return stroke(paint: paint, thickness: thickness, cap: cap, join: join, dash: dash, miter-limit: miter-limit) +} diff --git a/src/verifications.typ b/src/verifications.typ new file mode 100644 index 0000000..59c27ea --- /dev/null +++ b/src/verifications.typ @@ -0,0 +1,81 @@ +#let plural-s(n) = if n == 1 { "" } else { "s" } + +#let verify-controlled-gate(gate, x, y, circuit-rows, circuit-cols) = { + let multi = gate.multi + if y + multi.target >= circuit-rows or y + multi.target < 0 { + assert(false, message: + "A controlled gate starting at qubit " + str(y) + + " with relative target " + str(multi.target) + + " exceeds the circuit which has only " + str(circuit-rows) + + " qubit" + plural-s(circuit-rows) + ) + } +} + + +#let verify-mqgate(gate, x, y, circuit-rows, circuit-cols) = { + let nq = gate.multi.num-qubits + if y + nq - 1 >= circuit-rows { + assert(false, message: + "A " + str(nq) + "-qubit gate starting at qubit " + + str(y) + " exceeds the circuit which has only " + + str(circuit-rows) + " qubits" + ) + } +} + +#let verify-slice(slice, x, y, circuit-rows, circuit-cols) = { + if slice.wires < 0 { + assert(false, message: "`slice`: The number of wires needs to be > 0 (is " + str(slice.wires) + ")") + } + if y + slice.wires > circuit-rows { + assert(false, message: + "A `slice` starting at qubit " + str(y) + + " spanning " + str(slice.wires) + + " qubit" + plural-s(slice.wires) + + " exceeds the circuit which has only " + + str(circuit-rows) + " qubit" + plural-s(circuit-rows) + ) + } +} + + +#let verify-gategroup(gategroup, x, y, circuit-rows, circuit-cols) = { + if gategroup.wires <= 0 { + assert(false, message: "`gategroup`: The number of wires needs to be > 0 (is " + str(gategroup.wires) + ")") + } + if gategroup.steps <= 0 { + assert(false, message: "`gategroup`: The number of steps needs to be > 0 (is " + str(gategroup.steps) + ")") + } + if y + gategroup.wires > circuit-rows { + assert(false, message: + "A `gategroup` at qubit " + str(y) + + " spanning " + str(gategroup.wires) + + " qubit" + plural-s(gategroup.wires) + + " exceeds the circuit which has only " + + str(circuit-rows) + " qubit" + plural-s(circuit-rows) + ) + } + if x + gategroup.steps > circuit-cols { + assert(false, message: + "A `gategroup` at column " + str(x) + + " spanning " + str(gategroup.steps) + + " column" + plural-s(gategroup.steps) + + " exceeds the circuit which has only " + + str(circuit-cols) + " column" + plural-s(circuit-cols) + ) + } +} + +#let verify-annotation-content(annotation-content) = { + let content-type = type(annotation-content) + assert(content-type in ("content", "string", "dictionary"), message: "`annotate`: Unsupported callback return type `" + str(content-type) + "` (can be `dictionary` or `content`") + + if content-type == "dictionary" { + assert("content" in annotation-content, message: "`annotate`: Missing field `content` in annotation. If the callback returns a dictionary, it must contain the key `content` and may specify coordinates with `dx` and `dy`.") + if "z" in annotation-content { + let z = annotation-content.z + assert(z in ("below", "above"), message: "`annotate`: The parameter `z` can take the values `\"above\"` and `\"below\"`") + } + } +} diff --git a/tests/bell/ref/1.png b/tests/bell/ref/1.png index 701be9b..62a9a03 100644 Binary files a/tests/bell/ref/1.png and b/tests/bell/ref/1.png differ diff --git a/tests/decorations/lstick rstick/ref/1.png b/tests/decorations/lstick rstick/ref/1.png index d0d308a..dac0d4d 100644 Binary files a/tests/decorations/lstick rstick/ref/1.png and b/tests/decorations/lstick rstick/ref/1.png differ diff --git a/tests/decorations/lstick rstick/ref/2.png b/tests/decorations/lstick rstick/ref/2.png index 44f1c66..ff5628d 100644 Binary files a/tests/decorations/lstick rstick/ref/2.png and b/tests/decorations/lstick rstick/ref/2.png differ diff --git a/tests/decorations/lstick rstick/ref/3.png b/tests/decorations/lstick rstick/ref/3.png index 989afb0..59946c7 100644 Binary files a/tests/decorations/lstick rstick/ref/3.png and b/tests/decorations/lstick rstick/ref/3.png differ diff --git a/tests/decorations/lstick rstick/ref/4.png b/tests/decorations/lstick rstick/ref/4.png index d6ef86c..ffbe63c 100644 Binary files a/tests/decorations/lstick rstick/ref/4.png and b/tests/decorations/lstick rstick/ref/4.png differ diff --git a/tests/decorations/lstick rstick/ref/5.png b/tests/decorations/lstick rstick/ref/5.png index 6f98062..639b758 100644 Binary files a/tests/decorations/lstick rstick/ref/5.png and b/tests/decorations/lstick rstick/ref/5.png differ diff --git a/tests/decorations/lstick rstick/ref/6.png b/tests/decorations/lstick rstick/ref/6.png index a603322..d58d11c 100644 Binary files a/tests/decorations/lstick rstick/ref/6.png and b/tests/decorations/lstick rstick/ref/6.png differ diff --git a/tests/decorations/lstick rstick/ref/7.png b/tests/decorations/lstick rstick/ref/7.png new file mode 100644 index 0000000..e10c578 Binary files /dev/null and b/tests/decorations/lstick rstick/ref/7.png differ diff --git a/tests/decorations/lstick rstick/test.typ b/tests/decorations/lstick rstick/test.typ index 40733f1..e9e888f 100644 --- a/tests/decorations/lstick rstick/test.typ +++ b/tests/decorations/lstick rstick/test.typ @@ -45,3 +45,9 @@ #quantum-circuit( lstick($|0〉$, brace: "{"), 1 ) + +#pagebreak() + +#quantum-circuit( + lstick($|0〉$, brace: "{", pad: 10pt), 1, rstick($|0〉$, brace: "}", pad: 10pt) +) diff --git a/tests/examples/fault-tolerant-measurement/ref/1.png b/tests/examples/fault-tolerant-measurement/ref/1.png index 9c88a35..789737e 100644 Binary files a/tests/examples/fault-tolerant-measurement/ref/1.png and b/tests/examples/fault-tolerant-measurement/ref/1.png differ diff --git a/tests/examples/fault-tolerant-toffoli1/ref/1.png b/tests/examples/fault-tolerant-toffoli1/ref/1.png index b935ca0..2ed3209 100644 Binary files a/tests/examples/fault-tolerant-toffoli1/ref/1.png and b/tests/examples/fault-tolerant-toffoli1/ref/1.png differ diff --git a/tests/examples/fault-tolerant-toffoli2/ref/1.png b/tests/examples/fault-tolerant-toffoli2/ref/1.png index 1f0db0b..3758acd 100644 Binary files a/tests/examples/fault-tolerant-toffoli2/ref/1.png and b/tests/examples/fault-tolerant-toffoli2/ref/1.png differ diff --git a/tests/examples/phase-estimation/ref/1.png b/tests/examples/phase-estimation/ref/1.png index 5617c96..7660b99 100644 Binary files a/tests/examples/phase-estimation/ref/1.png and b/tests/examples/phase-estimation/ref/1.png differ diff --git a/tests/examples/qft/ref/1.png b/tests/examples/qft/ref/1.png index 99276dc..5fd21cd 100644 Binary files a/tests/examples/qft/ref/1.png and b/tests/examples/qft/ref/1.png differ diff --git a/tests/examples/shor-nine-qubit-code/ref/1.png b/tests/examples/shor-nine-qubit-code/ref/1.png index aea0cda..f905ecf 100644 Binary files a/tests/examples/shor-nine-qubit-code/ref/1.png and b/tests/examples/shor-nine-qubit-code/ref/1.png differ diff --git a/tests/examples/teleportation/ref/1.png b/tests/examples/teleportation/ref/1.png index e868063..2759a00 100644 Binary files a/tests/examples/teleportation/ref/1.png and b/tests/examples/teleportation/ref/1.png differ diff --git a/tests/gates/custom colors/ref/1.png b/tests/gates/custom colors/ref/1.png index 906ede7..201f411 100644 Binary files a/tests/gates/custom colors/ref/1.png and b/tests/gates/custom colors/ref/1.png differ diff --git a/tests/gates/custom gate/ref/1.png b/tests/gates/custom gate/ref/1.png index 4134a69..d01268c 100644 Binary files a/tests/gates/custom gate/ref/1.png and b/tests/gates/custom gate/ref/1.png differ diff --git a/tests/gates/inputs and outputs/ref/1.png b/tests/gates/inputs and outputs/ref/1.png index 9f9d084..7c30cd4 100644 Binary files a/tests/gates/inputs and outputs/ref/1.png and b/tests/gates/inputs and outputs/ref/1.png differ diff --git a/tests/gates/meter/ref/2.png b/tests/gates/meter/ref/2.png index 4e85abf..98c6199 100644 Binary files a/tests/gates/meter/ref/2.png and b/tests/gates/meter/ref/2.png differ diff --git a/tests/gates/meter/ref/3.png b/tests/gates/meter/ref/3.png index 8e408b0..8501e25 100644 Binary files a/tests/gates/meter/ref/3.png and b/tests/gates/meter/ref/3.png differ diff --git a/tests/gates/meter/test.typ b/tests/gates/meter/test.typ index d5a0cba..4ff37f2 100644 --- a/tests/gates/meter/test.typ +++ b/tests/gates/meter/test.typ @@ -21,5 +21,5 @@ color: red, // scale-factor: 200%, 1, meter(label: $y$), 1, meter(n: 1, label: $lr(|plus.minus〉)$), meter(label: $phi/2$, n: 1, wire-count: 1), meter(target: 1, label: "a"), meter(n: 2, label: "a"), [\ ], - 1, gate($H$), ctrl(0), 2 + 1, gate($H$), 3, ctrl(0), 2 ) \ No newline at end of file diff --git a/tests/gates/nwire/ref/1.png b/tests/gates/nwire/ref/1.png index 32ddb94..7eb48ef 100644 Binary files a/tests/gates/nwire/ref/1.png and b/tests/gates/nwire/ref/1.png differ diff --git a/tests/gates/permute/ref/1.png b/tests/gates/permute/ref/1.png index ca30f1e..bb4ac41 100644 Binary files a/tests/gates/permute/ref/1.png and b/tests/gates/permute/ref/1.png differ diff --git a/tests/labels/ref/1.png b/tests/labels/ref/1.png index d943795..247a9f0 100644 Binary files a/tests/labels/ref/1.png and b/tests/labels/ref/1.png differ diff --git a/tests/labels/ref/2.png b/tests/labels/ref/2.png index 6c6a363..fc0cbf9 100644 Binary files a/tests/labels/ref/2.png and b/tests/labels/ref/2.png differ diff --git a/tests/labels/ref/3.png b/tests/labels/ref/3.png index 8efdf3e..ef132c2 100644 Binary files a/tests/labels/ref/3.png and b/tests/labels/ref/3.png differ diff --git a/tests/labels/ref/4.png b/tests/labels/ref/4.png index 23d652f..0098f1c 100644 Binary files a/tests/labels/ref/4.png and b/tests/labels/ref/4.png differ diff --git a/tests/labels/ref/5.png b/tests/labels/ref/5.png index 2c544a4..541a5c7 100644 Binary files a/tests/labels/ref/5.png and b/tests/labels/ref/5.png differ diff --git a/tests/labels/ref/6.png b/tests/labels/ref/6.png index c030431..abc2289 100644 Binary files a/tests/labels/ref/6.png and b/tests/labels/ref/6.png differ diff --git a/tests/labels/ref/7.png b/tests/labels/ref/7.png index 9ffc806..5c3cde9 100644 Binary files a/tests/labels/ref/7.png and b/tests/labels/ref/7.png differ diff --git a/tests/labels/ref/8.png b/tests/labels/ref/8.png index b803a1f..4cc10cd 100644 Binary files a/tests/labels/ref/8.png and b/tests/labels/ref/8.png differ diff --git a/tests/labels/ref/9.png b/tests/labels/ref/9.png index e07ad58..8963176 100644 Binary files a/tests/labels/ref/9.png and b/tests/labels/ref/9.png differ diff --git a/tests/labels/test.typ b/tests/labels/test.typ index d303f47..e985404 100644 --- a/tests/labels/test.typ +++ b/tests/labels/test.typ @@ -70,5 +70,5 @@ #quantum-circuit( 1, $H$, 1, $H$,[H],$I$, $S$, "H", [\ ], - lstick($|0〉$, label: "System 1"), gate($H$, label: "a"), 1, midstick("mid", label: (content: "r", pos: bottom)), 1, rstick($F$, label: "a") + lstick($|0〉$, label: "System 1"), gate($H$, label: "a"), 1, midstick("mid", label: (content: "r", pos: bottom)), 1, rstick($F$, label: "a"), setwire(0) ) \ No newline at end of file diff --git a/tests/layout/aligned environment/ref/1.png b/tests/layout/aligned environment/ref/1.png index 398b2e9..e8ef33e 100644 Binary files a/tests/layout/aligned environment/ref/1.png and b/tests/layout/aligned environment/ref/1.png differ diff --git a/tests/layout/gutter/ref/1.png b/tests/layout/gutter/ref/1.png index 422dd10..62ed979 100644 Binary files a/tests/layout/gutter/ref/1.png and b/tests/layout/gutter/ref/1.png differ diff --git a/tests/layout/placed items/ref/1.png b/tests/layout/placed items/ref/1.png new file mode 100644 index 0000000..51142e2 Binary files /dev/null and b/tests/layout/placed items/ref/1.png differ diff --git a/tests/layout/placed items/ref/2.png b/tests/layout/placed items/ref/2.png new file mode 100644 index 0000000..4f4dfd7 Binary files /dev/null and b/tests/layout/placed items/ref/2.png differ diff --git a/tests/layout/placed items/ref/3.png b/tests/layout/placed items/ref/3.png new file mode 100644 index 0000000..471c20f Binary files /dev/null and b/tests/layout/placed items/ref/3.png differ diff --git a/tests/layout/placed items/ref/4.png b/tests/layout/placed items/ref/4.png new file mode 100644 index 0000000..a9c7d63 Binary files /dev/null and b/tests/layout/placed items/ref/4.png differ diff --git a/tests/layout/placed items/test.typ b/tests/layout/placed items/test.typ new file mode 100644 index 0000000..0686ac3 --- /dev/null +++ b/tests/layout/placed items/test.typ @@ -0,0 +1,32 @@ +#set page(width: auto, height: auto, margin: 0pt) +#import "/src/quill.typ": * + +#quantum-circuit( + 1, $H$, [\ ], + 1, $H$, [\ ], + 1, $H$, [\ ], + ..range(3).map(i => mqgate($+$, x: i + 2, y: i, n: 2)), + ..range(3).map(i => meter(x: 6, y: i)), + ..range(3).map(i => ctrl(0, x: 7, y: i)), + ..range(3).map(i => lstick($|0〉$, x: 0, y: i)), + gategroup(4, 3, x: 2, y: 0), + slice(y: 1, x: 6, n: 2), +) + +#pagebreak() + +#quantum-circuit( + gate($H$, y: 1), gate($H$, y: 0), 1, $B$, gate($X$, x: 4), [\ ], gate($X$, x:3) +) + +#pagebreak() + +#quantum-circuit( + gate($H$, x: 2), gate($H$, x: 1), $B$, 2, $N$ +) + +#pagebreak() + +#quantum-circuit( + $X$, 20pt, $Y$, slice(y: 0, n: 1), 20pt, $Y$, 20pt, $ß$, 20pt, gategroup(x: 0, y: 0, 1, 4), mqgate("a", n: 1) +) \ No newline at end of file diff --git a/tests/layout/relative for row,col spacing/ref/1.png b/tests/layout/relative for row,col spacing/ref/1.png index c77f753..60fd1ae 100644 Binary files a/tests/layout/relative for row,col spacing/ref/1.png and b/tests/layout/relative for row,col spacing/ref/1.png differ diff --git a/tests/layout/relative for row,col spacing/ref/2.png b/tests/layout/relative for row,col spacing/ref/2.png index 100f01e..a402523 100644 Binary files a/tests/layout/relative for row,col spacing/ref/2.png and b/tests/layout/relative for row,col spacing/ref/2.png differ diff --git a/tests/wire/control wires/ref/1.png b/tests/wire/control wires/ref/1.png index 19e6ab4..fb4030e 100644 Binary files a/tests/wire/control wires/ref/1.png and b/tests/wire/control wires/ref/1.png differ diff --git a/tests/wire/mode/ref/1.png b/tests/wire/mode/ref/1.png index 1e17099..afe3e86 100644 Binary files a/tests/wire/mode/ref/1.png and b/tests/wire/mode/ref/1.png differ diff --git a/tests/wire/mode/ref/2.png b/tests/wire/mode/ref/2.png new file mode 100644 index 0000000..3438563 Binary files /dev/null and b/tests/wire/mode/ref/2.png differ diff --git a/tests/wire/mode/test.typ b/tests/wire/mode/test.typ index 2042a4b..38835bc 100644 --- a/tests/wire/mode/test.typ +++ b/tests/wire/mode/test.typ @@ -7,4 +7,11 @@ 1, setwire(1, stroke: (paint: blue, dash: "dash-dotted", thickness: .7pt, )), 1, setwire(2),1, [\ ], 1, [\ ], 2, setwire(2), 1, setwire(3), 1, setwire(4), 1, setwire(5), 1 +) + +#pagebreak() + + +#quantum-circuit( + 2, setwire(1, stroke: blue), 1, setwire(1, stroke: 1pt), 1, setwire(1, stroke: red), setwire(1, stroke: stroke(dash: "dotted")), 1, setwire(2), 1, setwire(2, wire-distance: 2pt), 1, setwire(2, stroke: stroke(dash: "solid")), 1 ) \ No newline at end of file diff --git a/tests/wire/targ, control, phase/ref/1.png b/tests/wire/targ, control, phase/ref/1.png index 8e6834c..c89936e 100644 Binary files a/tests/wire/targ, control, phase/ref/1.png and b/tests/wire/targ, control, phase/ref/1.png differ