Skip to content

Add impls of ProgramNode for various math operations - #16107

Merged
ihincks merged 18 commits into
Qiskit:mainfrom
ihincks:program-node-math
Aug 27, 2026
Merged

Add impls of ProgramNode for various math operations#16107
ihincks merged 18 commits into
Qiskit:mainfrom
ihincks:program-node-math

Conversation

@ihincks

@ihincks ihincks commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

This PR closes #16031 by implementing ProgramNode for various math-y structs.

  • Add
  • Subtract
  • Multiply
  • Divide
  • Remainder
  • Power

PR Stack

AI/LLM disclosure

  • I didn't use LLM tooling, or only used it privately.
  • I used the following tool to help write this PR description:
  • I used the following tool to generate or modify code: Claude 4.6

@ihincks
ihincks requested a review from a team as a code owner April 29, 2026 20:04
@ihincks ihincks added Rust This PR or issue is related to Rust code in the repository mod: providers Related to the backend and job abstractions labels Apr 29, 2026
@qiskit-bot

Copy link
Copy Markdown
Collaborator

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

  • @Qiskit/terra-core

@ihincks
ihincks marked this pull request as draft April 29, 2026 20:04
@ihincks ihincks mentioned this pull request Apr 29, 2026
@coveralls

coveralls commented Apr 29, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 33116403395

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage decreased (-0.5%) to 87.74%

Details

  • Coverage decreased (-0.5%) from the base build.
  • Patch coverage: 147 uncovered changes across 3 files (818 of 965 lines covered, 84.77%).
  • 2610 coverage regressions across 48 files.

Uncovered Changes

File Changed Covered %
crates/providers/src/math_nodes/reduction.rs 577 492 85.27%
crates/providers/src/math_nodes/bitwise.rs 209 164 78.47%
crates/providers/src/math_nodes/binary.rs 172 155 90.12%
Total (5 files) 965 818 84.77%

Coverage Regressions

2610 previously-covered lines in 48 files lost coverage.

Top 10 Files by Coverage Loss Lines Losing Coverage Coverage
crates/circuit/src/dag_circuit.rs 534 86.0%
crates/circuit/src/parameter/symbol_expr.rs 449 78.35%
qiskit/qpy/binary_io/circuits.py 245 63.72%
crates/qpy/src/circuit_reader.rs 230 74.53%
crates/qpy/src/value.rs 139 73.54%
crates/circuit/src/circuit_data.rs 130 86.84%
crates/cext/src/circuit.rs 90 82.63%
crates/circuit/src/operations.rs 86 83.78%
qiskit/transpiler/passes/synthesis/hls_plugins.py 84 85.94%
crates/synthesis/src/multi_controlled/mcx.rs 64 90.5%

Coverage Stats

Coverage Status
Relevant Lines: 131079
Covered Lines: 115009
Line Coverage: 87.74%
Coverage Strength: 982075.61 hits per line

💛 - Coveralls

@ShellyGarion ShellyGarion added this to the 2.5.0 milestone Apr 30, 2026
@ihincks
ihincks force-pushed the program-node-math branch 2 times, most recently from b429b8d to a437668 Compare April 30, 2026 20:31
@ihincks ihincks changed the title Add impls of Program node for various math operations Add impls of ProgramNode for various math operations May 1, 2026
@ihincks
ihincks force-pushed the program-node-math branch 4 times, most recently from 31adc4f to 768edb2 Compare May 16, 2026 11:07
@ihincks
ihincks marked this pull request as ready for review May 16, 2026 11:07
@qiskit-bot

Copy link
Copy Markdown
Collaborator

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

  • @Qiskit/terra-core

@ihincks
ihincks requested a review from mtreinish May 16, 2026 11:07
Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
@ihincks
ihincks force-pushed the program-node-math branch 3 times, most recently from a590a50 to 2be78bc Compare May 21, 2026 19:02
@ihincks
ihincks force-pushed the program-node-math branch 2 times, most recently from 73504ec to d590df2 Compare May 28, 2026 11:08
@ihincks ihincks self-assigned this May 28, 2026
@ihincks ihincks removed this from Qiskit 2.5 May 28, 2026
@ihincks

ihincks commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

I also think we could use a bit more testing just to cover cases common cases (both positive and negative) for all the operations.

I've added a few more tests now, and in general I think coverage is decent. If there are any specific missing spots you see, please let me know and I'll add more.

@ihincks
ihincks force-pushed the program-node-math branch 2 times, most recently from 6b8b47b to 337dba8 Compare July 24, 2026 17:43
@ihincks

ihincks commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

a sharp edge when creating a program that causes unhandleable crashes

This lead me to also realize that we should handle % 0 and / 0 better. Right now, in the float case, you get NaNs or infs. This is fine, not ideal, but not a runtime error, and some of the data might be recoverable if only some elements of an array have this.

However, for integer types, we panic. We should instead do what NumPy does, and return 0 on % 0, and return NaN/inf on / 0, which means we need to cast to real.

