Skip to content

Conversation

mtreinish
Copy link
Member

@mtreinish mtreinish commented Feb 23, 2022

Summary

This commit replaces the cython implementation of the pauli expectation
value functions with a multithreaded rust implementation. This was done
primarily for two reasons, the first and primary reason for this change
is because after #7658 this module was the only cython code left in the
qiskit-terra repository so unifying on a single compiled language will
reduce the maintanence burden in qiskit-terra. The second reason is
similar to the rationale in #7658 around why using rust over cython for
multi-threaded hybrid python module. The difference here though is
unlike in stochastic swap this module isn't as performance critical as
it's not nearly as widely used.

Details and comments

@mtreinish mtreinish added the on hold Can not fix yet label Feb 23, 2022
@mtreinish mtreinish added this to the 0.20 milestone Feb 23, 2022
@mtreinish mtreinish requested review from a team and ikkoham as code owners February 23, 2022 16:02
@mtreinish
Copy link
Member Author

To quickly compare the performance with this PR vs the previous implementation I ran this script:

import time

import numpy as np
from qiskit.quantum_info import random_statevector
from qiskit.quantum_info import random_density_matrix
from qiskit.quantum_info import Pauli
import matplotlib.pyplot as plt

size = []
x_times = []
random_operator_times = []

for n in range(1, 30):
    size.append(2**n)
    statevector = random_statevector(2**n)
    pauli_local_times = []
    pauli_x = Pauli("X")
    for i in range(5):
        start = time.time()
        statevector.expectation_value(pauli_x)
        stop = time.time()
        pauli_local_times.append(stop - start)
    x_times.append(np.mean(pauli_local_times))

plt.loglog(size, x_times)
plt.title('Random Statevector Expectation value time for Pauli("X") observable')
plt.savefig("test.png")

With this PR applied:

test

vs the current main branch:

test

@coveralls
Copy link

coveralls commented Feb 23, 2022

Pull Request Test Coverage Report for Build 1964856018

  • 3 of 3 (100.0%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.002%) to 83.465%

Totals Coverage Status
Change from base Build 1964131760: 0.002%
Covered Lines: 52438
Relevant Lines: 62826

💛 - Coveralls

@mtreinish
Copy link
Member Author

mtreinish commented Feb 25, 2022

After writing 3751216 I reran the benchmarks to compare the performance I graphed the ratio compared to cython:

ratio_rust_over_cython

Which shows that 3751216 significantly improves the single threaded performance and it's faster than cython almost everywhere now. Then once we hit 19 qubits and start running multithreaded it's even faster. (in the graph above I'm running on my workstation with 32 physical cores and 64 logical cores, the scaling might not be as good on smaller systems)

I also tweaked the benchmark script I used to collect the data to be a bit more realistic:

import io
import time

import numpy as np
from qiskit.quantum_info import random_statevector
from qiskit.quantum_info import random_density_matrix
from qiskit.quantum_info import random_pauli
import matplotlib.pyplot as plt

size = []
x_times = []
random_operator_times = []

rng = np.random.default_rng(seed=42)
PAULI_CHOICES = ["I", "X", "Y", "Z"]

for n in range(1, 30):
    size.append(2**n)
    statevector = random_statevector(2**n)
    pauli_local_times = []
    pauli_x = random_pauli(n, seed=rng)
    for i in range(5):
        start = time.time()
        statevector.expectation_value(pauli_x)
        stop = time.time()
        pauli_local_times.append(stop - start)
    x_times.append(np.mean(pauli_local_times))

This commit replaces the cython implementation of the pauli expectation
value functions with a multithreaded rust implementation. This was done
primarily for two reasons, the first and primary reason for this change
is because after Qiskit#7658 this module was the only cython code left in the
qiskit-terra repository so unifying on a single compiled language will
reduce the maintanence burden in qiskit-terra. The second reason is
similar to the rationale in Qiskit#7658 around why using rust over cython for
multi-threaded hybrid python module. The difference here though is
unlike in stochastic swap this module isn't as performance critical as
it's not nearly as widely used.
This commit tunes the sum for the single threaded path. Using the
iterator sum() method is very convienent but for the single threaded
path it doesn't create the most efficient output. This was causing a
regression in performance over the previous cython version. To address
that issue, this commit adds a new tuned function which does a chunked
sum which the compiler can handle better. It more closely models how
we'd do this with vectorized SIMD instructions. As a future step we can
look at using simdeez https://github.com/jackmott/simdeez
to further optimize this by doing runtime CPU feature detection and
leveraging SIMD instrinsics (we might want to look at using `fast_sum()`
in the multithreaded path if we do that too).
@mtreinish mtreinish changed the title [WIP] Replace pauli expectation value cython with multithreaded rust implementation Replace pauli expectation value cython with multithreaded rust implementation Feb 28, 2022
@mtreinish mtreinish added Changelog: New Feature Include in the "Added" section of the changelog Changelog: Removal Include in the Removed section of the changelog and removed on hold Can not fix yet labels Feb 28, 2022
mtreinish added a commit to mtreinish/qiskit that referenced this pull request Mar 1, 2022
This commit updates the asv configuration to support two recent changes
in the terra repo. The first is updating the supported python version
list to reflect the current versions supported by terra. Python 3.6 is
no longer supported and python 3.10 is now supported. Additionally,
after Qiskit/qiskit#7658 merged setuptools-rust and Rust are now
being used to build compiled extensions. While cython is still being
used, it's use will be removed soon with Qiskit/qiskit#7702. This
commit updates the build configuration to build the rust extension and
then build a wheel from it instead of building the cython extension.
jakelishman pushed a commit to Qiskit/qiskit-metapackage that referenced this pull request Mar 1, 2022
This commit updates the asv configuration to support two recent changes
in the terra repo. The first is updating the supported python version
list to reflect the current versions supported by terra. Python 3.6 is
no longer supported and python 3.10 is now supported. Additionally,
after Qiskit/qiskit#7658 merged setuptools-rust and Rust are now
being used to build compiled extensions. While cython is still being
used, it's use will be removed soon with Qiskit/qiskit#7702. This
commit updates the build configuration to build the rust extension and
then build a wheel from it instead of building the cython extension.
mtreinish added a commit to mtreinish/qiskit that referenced this pull request Mar 1, 2022
With Qiskit/qiskit#7658 and Qiskit/qiskit#7702 not far
behind the requiremetns for building terra from source will be changed.
A C++ compiler is no longer required and instead a rust compiler is
needed. This commit updates the instructions on building from source and
also removes so old out of date notes from the document at the same
time.
@mtreinish
Copy link
Member Author

mtreinish commented Mar 1, 2022

This should be ready for review now

@mtreinish mtreinish added the Rust This PR or issue is related to Rust code in the repository label Mar 3, 2022
mtreinish and others added 2 commits March 10, 2022 09:08
Co-authored-by: Kevin Hartman <kevin@hart.mn>
The functions only work for at most for number of qubits < usize bits
anything larger would cause an overflow. While rust provides overflow
checking in debug mode it disables this for performance in release mode.
Sice we ship binaries in release mode this commit adds an overflow check
for the num_qubits argument to ensure that we don't overflow and produce
incorrect results.
The setup_requires field in the setup.py is deprecated and
has been superseded by the pyproject.toml to define build
system dependencies. Since we're already relying on the
pyproject.toml to install setuptools-rust for us having the
setup_requires line will do nothing but potentially cause
issues as it will use an older install mechanism that will potentially conflict with  people's environments.
Copy link
Contributor

@kevinhartman kevinhartman left a comment

Choose a reason for hiding this comment

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

Looks good!

Do we think it's an issue for these algorithms to be capped at ~63 qubits when porting to Rust? I suppose they'd've had the same limit in Cython?

@mtreinish
Copy link
Member Author

Looks good!

Do we think it's an issue for these algorithms to be capped at ~63 qubits when porting to Rust? I suppose they'd've had the same limit in Cython?

In practice they're capped much lower than 63 qubits, these are only called internally by the statevector and density matrix classes. A statevector requires ~16 bytes * 2^num qubits of memory (and a density matrix is that squared because it's 2d) we'll hit either insufficient memory or the max number of array elements trying to build the objects. We probably don't need the overflow guard here because in practice I don't think we'll ever see it, I added it because an int comparison is quick and just in case something decided to call this outside of quantum_info.

Copy link
Contributor

@kevinhartman kevinhartman left a comment

Choose a reason for hiding this comment

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

LGTM!

@mergify mergify bot merged commit e5721e9 into Qiskit:main Mar 10, 2022
@mtreinish mtreinish deleted the rust-pauli-expval branch March 10, 2022 20:55
@kevinhartman
Copy link
Contributor

Taking this moment (PR with this number being merged) to also commemorate the Bode 7702 Vocoder.

mtreinish added a commit to mtreinish/qiskit-core that referenced this pull request Mar 11, 2022
As part of Qiskit#7702 we added a function for performing a sum over an
array/Vec of f64 values that is optimized to let the compiler use
SIMD instructions to speed up the computation. The stochastic swap rust
module performs a very similar sum multiple times as part of each swap
trial. This commit moves the fast_sum() function used in the pauli
expectation value functions to a common location and updates stochastic
swap to use it too.
garrison added a commit to garrison/qiskit that referenced this pull request Mar 14, 2022
This follows up on Qiskit#7702, which removed the last of the Cython code.
The current change was was presumably intended to be part of that
PR, I think, based on the release note added there:

> Cython is no longer a build dependency of Qiskit Terra and is no
> longer required to be installed when building Qiskit Terra from
> source.
mergify bot pushed a commit that referenced this pull request Mar 14, 2022
This follows up on #7702, which removed the last of the Cython code.
The current change was was presumably intended to be part of that
PR, I think, based on the release note added there:

> Cython is no longer a build dependency of Qiskit Terra and is no
> longer required to be installed when building Qiskit Terra from
> source.
mtreinish added a commit to Qiskit/qiskit-metapackage that referenced this pull request Mar 23, 2022
* Update building from source instructions

With Qiskit/qiskit#7658 and Qiskit/qiskit#7702 not far
behind the requiremetns for building terra from source will be changed.
A C++ compiler is no longer required and instead a rust compiler is
needed. This commit updates the instructions on building from source and
also removes so old out of date notes from the document at the same
time.

* Apply suggestions from code review

* Consistently capitalise "Rust"

* Add section on modifying rust extension

* Fix typos

* Empty-Commit to retrigger ci after outage

Co-authored-by: Jake Lishman <jake@binhbar.com>
jakelishman pushed a commit to jakelishman/qiskit-terra that referenced this pull request Aug 11, 2023
…kage#1437)

This commit updates the asv configuration to support two recent changes
in the terra repo. The first is updating the supported python version
list to reflect the current versions supported by terra. Python 3.6 is
no longer supported and python 3.10 is now supported. Additionally,
after Qiskit#7658 merged setuptools-rust and Rust are now
being used to build compiled extensions. While cython is still being
used, it's use will be removed soon with Qiskit#7702. This
commit updates the build configuration to build the rust extension and
then build a wheel from it instead of building the cython extension.
jakelishman added a commit to jakelishman/qiskit-terra that referenced this pull request Aug 11, 2023
)

* Update building from source instructions

With Qiskit#7658 and Qiskit#7702 not far
behind the requiremetns for building terra from source will be changed.
A C++ compiler is no longer required and instead a rust compiler is
needed. This commit updates the instructions on building from source and
also removes so old out of date notes from the document at the same
time.

* Apply suggestions from code review

* Consistently capitalise "Rust"

* Add section on modifying rust extension

* Fix typos

* Empty-Commit to retrigger ci after outage

Co-authored-by: Jake Lishman <jake@binhbar.com>
SameerD-phys pushed a commit to SameerD-phys/qiskit-terra that referenced this pull request Sep 7, 2023
…kage#1437)

This commit updates the asv configuration to support two recent changes
in the terra repo. The first is updating the supported python version
list to reflect the current versions supported by terra. Python 3.6 is
no longer supported and python 3.10 is now supported. Additionally,
after Qiskit#7658 merged setuptools-rust and Rust are now
being used to build compiled extensions. While cython is still being
used, it's use will be removed soon with Qiskit#7702. This
commit updates the build configuration to build the rust extension and
then build a wheel from it instead of building the cython extension.
SameerD-phys pushed a commit to SameerD-phys/qiskit-terra that referenced this pull request Sep 7, 2023
)

* Update building from source instructions

With Qiskit#7658 and Qiskit#7702 not far
behind the requiremetns for building terra from source will be changed.
A C++ compiler is no longer required and instead a rust compiler is
needed. This commit updates the instructions on building from source and
also removes so old out of date notes from the document at the same
time.

* Apply suggestions from code review

* Consistently capitalise "Rust"

* Add section on modifying rust extension

* Fix typos

* Empty-Commit to retrigger ci after outage

Co-authored-by: Jake Lishman <jake@binhbar.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: New Feature Include in the "Added" section of the changelog Changelog: Removal Include in the Removed section of the changelog performance Rust This PR or issue is related to Rust code in the repository
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants