Skip to content

Add qk_circuit_draw function to the C API#15361

Merged
jakelishman merged 6 commits intoQiskit:mainfrom
eliarbel:c-api-circuit-drawer
Mar 19, 2026
Merged

Add qk_circuit_draw function to the C API#15361
jakelishman merged 6 commits intoQiskit:mainfrom
eliarbel:c-api-circuit-drawer

Conversation

@eliarbel
Copy link
Copy Markdown
Member

@eliarbel eliarbel commented Nov 20, 2025

This PR adds support for circuit text drawing through the C API. It is based and blocked on #15357. See commit fefdd03 for the changes of this PR only.

@eliarbel eliarbel added this to the 2.3.0 milestone Nov 20, 2025
@eliarbel eliarbel requested a review from a team as a code owner November 20, 2025 22:45
@eliarbel eliarbel added the Changelog: Added Add an "Added" entry in the GitHub Release changelog. label Nov 20, 2025
@eliarbel eliarbel added the C API Related to the C API label Nov 20, 2025
@qiskit-bot
Copy link
Copy Markdown
Collaborator

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

@eliarbel eliarbel added the on hold Can not fix yet label Nov 20, 2025
@coveralls
Copy link
Copy Markdown

coveralls commented Nov 20, 2025

Pull Request Test Coverage Report for Build 19696786623

Details

  • 15 of 788 (1.9%) changed or added relevant lines in 3 files are covered.
  • 36 unchanged lines in 2 files lost coverage.
  • Overall coverage decreased (-0.6%) to 87.604%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/cext/src/circuit.rs 14 16 87.5%
crates/circuit/src/circuit_drawer.rs 0 771 0.0%
Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 6 91.52%
crates/qasm2/src/parse.rs 30 95.68%
Totals Coverage Status
Change from base Build 19684338744: -0.6%
Covered Lines: 94408
Relevant Lines: 107767

💛 - Coveralls

@Cryoris Cryoris modified the milestones: 2.3.0, 2.4.0 Dec 9, 2025
@github-project-automation github-project-automation Bot moved this to Ready in Qiskit 2.4 Dec 9, 2025
@Cryoris Cryoris removed this from Qiskit 2.3 Dec 9, 2025
@eliarbel eliarbel mentioned this pull request Mar 10, 2026
@alexanderivrii alexanderivrii moved this from Ready to Blocked in Qiskit 2.4 Mar 18, 2026
Comment thread test/c/test_circuit.c Outdated

uint32_t qubits[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
double params[3] = {1.41, 2.71, 3.14};
for (uint8_t gate = 0; gate <= QkGate_RC3X; ++gate) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a simpler way to loop over all standard gates?
also, there is a gate that needs 4 parametrs (CUGate), and here only 3 are given.
should we also add reset to the test?
what about the new gates like PPM and PPR ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is merely a smoke test type of thing, just to have evidence that it's working. Thanks to Matthew we now have more rigor Rust test now for the Rust text drawer.

Good catch about the 4-param gate and the missing reset instruction. Addressed in c2ce88c.

Copy link
Copy Markdown
Member Author

@eliarbel eliarbel Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding PPR/PPM: not all gates are supported yet by the Rust drawer. We'll add more as we go.

Copy link
Copy Markdown
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is still intended to merge for the 2.4 cycle, can you give the new C functions export slots somewhere suitable in qiskit-cext-vtable?

@alexanderivrii alexanderivrii moved this from Blocked to In review in Qiskit 2.4 Mar 19, 2026
@eliarbel eliarbel force-pushed the c-api-circuit-drawer branch from afc2312 to 11e02ad Compare March 19, 2026 15:54
@eliarbel
Copy link
Copy Markdown
Member Author

This is now rebased on top of main.

@eliarbel
Copy link
Copy Markdown
Member Author

If this is still intended to merge for the 2.4 cycle, can you give the new C functions export slots somewhere suitable in qiskit-cext-vtable?

Good idea. Done in 11e02ad

Copy link
Copy Markdown
Member

@alexanderivrii alexanderivrii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Eli! I experimented with this PR earlier, drawing circuits using the C interface, and all the gates appear correct.

Copy link
Copy Markdown
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there was a slightly mistaken merge-conflict resolution

Comment thread crates/cext/cbindgen.toml Outdated
Comment thread crates/cext/src/circuit.rs Outdated
Comment on lines +1973 to +1983
/// The configuration options for the ``qk_circuit_draw`` function.
#[repr(C)]
pub struct CCircuitDrawerConfig {
/// If `true`, bundles classical registers into single wires.
bundle_cregs: bool,
/// If `true`, merges the bottom and top lines of adjacent wires.
merge_wires: bool,
/// Sets the line length for wrapping the rendered text. Use 0
/// to auto-detect console width.
fold: usize,
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's too late to change now for the release, but given this configuration may well expand in the future, we might be in a bit of an awkward position with API stability and require a breaking change - having the struct members all be visible to C makes it harder for us to modify it in the future without an API break.

We can revisit in the future if/when we need to change it, and we're explicitly not API stable yet in the C API, so no worries.

Fwiw (and this is really minor) - when in repr(C), the order of the struct members is guaranteed to be in declaration order, but then to satisfy alignment concerns this means that there's going to be padding bytes between merge_wires and fold.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

having the struct members all be visible to C makes it harder for us to modify it in the future without an API break.

I didn't want to add more functions to the API for this (i.e. getter and setters for the options if this is opaque), so I thought maybe ABI stability should be enough (since it's passed by address). Anyway, Ok, I'd be happy to have it more API-stability friendly.

Thanks about the repr(c).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's passed by address, but given the access pattern is meant to be (judging by the test) that the caller allocates one on the stack themselves, then the trouble will be that if we extend the struct in a later version of the C API, code compiled against Qiskit 2.4 will have only allocated the 16 bytes needed for this struct, but Qiskit 2.5 might then try to read more than 16 bytes through the pointer it's given, which is an overread error, and it'll get random stack data instead.

@eliarbel eliarbel removed the on hold Can not fix yet label Mar 19, 2026
Copy link
Copy Markdown
Member

@jakelishman jakelishman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, Eli. I think given more time I might have wanted to think about the configuration API more, but given we're explicitly unstable in the C API, I'd rather get this out like this than not at all.

Comment thread test/c/test_circuit.c
Comment on lines +1169 to +1171
for (uint8_t gate = 0; gate <= QkGate_RC3X; ++gate) {
qk_circuit_gate(circuit, gate, &qubits[gate % 8], params);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hahaha oh wow, that's quite the strategy

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's C after all, right? 😉

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also surprized that there was no API like
for gate in StandardGateList
or similar...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, this basically is the way of doing it in C, but yeah, we don't have it in Rust.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we do :p for gate in (0..STANDARD_GATE_SIZE).map(|x| unsafe { std::mem::transmute(x) }) (probably missing a type hint, but I'm on my phone)

@jakelishman jakelishman enabled auto-merge March 19, 2026 16:21
merge_wires: bool,
/// Sets the line length for wrapping the rendered text. Use 0
/// to auto-detect console width.
fold: usize,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not have an option for no folding in the api? In python we set this to -1 to not fold. I guess usize::max is fine as an equivalent. But maybe we should document that.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't really thought about this use case initially, but I can see now how this could be useful e.g. for saving the output to a file. The Rust drawer itself uses usize for the wrapping length, so using -1 as a sentinel value seems maybe too intrusive change for this, since usize::MAX practically provides this behavior. I'll update the documentation during the RC period.

@jakelishman jakelishman added this pull request to the merge queue Mar 19, 2026
Merged via the queue into Qiskit:main with commit f0d87ec Mar 19, 2026
25 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Qiskit 2.4 Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C API Related to the C API Changelog: Added Add an "Added" entry in the GitHub Release changelog.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

8 participants