I'll do a new PR for this.

@ihincks
ihincks force-pushed the program-node-math branch from 1b0409c to f3d7dbc Compare July 24, 2026 18:19
@ihincks
ihincks requested a review from mtreinish August 25, 2026 13:50

@mtreinish mtreinish left a comment

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.

Overall I think this is almost good to go. The only thing that stood out to me is the array operations in the reduction module are allocating a bit more than is necessary. I think we can reduce the amount of allocations by mutating some of the intermediate arrays inplace. I left comments on some spots that I saw but I'm not sure I caught them all.

I also left some inline nits on removing the static lifetime from all the functions that return string. It's not necessary as it's implied by returning an inline string literal and it doesn't really convey anything useful.

Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
Comment thread crates/providers/src/math_nodes/bitwise.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
let n = a.shape()[self.axis] as f64;
let mean = (a.sum_axis(Axis(self.axis)) / Complex::new(n, 0.0))
.insert_axis(Axis(self.axis));
let sq_mod = (a - &mean).mapv(|c| c.re * c.re + c.im * c.im);

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 think we can probably do mapv_inplace here too and avoid another allocation since the subtraction should be allocating a new array already too. But it might require a bit large of a change than is easy inline.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I applied your other mapv_inplace suggestions, but then ended up reverting because they were wrong for a trivial reason: stds/vars of a complex vector are real, so we can't put a float into a complex slot in-place.

However, you sent me down a mini rabbit hole that also addresses this comment: see aea04da, which is both faster (in some regims) and more memory efficient than the current implementation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

shape axis input original ms / peak lane ms slice ms dispatch ms / peak
[1024,1024] 0 8.0 MiB 1.72 / 12.0 MiB 1.69 0.58 0.58 / 0.02 MiB
[1024,1024] 1 8.0 MiB 1.66 / 12.0 MiB 1.26 1.94 1.26 / 0.02 MiB
[100,100000] 0 76.3 MiB 19.18 / 115.2 MiB 12.97 6.90 6.85 / 1.53 MiB
[100000,100] 1 76.3 MiB 22.05 / 115.2 MiB 9.21 33.02 8.68 / 1.53 MiB
[64,128,512] 1 32.0 MiB 9.32 / 48.2 MiB 7.57 5.41 4.95 / 0.50 MiB
[4096,4096] 0 128.0 MiB 29.44 / 192.0 MiB 95.37 8.47 8.25 / 0.06 MiB
[1000000,4] 0 30.5 MiB 107.18 / 45.8 MiB 50.01 101.35 49.75 / 0.00 MiB
[4,1000000] 1 30.5 MiB 5.87 / 45.8 MiB 5.15 76.61 5.13 / 0.00 MiB
[1000000] 0 7.6 MiB 1.88 / 11.4 MiB 1.27 54.03 1.27 / 0.00 MiB
[2,2000000] 0 30.5 MiB 11.00 / 61.0 MiB 11.16 8.26 6.35 / 30.5 MiB
[2000000,2] 1 30.5 MiB 42.72 / 61.0 MiB 13.65 12.72 12.32 / 30.5 MiB
[1024,1024] strided view 1 8.0 MiB 5.62 / 12.0 MiB 2.25 4.27 2.24 / 0.02 MiB
[2048,2048] transposed 0 32.0 MiB 7.67 / 48.0 MiB 5.22 15.11 5.22 / 0.03 MiB

@ihincks
ihincks requested a review from mtreinish August 26, 2026 21:00
mtreinish
mtreinish previously approved these changes Aug 27, 2026

@mtreinish mtreinish left a comment

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.

This LGTM now. Just one inline nit on the bare unreachable macros. It'd be good to add a reason that we think it's unreachable just for diagnostic when debugging an issue if it somehow got tripped and things panic.

Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Comment thread crates/providers/src/math_nodes/reduction.rs Outdated
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
mtreinish
mtreinish previously approved these changes Aug 27, 2026
This commit expands the test coverage of the reduction module to make
sure all the code paths are exercised and validated. It was mostly dtype
coverage for all the math nodes that was missing. The other piece was
the optimizations added aea04da the
accumulation path was not covered so a test was added and compared
against the result from ndarray's var axis.
mtreinish
mtreinish previously approved these changes Aug 27, 2026

@mtreinish mtreinish left a comment

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 pushed a commit to close the test coverage gaps in the reduction module in:
a801fc0

If this looks good to you feel free to enqueue this for merging.

@ihincks
ihincks enabled auto-merge August 27, 2026 21:09
@ihincks
ihincks added this pull request to the merge queue Aug 27, 2026
Merged via the queue into Qiskit:main with commit 4017510 Aug 27, 2026
31 checks passed
@ihincks
ihincks deleted the program-node-math branch August 27, 2026 21:55
@github-project-automation github-project-automation Bot moved this from Ready to Done in Qiskit 2.6 Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod: providers Related to the backend and job abstractions Rust This PR or issue is related to Rust code in the repository

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Implement built-in math ProgramNodes

7 participants