Skip to content
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

Port linear_depth_lnn to rust #13654

Merged
merged 10 commits into from
Jan 27, 2025
Merged

Conversation

gadial
Copy link
Contributor

@gadial gadial commented Jan 13, 2025

Summary

Ports the optimize_cx_circ_depth_5n_line method to Rust.

Closes #12228

Details and comments

This is synthesis pass for constructing general linear reversible circuits given by an invertible boolean matrix. The code generating the instruction list was ported to Rust in a straightforward manner; construction of the circuit itself is done in Python.

A quick benchmarking was performed by using random_invertible_binary_matrix(n, seed=seed) and timing the application of synth_cnot_depth_line_kms on the result, showing consistent improvement for the rust version.

╒═════════════════════╤═════════════╤═════════════╤═══════════════════════╕
│ Test Case           │        rust │      python │   Ratio (python/rust) │
╞═════════════════════╪═════════════╪═════════════╪═══════════════════════╡
│ 10x10 (seed 42)     │ 8.58307e-05 │ 0.00221419  │              25.7972  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 5x5 (seed 42)       │ 9.48906e-05 │ 0.000352144 │               3.71106 │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 20x20 (seed 55)     │ 0.000299549 │ 0.00747766  │              24.9631  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 50x50 (seed 13)     │ 0.00281119  │ 0.0665068   │              23.6579  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 60x60 (seed 55)     │ 0.00581484  │ 0.119858    │              20.6124  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 70x70 (seed 13)     │ 0.00826478  │ 0.168697    │              20.4115  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 100x100 (seed 1089) │ 0.0262463   │ 0.439383    │              16.7407  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 120x120 (seed 17)   │ 0.0428403   │ 0.675542    │              15.7688  │
├─────────────────────┼─────────────┼─────────────┼───────────────────────┤
│ 150x150 (seed 99)   │ 0.0835741   │ 1.47674     │              17.6699  │
╘═════════════════════╧═════════════╧═════════════╧═══════════════════════╛

@qiskit-bot
Copy link
Collaborator

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

  • @Qiskit/terra-core

@coveralls
Copy link

coveralls commented Jan 13, 2025

Pull Request Test Coverage Report for Build 12986663347

Details

  • 244 of 250 (97.6%) changed or added relevant lines in 5 files are covered.
  • 31 unchanged lines in 5 files lost coverage.
  • Overall coverage decreased (-0.01%) to 88.93%

Changes Missing Coverage Covered Lines Changed/Added Lines %
crates/accelerate/src/synthesis/linear/lnn.rs 226 227 99.56%
crates/accelerate/src/synthesis/linear/utils.rs 10 15 66.67%
Files with Coverage Reduction New Missed Lines %
crates/accelerate/src/unitary_synthesis.rs 1 92.97%
crates/qasm2/src/expr.rs 1 94.23%
crates/qasm2/src/lex.rs 7 91.98%
crates/accelerate/src/synthesis/linear/mod.rs 10 82.8%
crates/qasm2/src/parse.rs 12 97.15%
Totals Coverage Status
Change from base Build 12951053301: -0.01%
Covered Lines: 79549
Relevant Lines: 89451

💛 - Coveralls

@ShellyGarion ShellyGarion added synthesis Rust This PR or issue is related to Rust code in the repository labels Jan 13, 2025
Copy link
Member

@ShellyGarion ShellyGarion left a comment

Choose a reason for hiding this comment

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

Thanks @gadial for your contribution! I only have some minor comments and questions.

crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
@ShellyGarion
Copy link
Member

I also think we can add some release notes saying that there was a performance improvement in synth_cnot_depth_line_kms since it's implementation was ported to rust

Copy link
Contributor

@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 Gadi, the PR looks very nice and is quite close to the original Python code. I have left a few comments in-place. The main one is probably to rethink which functions we want to expose from the rust side. You probably want to add release notes as well.

crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
Comment on lines 294 to 299
#[pyfunction]
#[pyo3(signature = (mat))]
pub fn optimize_cx_circ_depth_5n_line(
_py: Python,
mat: PyReadonlyArray2<bool>,
) -> PyResult<(InstructionList, InstructionList)> {
Copy link
Contributor

Choose a reason for hiding this comment

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

For the rust function to be entirely self-contained and for consistency with other synthesis functions, it would be nice to return PyResult<CircuitData>.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 4902815

qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py Outdated Show resolved Hide resolved
qiskit/synthesis/linear/linear_depth_lnn.py Outdated Show resolved Hide resolved
qiskit/synthesis/linear_phase/cx_cz_depth_lnn.py Outdated Show resolved Hide resolved
Copy link
Contributor

@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.

This looks great! I have left a few minor in-place suggestions, but I don't feel strongly about any of these, so feel free to ignore, I am completely happy to approve this PR just as it is right now. @ShellyGarion, please take a look to see if you have any more comments. I am not sure if we need release notes: on the one hand, we can skip release notes if there is no API change, but on the other hand it might be nice to highlight that a certain algorithm was ported to Rust, giving 20x performance speedup.

crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
// Find the last "1" in row i, use COL operations to the left in order to
// zero out all other "1"s in that row.
let cols_to_update: Vec<usize> = (0..n).rev().filter(|&j| mat[[i, j]]).collect();
let (first_j, cols_to_update) = cols_to_update.split_first().unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

oh nice! I didn't know about split_first before :)

let cols_to_update: Vec<usize> = (0..n).rev().filter(|&j| mat[[i, j]]).collect();
let (first_j, cols_to_update) = cols_to_update.split_first().unwrap();
cols_to_update.iter().for_each(|j| {
_col_op_inv(mat.view_mut(), *j, *first_j);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to replace _col_op_inv by _col_op and swap the order of the arguments? (I know this is how it was done in the Python code, and badly named at that).

crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Show resolved Hide resolved
crates/accelerate/src/synthesis/linear/lnn.rs Outdated Show resolved Hide resolved
#[pyfunction]
#[pyo3(signature = (mat))]
pub fn optimize_cx_circ_depth_5n_line(
_py: Python,
Copy link
Contributor

Choose a reason for hiding this comment

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

We can probably skip passing _py to the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

The function name is not particularly representative of what the function is doing (in particular, it does not optimize anything). Maybe something like synth_cnot_depth_line_pair (but please find a better name than that). Also it seems that our new agreed on convention is to prefix python interface functions with py, i.e. let's change the names to py_synth_cnot_depth_line_pair and to py_synth_cnot_depth_line_kms. We don't follow this convention anywhere else in the synthesis code yet, but I believe someone is working on that already.

Copy link
Member

@ShellyGarion ShellyGarion left a comment

Choose a reason for hiding this comment

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

Generally it looks good. I only have a minor comment on the docs.

/// `arXiv:quant-ph/0701194 <https://arxiv.org/abs/quant-ph/0701194>`_.
#[pyfunction]
#[pyo3(signature = (mat))]
pub fn py_synth_cnot_depth_line_kms(
Copy link
Member

@ShellyGarion ShellyGarion Jan 26, 2025

Choose a reason for hiding this comment

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

this is a minor comment: both these pyfunctions have exactly the same docstring. could you add an explanation? it seems that the difference is in the args+returns. Could you please add them too (at least to the pyfunctions)?

Copy link
Member

@ShellyGarion ShellyGarion left a comment

Choose a reason for hiding this comment

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

LGTM, thanks @gadial !

@ShellyGarion ShellyGarion added this pull request to the merge queue Jan 27, 2025
Merged via the queue into Qiskit:main with commit e4743a0 Jan 27, 2025
17 checks passed
@gadial gadial deleted the rust_linear_depth_lnn branch January 27, 2025 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Rust This PR or issue is related to Rust code in the repository synthesis
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Port synth_cnot_depth_line_kms to Rust
5 participants