-
Notifications
You must be signed in to change notification settings - Fork 161
Circuit diagrams: Group loops #2827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…ks/circuit-collapse-no-line-art-loops
| // Put a placeholder in the execution graph for the jump past the loop | ||
| self.exec_graph.push(ExecGraphNode::Jump(0)); | ||
| let body = self.lower_block(body); | ||
| let body = self.lower_block(body, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since this is the only place that is_loop_body is passed as true, and that only causes the extra node to be pushed, it might make sense to put the node pushing here and then leave lower_block signature unchanged.
| frame_id, | ||
| loop_scope: Some(LoopScope { | ||
| loop_expr, | ||
| iteration_count, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: this is very "code golf" of me, but the extra local to define iteration_count feels unnecessary when this line could just be interation_count: 0, instead.
Feature changes
Loops from user source are now grouped in circuit diagrams.
BEFORE:
AFTER:
All loops (
for,while,repeat/until) are supported. The label is the expression in the loop header, which can be, depending on the loop type, an iterable, a "while" condition, or an "until" condition. e.g.:loop: 0..2loop: i < 2loop: i==2Exception 1: If a loop only has a single iteration, we don't group.
Exception 2: If a loop is "vertical", meaning each iteration of the loop only interacts with a distinct set of qubits, then there is no grouping, since grouping in this case tends to look more confusing than helpful.
Internals
High level circuit diagram pipeline
To recap, this is how circuit diagrams get currently generated.
Q#/OpenQASM gets compiled to (via the compilation pipeline --
qsc_frontend,qsc_lowerererFIR lowerer etc)......FIR gets evaluated and traced (via
qsc_evalEvaluator)......Traces with raw stacks get captured and transformed to (via Circuit Tracer)...
...Traces with logical stacks get transformed to (via Circuit Tracer)...
...
Circuitrepresentation gets serialized to (viaserde-json)......Circuit JSON object gets rendered as (via
circuit-vis)...SVG & HTML circuit diagram
Evaluator changes
Tracing in the Evaluator: The
Tracernow captures the stack ofScopes in addition to the usual call stack (Frames) in the tracing calls. The scope stack includes the stack of current lexical scopes and loops, including iteration count. This allows the circuit tracer to build a comprehensive "logical" stack that includes both call frames and lexical scopes in the source.The evaluator, when in DEBUG configuration, pushes LOOPs as a scope into the
Scopestack. Before this change, we did track each Block as a scope, but not specifically loops. So now when we're in a loop, there is an extraScopein the stack:iteration_countwhich the evaluator is instructed to increment every time it enters the body block of the loop.FIR lowerer changes
FIR: In the execution graph, debug-only nodes are consolidated into a separate
ExecGraphDebugNodeenum, just for legibility.FIR: during lowering, we add some extra data to the execution graph for loops: The a new
PushLoopScopeinstruction to push loop scope, with an attachedExprId(used later by the circuit tracer to look up the loop source code and display the loop label) , and aLoopIterationinstruction that is used to indicate a new iteration of the loop has started.Circuit tracer changes
builder.rs/CircuitTracer: Introduces aLogicalStackwhich is a blended stack of call frames and lexical scopes. This struct is produced by transforming the stack traces passed down from the evaluator into a more "friendly" shape, and it corresponds to the structure that will ultimately be seen in the circuit diagram.circuit.rs/Circuit: TheSourceLocation::Unresolvedenum is a now-unnecessary abstraction that is removed in this change.in
CircuitTracer,finishnow takes both FIR and HIR store to resolve sources and scopescircuit-visHTML rendererTest coverage
compiler/qsc/src/interpret/circuit_tests.rstest direct all the way from Q# to theCircuitrepresentationnpm/qsharp/test/circuits-casestest all the way from Q# to rendered SVG & HTML circuit diagram using the JS/WASM componentcompiler/qsc_circuit/src/builder/tests/logical_stack_trace.rs- this exercises the Q# -> traces pipeline, validating that the evaluator returns expected "logical" stack traces