Skip to content

Commit

Permalink
Fix missing tick indicators at end of circuit diagrams (#430)
Browse files Browse the repository at this point in the history
- Also fix some unnecessary extra qubit wire length

Fixes #428
  • Loading branch information
Strilanc authored Nov 19, 2022
1 parent f56d1de commit fb83dba
Show file tree
Hide file tree
Showing 29 changed files with 381 additions and 153 deletions.
1 change: 1 addition & 0 deletions file_lists/test_files
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ src/stim/cmd/command_m2d.test.cc
src/stim/cmd/command_sample.test.cc
src/stim/cmd/command_sample_dem.test.cc
src/stim/dem/detector_error_model.test.cc
src/stim/diagram/ascii_diagram.test.cc
src/stim/diagram/base64.test.cc
src/stim/diagram/detector_slice/detector_slice_set.test.cc
src/stim/diagram/graph/match_graph_3d_drawer.test.cc
Expand Down
2 changes: 1 addition & 1 deletion src/stim/cmd/command_diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ int stim::command_diagram(int argc, const char **argv) {
bool has_tick_arg = false;
uint64_t tick = 0;
uint64_t tick_start = 0;
uint64_t tick_num = 1;
uint64_t tick_num = UINT64_MAX;
if (find_argument("--tick", argc, argv) != nullptr) {
has_tick_arg = true;
std::string tick_str = find_argument("--tick", argc, argv);
Expand Down
60 changes: 60 additions & 0 deletions src/stim/cmd/command_diagram.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "gtest/gtest.h"

#include "stim/main_namespaced.test.h"
#include "stim/test_util.test.h"

using namespace stim;

Expand Down Expand Up @@ -96,6 +97,65 @@ q2: ------
)output"));
}

TEST(command_diagram, run_captured_stim_main_timeline_ticking) {
auto circuit = R"input(
R 0 1
TICK
H 0
CNOT 0 1
TICK
S 0
TICK
H 0
M 0 1
)input";
auto result_txt = run_captured_stim_main(
{"diagram", "--type", "timeline-text"},
circuit);
ASSERT_EQ("\n" + result_txt, R"DIAGRAM(
/-\ /--------\
q0: -R-H-@-S-H-M:rec[0]-
|
q1: -R---X-----M:rec[1]-
\-/ \--------/
)DIAGRAM");

auto result = run_captured_stim_main(
{"diagram", "--type", "timeline-svg"},
circuit);
expect_string_is_identical_to_saved_file(
result,
"command_diagram_timeline.svg");

result = run_captured_stim_main(
{"diagram", "--type", "timeline-svg", "--tick", "0"},
circuit);
expect_string_is_identical_to_saved_file(
result,
"command_diagram_timeline_tick0.svg");

result = run_captured_stim_main(
{"diagram", "--type", "timeline-svg", "--tick", "1"},
circuit);
expect_string_is_identical_to_saved_file(
result,
"command_diagram_timeline_tick1.svg");

result = run_captured_stim_main(
{"diagram", "--type", "timeline-svg", "--tick", "2"},
circuit);
expect_string_is_identical_to_saved_file(
result,
"command_diagram_timeline_tick2.svg");

result = run_captured_stim_main(
{"diagram", "--type", "timeline-svg", "--tick", "1:3"},
circuit);
expect_string_is_identical_to_saved_file(
result,
"command_diagram_timeline_tick1_3.svg");
}

TEST(command_diagram, run_captured_stim_main_works_various_arguments) {
std::vector<std::string> diagram_types{
"timeline-text",
Expand Down
61 changes: 39 additions & 22 deletions src/stim/diagram/ascii_diagram.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,33 +141,50 @@ void AsciiDiagram::render(std::ostream &out) const {
line.resize(layout.x_offsets.back(), ' ');
}

auto p_align = [&](size_t c0, size_t cn, float align) {
if (align == 0.5f) {
cn--;
}
return c0 + (int)floor(align * cn);
};
auto x_align = [&](AsciiDiagramPos pos) {
return p_align(
layout.x_offsets[pos.x],
layout.x_spans[pos.x],
pos.align_x);
};
auto y_align = [&](AsciiDiagramPos pos) {
return p_align(
layout.y_offsets[pos.y],
layout.y_spans[pos.y],
pos.align_y);
};

for (const auto &line : lines) {
auto &p1 = line.first;
auto &p2 = line.second;
auto x = layout.x_offsets[p1.x];
auto y = layout.y_offsets[p1.y];
auto x2 = layout.x_offsets[p2.x];
auto y2 = layout.y_offsets[p2.y];
x += (int)floor(p1.align_x * (layout.x_spans[p1.x] - 1));
y += (int)floor(p1.align_y * (layout.y_spans[p1.y] - 1));
x2 += (int)floor(p2.align_x * (layout.x_spans[p2.x] - 1));
y2 += (int)floor(p2.align_y * (layout.y_spans[p2.y] - 1));
while (x != x2) {
out_lines[y][x] = '-';
x += x < x2 ? 1 : -1;

auto x1 = x_align(p1);
auto x2 = x_align(p2);
auto y1 = y_align(p1);
auto y2 = y_align(p2);
if (x1 > x2) {
std::swap(x1, x2);
}
if (p1.x != p2.x && p1.y != p2.y) {
out_lines[y][x] = '.';
} else if (p1.x != p2.x) {
out_lines[y][x] = '-';
} else if (p1.y != p2.y) {
out_lines[y][x] = '|';
} else {
out_lines[y][x] = '.';
if (y1 > y2) {
std::swap(y1, y2);
}
while (y != y2) {
y += y < y2 ? 1 : -1;
out_lines[y][x] = '|';
bool bx = x1 != x2;
while (x1 < x2) {
out_lines[y1][x1] = '-';
x1++;
}

char next_char = bx ? '.' : '|';
while (y1 < y2) {
out_lines[y1][x1] = next_char;
next_char = '|';
y1++;
}
}

Expand Down
60 changes: 60 additions & 0 deletions src/stim/diagram/ascii_diagram.test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "stim/diagram/ascii_diagram.h"

#include "gtest/gtest.h"

using namespace stim_draw_internal;

TEST(ascii_diagram, basic) {
AsciiDiagram diagram;
diagram.add_entry(AsciiDiagramEntry{
AsciiDiagramPos{0, 0, 0.5, 0.5},
{"ABC"},
});
ASSERT_EQ("\n" + diagram.str() + "\n", R"DIAGRAM(
ABC
)DIAGRAM");
diagram.add_entry(AsciiDiagramEntry{
AsciiDiagramPos{2, 0, 0.5, 0.5},
{"DE"},
});
ASSERT_EQ("\n" + diagram.str() + "\n", R"DIAGRAM(
ABC DE
)DIAGRAM");
diagram.lines.push_back({
AsciiDiagramPos{0, 1, 1, 0.5},
AsciiDiagramPos{2, 1, 0, 0.5},
});
diagram.lines.push_back({
AsciiDiagramPos{0, 2, 0, 0.5},
AsciiDiagramPos{2, 2, 1, 0.5},
});
diagram.lines.push_back({
AsciiDiagramPos{1, 3, 0, 0.5},
AsciiDiagramPos{1, 3, 1, 0.5},
});
diagram.lines.push_back({
AsciiDiagramPos{1, 4, 1, 0.5},
AsciiDiagramPos{1, 4, 0, 0.5},
});
ASSERT_EQ("\n" + diagram.str() + "\n", R"DIAGRAM(
ABC DE
-
------
-
-
)DIAGRAM");
}
2 changes: 1 addition & 1 deletion src/stim/diagram/circuit_timeline_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ void CircuitTimelineHelper::do_next_operation(const Circuit &circuit, const Oper
} else if (op.gate->id == gate_name_to_id("QUBIT_COORDS")) {
do_qubit_coords(op);
} else if (op.gate->id == gate_name_to_id("TICK")) {
num_ticks_seen += 1;
do_atomic_operation(op.gate, {}, {});
num_ticks_seen += 1;
} else if (op.gate->flags & GATE_TARGETS_PAIRS) {
do_two_qubit_gate(op);
} else {
Expand Down
12 changes: 8 additions & 4 deletions src/stim/diagram/timeline/timeline_ascii_drawer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ void DiagramTimelineAsciiDrawer::do_end_repeat(const CircuitTimelineLoopData &lo
do_tick();
}

AsciiDiagramPos top{m2x(cur_moment), 0, 1.0, 0.0};
AsciiDiagramPos bot{m2x(cur_moment), q2y(num_qubits - 1) + 1, 1.0, 1.0};
AsciiDiagramPos top{m2x(cur_moment), 0, 0.5, 0.0};
AsciiDiagramPos bot{m2x(cur_moment), q2y(num_qubits - 1) + 1, 0.5, 1.0};

diagram.lines.push_back({top, bot});
diagram.add_entry(AsciiDiagramEntry{
Expand Down Expand Up @@ -470,13 +470,17 @@ AsciiDiagram DiagramTimelineAsciiDrawer::make_diagram(const Circuit &circuit) {
obj.do_end_repeat(loop_data);
};
obj.resolver.do_circuit(circuit);
if (obj.cur_moment_is_used) {
obj.do_tick();
}

// Make sure qubit lines are drawn first, so they are in the background.
// Make space for the qubit lines to be drawn before other things.
obj.diagram.lines.insert(obj.diagram.lines.begin(), obj.num_qubits, {{0, 0, 0.0, 0.5}, {0, 0, 1.0, 0.5}});
// Overwrite the reserved space with the actual qubit lines.
for (size_t q = 0; q < obj.num_qubits; q++) {
obj.diagram.lines[q] = {
{0, obj.q2y(q), 1.0, 0.5},
{obj.m2x(obj.cur_moment) + 1, obj.q2y(q), 1.0, 0.5},
{obj.m2x(obj.cur_moment), obj.q2y(q), 0.0, 0.5},
};
obj.diagram.add_entry(AsciiDiagramEntry{
{0, obj.q2y(q), 1.0, 0.5},
Expand Down
36 changes: 18 additions & 18 deletions src/stim/diagram/timeline/timeline_ascii_drawer.test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@ TEST(circuit_diagram_timeline_text, measurement_looping) {
)CIRCUIT");
ASSERT_EQ("\n" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + "\n", R"DIAGRAM(
/REP 100 /REP 5 \ /REP 7 \ \
q0: -M:rec[0]-|-------------------------|-----------------------------|-|----------------------------------|-|---
q0: -M:rec[0]-|-------------------------|-----------------------------|-|----------------------------------|-|-
| | | | | |
q1: ----------|--------M:rec[1+iter*13]-|-----------------------------|-|----------------------------------|-|---
q1: ----------|--------M:rec[1+iter*13]-|-----------------------------|-|----------------------------------|-|-
| | | | | |
q2: ----------|-------------------------|------M:rec[2+iter*13+iter2]-|-|----------------------------------|-|---
q2: ----------|-------------------------|------M:rec[2+iter*13+iter2]-|-|----------------------------------|-|-
| | | | | |
q3: ----------|-------------------------|-----------------------------|-|------MPP[X]:rec[7+iter*13+iter2]-|-|---
q3: ----------|-------------------------|-----------------------------|-|------MPP[X]:rec[7+iter*13+iter2]-|-|-
| | | | | | |
q4: ----------|-------------------------|-----------------------------|-|------MPP[Y]:rec[7+iter*13+iter2]-|-|---
q4: ----------|-------------------------|-----------------------------|-|------MPP[Y]:rec[7+iter*13+iter2]-|-|-
\ \ / \ / /
)DIAGRAM");
}
Expand All @@ -222,13 +222,13 @@ TEST(circuit_diagram_timeline_text, repeat) {
)CIRCUIT");
ASSERT_EQ("\n" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + "\n", R"DIAGRAM(
/REP 5 /REP 100 \ \
q0: -H-|---------|--------H---|-|---
q0: -H-|---------|--------H---|-|-
| | | |
q1: -H-|---------|--------H---|-|---
q1: -H-|---------|--------H---|-|-
| | | |
q2: -H-|------RX-|------------|-|---
q2: -H-|------RX-|------------|-|-
| | | |
q3: ---|---------|--------H-H-|-|---
q3: ---|---------|--------H-H-|-|-
\ \ / /
)DIAGRAM");
}
Expand Down Expand Up @@ -301,11 +301,11 @@ TEST(circuit_diagram_timeline_text, tick) {
H 0 0
)CIRCUIT");
ASSERT_EQ("\n" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + "\n", R"DIAGRAM(
/-\ /REP 1 /-\ \ /--------\
/-\ /REP 1 /-\ \ /--------\ /-\
q0: -H-H-H-H-|------H-H-S-|-H-H-SQRT_X-H-H-
| |
q1: -----H---|------H-----|----------------
\-/ \ \-/ / \--------/
\-/ \ \-/ / \--------/ \-/
)DIAGRAM");
}

Expand Down Expand Up @@ -375,7 +375,7 @@ TEST(circuit_diagram_timeline_text, surface_code) {
CircuitGenParameters params(10, 3, "unrotated_memory_z");
auto circuit = generate_surface_code_circuit(params).circuit;
ASSERT_EQ("\n" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + "\n", R"DIAGRAM(
/-----------------\ /-------\ /-------\ /----------------------------------\ /REP 9 /-------\ /-------\ /-----------------------------------------------------------------------------------\ \
/-----------------\ /-------\ /-------\ /----------------------------------\ /REP 9 /-------\ /-------\ /-----------------------------------------------------------------------------------\ \ /------------------------------------------------------------------------------------------------------------------\
q0: -QUBIT_COORDS(0,0)-R-----------------@-------X----------------------------------------|------------------------@-------X-----------------------------------------------------------------------------------------|-M:rec[120]---------------------------------------------------------OBSERVABLE_INCLUDE:L0*=rec[122]*rec[121]*rec[120]-
| | | | | |
q1: -QUBIT_COORDS(1,0)-R-H-@-@-----------|-------@-H-MR:rec[0]----------------------------|--------H-@-@-----------|-------@-H-MR:rec[12+iter*12]-DETECTOR(1,0,1+iter):D[6+iter*12]=rec[12+iter*12]*rec[0+iter*12]---|----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -425,15 +425,15 @@ q22: -QUBIT_COORDS(2,4)-R---X-------@-|---|-------X-----------------------------
q23: -QUBIT_COORDS(3,4)-R-H-@---------|---@-------@-H-MR:rec[11]---------------------------|--------H-@---------|---@-------@-H-MR:rec[23+iter*12]-DETECTOR(3,4,1+iter):D[17+iter*12]=rec[23+iter*12]*rec[11+iter*12]-|----------------------------------------------------------------------------------------------------------------------
| | | | | |
q24: -QUBIT_COORDS(4,4)-R---X---------@----------------------------------------------------|----------X---------@-----------------------------------------------------------------------------------------------------|-M:rec[132]-----------------------------------------------------------------------------------------------------------
\-----------------/ \-------/ \-------/ \----------------------------------/ \ \-------/ \-------/ \-----------------------------------------------------------------------------------/ /
\-----------------/ \-------/ \-------/ \----------------------------------/ \ \-------/ \-------/ \-----------------------------------------------------------------------------------/ / \------------------------------------------------------------------------------------------------------------------/
)DIAGRAM");
}

TEST(circuit_diagram_timeline_text, repetition_code) {
CircuitGenParameters params(10, 9, "memory");
auto circuit = generate_rep_code_circuit(params).circuit;
ASSERT_EQ("\n" + DiagramTimelineAsciiDrawer::make_diagram(circuit).str() + "\n", R"DIAGRAM(
/--------------------------------\ /REP 9 /-----------------------------------------------------------------------------\ \
/--------------------------------\ /REP 9 /-----------------------------------------------------------------------------\ \ /---------------------------------------------------\
q0: -R-@--------------------------------------|--------@-----------------------------------------------------------------------------------|-M:rec[80]-DETECTOR(1,10):D80=rec[81]*rec[80]*rec[72]--
| | | |
q1: -R-X-X-MR:rec[0]-DETECTOR(1,0):D0=rec[0]--|--------X-X-MR:rec[8+iter*8]--DETECTOR(1,1+iter):D[8+iter*8]=rec[8+iter*8]*rec[0+iter*8]----|-------------------------------------------------------
Expand Down Expand Up @@ -467,7 +467,7 @@ q14: -R-@-@------------------------------------|--------@-@---------------------
q15: -R-X-X-MR:rec[7]-DETECTOR(15,0):D7=rec[7]-|--------X-X-MR:rec[15+iter*8]-DETECTOR(15,1+iter):D[15+iter*8]=rec[15+iter*8]*rec[7+iter*8]-|-------------------------------------------------------
| | | |
q16: -R---@------------------------------------|----------@---------------------------------------------------------------------------------|-M:rec[88]-OBSERVABLE_INCLUDE:L0*=rec[88]--------------
\--------------------------------/ \ \-----------------------------------------------------------------------------/ /
\--------------------------------/ \ \-----------------------------------------------------------------------------/ / \---------------------------------------------------/
)DIAGRAM");
}

Expand Down Expand Up @@ -501,9 +501,9 @@ TEST(circuit_diagram_timeline_text, repetition_code_transposed) {
| | | | |
\-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------/
| | | | |
M:rec[20] | M:rec[21] | M:rec[22]
| | | | |
DETECTOR(1,10):D20=rec[21]*rec[20]*rec[18] | DETECTOR(3,10):D21=rec[22]*rec[21]*rec[19] | OBSERVABLE_INCLUDE:L0*=rec[22]
/ M:rec[20] | M:rec[21] | M:rec[22] \
| | | | | | |
\ DETECTOR(1,10):D20=rec[21]*rec[20]*rec[18] | DETECTOR(3,10):D21=rec[22]*rec[21]*rec[19] | OBSERVABLE_INCLUDE:L0*=rec[22]/
| | | | |
)DIAGRAM");
}
Loading

0 comments on commit fb83dba

Please sign in to comment.