Skip to content

Conversation

@Shobhit21287
Copy link

Summary

This PR addresses the feature request in #14713 and adds a draw function to rust which takes in &CircuitData type to give an ASCII art string representation for its visualisation. It currently focuses only on drawing StandardInstruction, StandardGate and Unitary variants of the PackedOperation and is being added as a standalone feature rather than replacing the entire TextDrawer from the python space.

struct VisualizationMatrix<'a> {
    layers: Vec<VisualizationLayer<'a>>,
    circuit: &'a CircuitData,
    clbit_map: Vec<usize>,
}

struct VisualizationLayer<'a>(Vec<VisualizationElement<'a>>);

enum VisualizationElement<'a> {
    #[default]
    Empty,
    VerticalLine(&'a PackedInstruction),
    Input(WireInputElement<'a>),
    DirectOnWire(OnWireElement<'a>),
    Boxed(BoxedElement<'a>),
}

VisualizationMatrix, VisualizationLayer struct and VisualizationElement enum are introduced to create a logical 2D matrix representation of the circuit instructions for visualization.

  1. fn build_layers(dag: &DAGCircuit) -> Vec<Vec<NodeIndex>>: This function is used to divide the NodeIndex of a DAGCircuit into layers so that when they are visualised, there are no instructions with overlapping wires.
  2. fn get_instruction_range(...) -> (usize, usize): This function provides with range of indices of wires that will be affected by an instruction when it is visualised. It is used in build_layer to avoid overlapping of visualised instructions.

Please note that these layers are purely for visualization. NodeIndex elements build_layersout , that might be topologically the same, will most likely be in different layers, as their respective instructions act on intersecting ranges.

The VisualizationMatrix is an intermediate representation that handles all the logic mappings of instructions for visualization. This is then used to build another data struct, TextDrawer that handles all the string operations to create the final ASCII string art.

struct TextDrawer {
    wires: Vec<Vec<TextWireElement>>,
}

struct TextWireElement {
    top: String,
    mid: String,
    bot: String,
}

The TextDrawer has a draw_element method which gives the corresponding TextWireElement for a VisualizationElement. The TextDrawer struct holds the 2D String representation which can then be printed using the .draw() method.

Code flow

  • The entry point takes in a CircuitData which is used to create the VisualizationMatrix. Specifically for the build_layers function, CircuitData is converted to DAGCircuit
  • build_layers is used in VisualizationMatrix::from_circuit() to construct the VisualizationMatrix for the input circuit
  • Each element in the VisualizationMatrix is a logical VisualizationLayer. This is a column based representation.
  • Each layer holds the enum VisualizationElement. These enums ultimately hold a reference to PackedInstruction.
  • After the VisualizationMatrix is created, it is then used to create TextDrawer, which holds a row based representation for the circuit. These rows represent the wires for each qubit and clbit/register based on if cregbundle is true or not.
  • Finally, post processing of the ASCII string art happens using the TextDrawer, after which it returns the string. At this point it is ready for printing.

Shobhit21287 and others added 30 commits November 20, 2025 17:12
…nger needed to import qiskit._accelerate, can simply call qc.draw(text2)
eliarbel and others added 13 commits November 20, 2025 19:39
* Change the VisualizationElement::VerticalLine to hold a PackedInstruction reference
* Fix capitalization of labels
* Fix clippy
* Correct drawing vertical line of a measure
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.
* 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`
@Shobhit21287 Shobhit21287 requested a review from a team as a code owner November 20, 2025 15:33
@qiskit-bot qiskit-bot added the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Nov 20, 2025
@qiskit-bot
Copy link
Collaborator

Thank you for opening a new pull request.

Before your PR can be merged it will first need to pass continuous integration tests and be reviewed. Sometimes the review process can be slow, so please be patient.

While you're waiting, please feel free to review other open PRs. While only a subset of people are authorized to approve pull requests for merging, everyone is encouraged to review open pull requests. Doing reviews helps reduce the burden on the core team and helps make the project's code better for everyone.

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core

@CLAassistant
Copy link

CLAassistant commented Nov 20, 2025

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ eliarbel
❌ Shobhit21287
You have signed the CLA already but the status is still pending? Let us recheck it.

@eliarbel eliarbel removed the Community PR PRs from contributors that are not 'members' of the Qiskit repo label Nov 20, 2025
@eliarbel eliarbel added this to the 2.3.0 milestone Nov 20, 2025
@eliarbel eliarbel added Changelog: None Do not include in changelog Rust This PR or issue is related to Rust code in the repository labels Nov 20, 2025
@coveralls
Copy link

coveralls commented Nov 20, 2025

Pull Request Test Coverage Report for Build 19755751808

Warning: This coverage report may be inaccurate.

This pull request's base commit is no longer the HEAD commit of its target branch. This means it includes changes from outside the original pull request, including, potentially, unrelated coverage changes.

Details

  • 1 of 775 (0.13%) changed or added relevant lines in 2 files are covered.
  • 134 unchanged lines in 10 files lost coverage.
  • Overall coverage decreased (-0.6%) to 87.773%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/circuit/src/circuit_drawer.rs 0 774 0.0%
Files with Coverage Reduction New Missed Lines %
crates/cext/src/transpiler/passes/remove_identity_equiv.rs 1 79.17%
crates/circuit/src/parameter/parameter_expression.rs 1 82.3%
qiskit/circuit/commutation_checker.py 1 94.74%
crates/circuit/src/parameter/symbol_expr.rs 2 73.27%
crates/qasm2/src/lex.rs 2 92.8%
crates/transpiler/src/passes/commutation_analysis.rs 4 92.78%
crates/transpiler/src/passes/remove_identity_equiv.rs 12 90.7%
qiskit/circuit/library/pauli_evolution.py 21 81.94%
crates/transpiler/src/commutation_checker.rs 22 88.84%
crates/circuit/src/dag_circuit.rs 68 84.63%
Totals Coverage Status
Change from base Build 19723813215: -0.6%
Covered Lines: 95692
Relevant Lines: 109022

💛 - Coveralls

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changelog: None Do not include in changelog Rust This PR or issue is related to Rust code in the repository

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

6 participants