Skip to content

Commit 85ecc97

Browse files
Shobhit21287eliarbelmtreinish
authored
Text circuit drawer (#15357)
* Entry point and function created, returns info about instructions in circuit * printing the qubits and clbits names * fixed entry point for draw function * addition to draw function, getting layers from DAG circuit * code moved to circuit_drawer.rs and added as module for import, no longer needed to import qiskit._accelerate, can simply call qc.draw(text2) * refactored code, wire and circuit class * minor qubit rep fixes * changed from pymodule to pyfunction * circuit to dag conversion moved to python * boilerplate code for layer stripping * creating visualisation layers * quadratic complexity building of sublayers * few minor fixes * get_layers implementation completed * datastruct for drawing rep * barrier implementation added * Visualization Matrix structure completed * Make build_layers a standalone function * drawing logic for box and multibox, renamed Enclosed to Drawable * printing logic complete, normalisation left * Lay groundwork for VisualizationMatrix * fixed a counter in draw_layer, removed debug print statement to make code run * general handling of standard gate and instructions added, inputs also handled * minor changes in print statements * Visualization Matrix implementation complete * Visualization Matrix implementation complete * text drawer, logic complete. TO DO: fix decorations * added swap gate support, removed circuit rep * added top and bottom connect support, fixed parameter labels * merge wires added * added cregbundle functionality * Clean up various `VisualizationMatrix` construction flow * added draw capabilities * linting for lib.rs * added cregbundle flag * removed visualization matrix printing * mergewires flag added * Run cargo fmt * fixed a few labels * added vertical lines support for controlled gates * added standard gate visualisation support barring special cases * fixed classical wire connection for measurement * added fold functionality * cosmetic addition for folding of quantum circuits * Fix `cregbundle` behavior The intention of the `cregbundle` parameter is to bundle the bits of each classical register separately. This commit fixes a bug where all classical register bits were bundled into a single classical register. * added aspect ratio based folding for printing, index out of range bug for creg bundling cases * Simplify get_label This commits refactors the `TextDrawer::get_label` method to be more Rust idiomatic. * preliminary changes to structure, added PackedInstruction to control and swap, a function that tells the position of the direct on wire element and changed the code to use this function when deciding to use top and bottom connectors for boxed instructions. * bug fix for top and bottom con for boxed elements * temporary commit to save changes before merging with text_circuit_drawer * Implement Debug for VisualizationMatrix * Simplify VisualizationElement::VerticalLine * Add get_name to ElementWireInput * Simplify DirectOnWire case * Simplify the Boxed::Single(inst) case * Simplify the Boxed::Multi case * Fix clippy issues, refactor and clean up a bit * Propagate "top" to `merge_wires` * Apply miscellaneous fixes * Change the VisualizationElement::VerticalLine to hold a PackedInstruction reference * Fix capitalization of labels * Fix clippy * Correct drawing vertical line of a measure * Fix minor visualization issues This commit fixes several issues discovered via manual testing. Specifically: * Single bit wires - avoid printing `_1` for bits of length 1. For example `my_qr` instead of `my_qr_1` if `my_qr` is of length 1 * Changed some standard gate names to match those in the Python drawer * Count number of chars in label to account for Unicode chars properly when computing label length. * Fix bugs related to input wires handling * Changed default names for qubit and clbit wires * Added support for anonymous bits * Fixed a bug with mapping clbit indices to `VisualizationMatrix` wires when `cregbunde=true` * Add clbit_map as a field in VisualizationMatrix * added indexing for classical bits when bundling * cargo fmt * Fix a panic when measuring anonymous clbits with cregbundle * Add unitary gate support * linting and final checks * cleanups * Fix panic with mergewires=true and improve Delay drawing * fixed label extraction for packed instruction * used iterators in multiple places to make the code efficient, inplace allocation to prevent intermediate strings * replaced a for loop with iterator, linting and final checks * added tests for merge_wire, cregbundle and folding * Cleanup tests and strip trailing whitespace This commit updates the formatting in the unit tests to make it easier to maintain. It uses multi-line strings in the source to show the output of the visualizations as they would be printed to make it easier to debug. Additionally, one aspect of the output that made working with it harder was all the lines in the strings were fixed width with whitespace. This is an artifact of the matrix approach that was filling in each space in the visualization even if it didn't have anything to draw in that coordinate. This was making the visualization tests harder to debug because there was a lot of whitespace that had to be exactly right. To address this and to make the output strings easier to work with this commit strips the unnecessary whitespace from the output. * Update use for crossterm to indicate source of size() call This commit updates the crossterm::terminal::size() use statement to avoid a bare `size()` function call. It wasn't super clear from reading that this is referring to the terminal size as "size" is a fairly generic function name. This switches to importing the `terminal` module making the sole call to the function `terminal::size()` which provides a bit more context around the call making the code clearer. * Remove the python entry point function This commit removes the pyfunction that enables calling the rust drawer from python. This is not needed right now becase the scope of this function is to be a drawer for C. In the future if it reaches feature pairity with the Python we can expose it to python and replace the python drawer's code with this. But, for this initial implementation we don't need to expose it to Python. * Remove TODO comment This commit removes a TODO comment about renaming a struct. This wasn't needed because the name is fine, especially as it's in use in the current code for the drawer. We can rename it later, but it's not really a TODO item at this point, especially as we prepare to merge this PR. * Avoid box creation in unitary label handling * Use label for fallback This commit updates the fallback operation label in the output visualization to first use the label field if set and then the operation name as a fallback if a label is not set. * Add missing whitespace back to fallback name string The previous commit erroneously removed the whitespace around the string label set when using the name. This restores that extra whitespace padding. * Add global phase display and expand test coverage This commit expands the test coverage to cover more of the operating space of this function. We want to be able to cover the surface area of the types of circuits coming from C as that is the intent of this function. This commit expands the test coverage to include more of this surface area, although it's probably still incomplete. The drawer was missing the global phase from the visualization. This commit adds it so that when visualizing a circuit users can see the global phase. This was found during the expansion of the test coverage for setting global phase. * Skip miri on tests with dynamic terminal width This commit adds miri skips on the tests that are using the circuit_drawer with dynamic terminal width determination. This relies on calls miri can't track (using the fs) and will cause miri to fail. Skipping is the only option in these cases as we want coverage of these code paths. * Update copyright header In #15629 the copyright header url was updated to use https instead of http. This was not reflected in this PR though, this commit makes the necessary update. * Simplify range loop * Update barrier usage in tests * Fix parameterized output This commit fixes the display of ParameterExpression parameters for global phase and gate/instruction parameters. Previously it was using debug formatting for parameter expressions which was resulting in debugging output instead of a normal string representation of the expression. This switches to use the ParameterExpression::to_string() method which is more useful. * Fix unicode width handling in drawer This commit fixes the handling of unicode character widths in the drawer. Previously the width of strings was determined by `string.chars().count()` which was only valid for ascii and a subset of UTF-8 as it's counting the number of bytes not even the unique graphemes as in UTF-8 graphemes are variable length. To address this we need to use external crates, first unicode-width is used to estimate the number of columns of text are used to display the graphemes in a string. This is needed because some unicode is wider than a single column, especially some of the emoji and icons. When calculating how wide to make boxes in the drawings this is important because we need to know how long to make the boxes to match the rendered width of the labels. The second crate is unicode-segmentation is used to provide an iterator over graphemes instead of raw bytes. * Build visualization layers on circuit data This commit adjusts the circuit drawer to avoid the intermediate DAGCircuit usage. Previously a DAGCircuit was constructed to compute layers of gates for drawing. The downside with this besides the general overhead is that we need to keep the instructions in circuit data mapped to the dagcircuit which complicates the code. However, this wasn't strictly needed as we can generate layers directly from a circuit data. This commit makes this change and adds an algorithm for computing layers by iterating over circuit data. This algorithm does not produce layers in the same way as DAGCircuit would, it is sensitive to insertion order and maybe produce different layers depending on the order which gates are added to the circuit. However as this drawer is just for C/Rust to start and this is an initial implementation we can change and improve this over time. The initial algorithm added in this commit is fairly simple. * Make build_layers less eager with adding new layers * Fix rendering bug of controlled gates Fixes a bug where controlled gates (e.g. a CPhase gate) had their top or bottom connectors misaligned by one position with the corresponding controlled lines, in case their label width is even. * Update comment for connector alignment * Address remaining minor comments --------- Co-authored-by: Eli Arbel <arbel@il.ibm.com> Co-authored-by: Matthew Treinish <mtreinish@kortar.org> Co-authored-by: Eli Arbel <46826214+eliarbel@users.noreply.github.com>
1 parent 14ec7d3 commit 85ecc97

4 files changed

Lines changed: 2108 additions & 1 deletion

File tree

Cargo.lock

Lines changed: 199 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/circuit/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ uuid.workspace = true
2828
nom.workspace = true
2929
nom-unicode.workspace = true
3030
nom-language.workspace = true
31+
crossterm = "0.29.0"
32+
unicode-width = "0.2"
33+
unicode-segmentation = "1.12"
3134

3235
[dependencies.pyo3]
3336
workspace = true

0 commit comments

Comments
 (0)