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

Speedup Pauli network synthesis code #4

Merged
merged 8 commits into from
Nov 6, 2024

Conversation

alexanderivrii
Copy link
Contributor

@alexanderivrii alexanderivrii commented Oct 19, 2024

This PR includes several low-hanging performance improvements for pauli network synthesis.

Reasoning about PauliDag's front layer

Instead of recalculating the front layer in the DAG every time, we use a vector in_degree to store the number of unprocessed predecessors for every node in the DAG. In addition, the nodes with no unprocessed predecessors are kept in a vector front_nodes. Note that we no longer remove nodes from a DAG, instead we consider them as processed and decrease the in_degree of their successors by 1.

Unfortunately, the output of the new method is not identical to the one before, probably because the order of Pauli operators in the Pauli set passed to single_synthesis_step may be different (even after sorting by support size). Empirically, this makes the results a bit better in some cases and a bit worse in some others.

Speeding up PauliSet.commute

For some testcases a considerable time is spent is PauliSet.commute, due to its calling get_as_vec_bool and allocating/deallocating vectors. It is significantly faster to just use get_entry method. In addition, we do not need to return or reason about Pauli phases.

Benchmarking

Here are two illustrative benchmarks from benchpress:

  • test 35: old method: 19.4 seconds, new method: 0.3 seconds
  • test 66: old method: 129.1 seconds, new method 13.7 seconds
    (with run arguments: metric = &Metric::COUNT, preserve_order = true, nshuffles = 0, skip_sort = false, fix_clifford = false)

Other comments

The PauliDag's function single_step_synthesis now gets the synthesized circuit as an argument, and adds new gates to it directly. I think this makes the code a bit cleaner.

One additional small fix is for the function check_circuit to correctly account for all-identity Paulis. Note that this checking function is still not quite correct, since it only checks that each Pauli is eventually transformed to a single-qubit rotation, but ignores the commutativity between Paulis.

In the future we could extend the synthesis functions to return a full circuit, consisting both of Clifford gates and Pauli operations. This would make Rustiq integration in Qiskit significantly simpler. I actually have the code for this already.

This PR is not based on #2 or #3 (so some of the changed code could introduce new clippy warnings).

@alexanderivrii alexanderivrii changed the title speedup pauli dag code Speedup Pauli network synthesis code Oct 20, 2024
@alexanderivrii
Copy link
Contributor Author

Here are some preliminary benchmarking results on my laptop for the 100 benchpress Hamiltonians
rustiq_changes.xlsx

@smartiel smartiel merged commit 5fc61ce into smartiel:main Nov 6, 2024
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants