Skip to content

Commit

Permalink
Long gate in ASCII art circuits - lengthen column width when necessary (
Browse files Browse the repository at this point in the history
#2126)

See issue #1476.

I tried to keep the logic as close as possible to the original, because
I wanted to keep it easy to review it in relation to the old logic.

The main change here is that instead of having the `ObjectsByColumn` of
every Row be a `FxHashMap<usize, String>` which contains the
7-width-wide strings, it's now a `FxHashMap<usize, CircuitObject>`,
where `CircuitObject` is an enum that supports every circuit object
except for than blanks and wires (because those are inserted later on,
on-the-go).

Using this enum allows us to calculate the required
`ColumnWidthsByColumn` (a `FxHashMap<usize, usize>`) right before
calling `row.fmt` - so we know what width the `CircuitObjects` need to
be when converted into strings.

In the example from the ticket, this means that this circuit:
```
use q3 = Qubit();

H(q3);
Rx(1.0, q3);
H(q3);
Rx(1.0, q3);
H(q3);
Rx(1.0, q3);
```

Which used to give:
```
q_0    ── H ─────────── ● ──── M ────────────────
                        │      ╘═════════════════
q_1    ── H ──── X ──── X ───────────────────────
q_2     rx(1.0000)  rx(1.0000) ────────────────────────────
q_3    ── H ── rx(1.0000) ── H ── rx(1.0000) ── H ── rx(1.0000)
```

Now gives
```
q_0    ────── H ─────────────────────── ● ──────── M ────────────────────────────
                                        │          ╘═════════════════════════════
q_1    ────── H ──────────── X ──────── X ───────────────────────────────────────
q_2    ─ rx(1.0000) ─── rx(1.0000) ──────────────────────────────────────────────
q_3    ────── H ─────── rx(1.0000) ──── H ─── rx(1.0000) ──── H ─── rx(1.0000) ──
```


Apart from this desired change for long gates, the only notable
difference is that, where ket-zero (`|0〉`) used to show as a width-5
circuit object (`─ |0〉 ─`, it now shows as a width-7 circuit object (`──
|0〉 ──`) - you can see the difference in every test that used it.
  • Loading branch information
Morcifer authored Jan 29, 2025
1 parent 39aa42b commit 6ce7372
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 96 deletions.
133 changes: 93 additions & 40 deletions compiler/qsc/src/interpret/circuit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,8 @@ fn rotation_gate() {
.circuit(CircuitEntryPoint::EntryPoint, false)
.expect("circuit generation should succeed");

// The wire isn't visible here since the gate label is longer
// than the static column width, but we can live with it.
expect![[r"
q_0 rx(1.5708)
q_0 rx(1.5708) ──
"]]
.assert_eq(&circ.to_string());
}
Expand Down Expand Up @@ -262,8 +260,8 @@ fn mresetz_unrestricted_profile() {
.expect("circuit generation should succeed");

expect![[r"
q_0 ── H ──── M ─── |0〉 ─
╘══════════
q_0 ── H ──── M ─── |0〉
╘════════════
"]]
.assert_eq(&circ.to_string());
}
Expand Down Expand Up @@ -349,10 +347,10 @@ fn unrestricted_profile_result_comparison() {
.expect("circuit generation should succeed");

expect![[r"
q_0 ── H ──── M ──── X ─── |0〉 ─
╘═════════════════
q_1 ── H ──── M ─── |0〉 ────────
╘═════════════════
q_0 ── H ──── M ──── X ───── |0〉
╘═════════════════════
q_1 ── H ──── M ─── |0〉 ───────────
╘═════════════════════
"]]
.assert_eq(&circ.to_string());

Expand All @@ -366,10 +364,10 @@ fn unrestricted_profile_result_comparison() {

let circuit = interpreter.get_circuit();
expect![[r"
q_0 ── H ──── M ──── X ─── |0〉 ─
╘═════════════════
q_1 ── H ──── M ─── |0〉 ────────
╘═════════════════
q_0 ── H ──── M ──── X ───── |0〉
╘═════════════════════
q_1 ── H ──── M ─── |0〉 ───────────
╘═════════════════════
"]]
.assert_eq(&circuit.to_string());
}
Expand Down Expand Up @@ -456,10 +454,8 @@ fn custom_intrinsic_one_classical_arg() {
.circuit(CircuitEntryPoint::EntryPoint, false)
.expect("circuit generation should succeed");

// A custom intrinsic that doesn't take qubits just doesn't
// show up on the circuit.
expect![[r"
q_0 ── X ── foo(4)
q_0 ── X ── foo(4) ──
"]]
.assert_eq(&circ.to_string());
}
Expand Down Expand Up @@ -497,16 +493,16 @@ fn custom_intrinsic_mixed_args() {
// This is one gate that spans ten target wires, even though the
// text visualization doesn't convey that clearly.
expect![[r"
q_0 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_1 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_2 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_3 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_4 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_5 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_6 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_7 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_8 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_9 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1)
q_0 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_1 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_2 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_3 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_4 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_5 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_6 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_7 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_8 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
q_9 AccountForEstimatesInternal([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)], 1) ──
"]]
.assert_eq(&circ.to_string());

Expand Down Expand Up @@ -536,7 +532,7 @@ fn custom_intrinsic_apply_idle_noise() {
// ConfigurePauliNoise has no qubit arguments so it shouldn't show up.
// ApplyIdleNoise is a quantum operation so it shows up.
expect![[r#"
q_0 ApplyIdleNoise
q_0 ApplyIdleNoise ──
"#]]
.assert_eq(&circ.to_string());
}
Expand Down Expand Up @@ -834,6 +830,63 @@ fn operation_with_non_qubit_args() {
.assert_debug_eq(&circ_err);
}

#[test]
fn operation_with_long_gates_properly_aligned() {
let mut interpreter = interpreter(
r"
namespace Test {
import Std.Measurement.*;
@EntryPoint()
operation Main() : Result[] {
use q0 = Qubit();
use q1 = Qubit();
H(q0);
H(q1);
X(q1);
Ry(1.0, q1);
CNOT(q0, q1);
M(q0);
use q2 = Qubit();
H(q2);
Rx(1.0, q2);
H(q2);
Rx(1.0, q2);
H(q2);
Rx(1.0, q2);
use q3 = Qubit();
Rxx(1.0, q1, q3);
CNOT(q0, q3);
[M(q1), M(q3)]
}
}
",
Profile::Unrestricted,
);

let circ = interpreter
.circuit(CircuitEntryPoint::EntryPoint, false)
.expect("circuit generation should succeed");

expect![[r#"
q_0 ── H ────────────────────────────────────── ● ──────── M ────────────────────────────────── ● ─────────
│ ╘════════════════════════════════════╪══════════
q_1 ── H ──────── X ─────── ry(1.0000) ──────── X ───────────────────────────── rxx(1.0000) ────┼───── M ──
┆ │ ╘═══
q_2 ── H ─── rx(1.0000) ──────── H ─────── rx(1.0000) ──── H ─── rx(1.0000) ─────────┆──────────┼──────────
q_3 ─────────────────────────────────────────────────────────────────────────── rxx(1.0000) ─── X ──── M ──
╘═══
"#]]
.assert_eq(&circ.to_string());
}

/// Tests that invoke circuit generation throught the debugger.
mod debugger_stepping {
use super::Debugger;
Expand Down Expand Up @@ -915,17 +968,17 @@ mod debugger_stepping {
step:
q_0 ── H ──
step:
q_0 ── H ──── Z ───────────────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
╘══════════
q_0 ── H ──── Z ─────────────────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉
╘════════════
step:
q_0 ── H ──── Z ─── |0〉 ───────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
══════════
q_0 ── H ──── Z ─── |0〉 ──────────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉
╘════════════
step:
q_0 ── H ──── Z ─── |0〉 ───────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉 ─
══════════
q_0 ── H ──── Z ─── |0〉 ──────────────────
q_1 ── H ──── ● ──── H ──── M ─── |0〉
╘════════════
"]]
.assert_eq(&circs);
}
Expand Down Expand Up @@ -959,11 +1012,11 @@ mod debugger_stepping {
q_0 ── H ──── M ──
╘═══
step:
q_0 ── H ──── M ─── |0〉 ─
╘══════════
q_0 ── H ──── M ─── |0〉
╘════════════
step:
q_0 ── H ──── M ─── |0〉 ─
╘══════════
q_0 ── H ──── M ─── |0〉
╘════════════
"]]
.assert_eq(&circs);
}
Expand Down
Loading

0 comments on commit 6ce7372

Please sign in to comment.