Commit Graph

38 Commits

Author SHA1 Message Date
Matthew Treinish b77f3c5b5c
Better align 1q euler decomposition output to multiples of π/2 (#10789)
* Better align 1q euler decomposition output to multiples of π/2

This commit updates the euler decomposer to better align the parameter
outputs to be multiples of π/2 when possible to enable the circuit to
be run under a clifford simulator.

Previously the angle was calculated as:

```
phi = angle(u11 * (det**(-0.5))) + angle(u10 * (det**(-0.5)))
```

which has been replaced with:

```
phi = angle(u11) + angle(u10) - angle(det)
```

The algebra to get the new expression is:

```
phi = angle(u11 * (det**(-0.5))) + angle(u10 * (det**(-0.5)))
    # assumes particular phase convention so not guaranteed to be the
    # valid interpretation (though it probably is).
    = angle(u11) - 0.5*angle(det) + angle(u10) - 0.5*angle(det)
    = angle(u11) + angle(u10) - angle(det)
```

A couple of tests are updated as they were testing for exact circuit
outputs and the synthesis is returning equivalent by different results
in those cases.

Co-authored-by: aeddins-ibm <60495383+aeddins-ibm@users.noreply.github.com>

* Simplify calculation

Given the same phase convention the calculation of theta and phase can
be simplified to remove the need of computing the coeff. This commit
implements this change which should speed up the calculation slighty as
we're doing less work to reach an equivalent result.

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Remove complex_phase function

The complex phase function previously defined in
euler_one_qubit_decomposer.rs was duplicated with an existing `arg()`
method of the Complex<T> type from num-complex. This commit removes the
duplicated definition in favor of the built-in method.

* Try removing rz gate from qpy tests to side step differing decomposition of controlled gate

* Update crates/accelerate/src/euler_one_qubit_decomposer.rs

Co-authored-by: aeddins-ibm <60495383+aeddins-ibm@users.noreply.github.com>

---------

Co-authored-by: aeddins-ibm <60495383+aeddins-ibm@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
2023-10-10 11:36:13 +00:00
dependabot[bot] 2e679dc905
Bump indexmap from 2.0.0 to 2.0.1 (#10912)
* Bump indexmap from 2.0.0 to 2.0.1

Bumps [indexmap](https://github.com/bluss/indexmap) from 2.0.0 to 2.0.1.
- [Changelog](https://github.com/bluss/indexmap/blob/master/RELEASES.md)
- [Commits](https://github.com/bluss/indexmap/commits)

---
updated-dependencies:
- dependency-name: indexmap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix transitive but API-exposed dependencies on `indexmap`

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
2023-09-29 14:02:48 +00:00
dependabot[bot] a9f9cee30a
Bump rayon from 1.7.0 to 1.8.0 (#10873)
Bumps [rayon](https://github.com/rayon-rs/rayon) from 1.7.0 to 1.8.0.
- [Changelog](https://github.com/rayon-rs/rayon/blob/master/RELEASES.md)
- [Commits](https://github.com/rayon-rs/rayon/compare/rayon-core-v1.7.0...rayon-core-v1.8.0)

---
updated-dependencies:
- dependency-name: rayon
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-21 15:51:16 +00:00
Jake Lishman 22b94a139e
Use physical qubits internally within Sabre (#10782)
* Use physical qubits internally within Sabre

This swaps the whole Sabre algorithm over to using physical qubits
rather than virtual qubits.  This makes all operations based on finding
the swaps and scoring them far more natural, at the cost of the layer
structures needing to do a little more book-keeping to rewrite
themselves in terms of the new physical qubits after a swap.  This also
means that the swaps that come out of the Sabre algorithm automatically
become physical, which requires less tracking to output them into the
final DAG circuit.

The test outputs change slightly because the order we filter out
duplicate swaps in `obtain_swaps` is not identical.  We filter out cases
where the left index is greater than the right, and with the assignments
of virtual qubits to physical qubits varying, doing the filter with
physical indices in not guaranteed to filter in the same order as doing
it with virtual indices (though the trialled swaps will be the same).

* Remove branching from extended-set scoring

On modern hardware, branching is typically more expensive than a simple
floating-point addition that can be pipelined in.  This removes the
branch in favour of removing the duplication from the scoring at the end
by dividing by two.

* Fix formatting
2023-09-20 13:28:44 +00:00
Matthew Treinish 578e109a11
Add option to SabreLayout to specify starting layouts (#10721)
* Add option to SabreLayout to specify starting layouts

The SabreLayout pass typically starts with each layout trial with a
random starting layout. However, in some cases starting with a specific
starting layout can result in better output quality than starting with
a fully random layout. To use this feature an analysis pass can set a
new `sabre_starting_layout` field in the property set before
`SabreLayout` with a list of layout objects that will add additional
trials using each layout as a starting layout.

* Fix lint

* Combine random layout and partial layouts

* Expand property set docs

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Simplify branching logic for parallelism

* Use a slice for starting_layout in a trial

* Update releasenotes/notes/seed-sabre-with-layout-17d46e1a6f516b0e.yaml

Co-authored-by: Jake Lishman <jake@binhbar.com>

* Make starting layout variable names plural

The starting layout is a list and can have more than one entry. To make
this clearer, this commit renames starting_layout -> starting_layouts
and sabre_starting_layout -> sabre_starting_layouts.

* Update releasenotes/notes/seed-sabre-with-layout-17d46e1a6f516b0e.yaml

Co-authored-by: Jake Lishman <jake@binhbar.com>

* Update property set key in test

* Update test to only use partial layout

---------

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
Co-authored-by: Jake Lishman <jake@binhbar.com>
2023-09-12 22:42:58 +00:00
Jake Lishman c5c6b11324
Track Sabre decay heuristic on physical qubits (#10756)
The custom `decay` heuristic is supposed to penalise increases in depth
in the output.  The output space of qubits are the physical qubits, so
the depth is defined in relation to those.  Since its introduction in
gh-4537, this heuristic has instead been tracking the depth on the
virtual qubits, which due to the swaps is not necessarily related to the
depth in the output.

Notably, this commit actually makes the depth for routing large
volumetric circuits slightly _worse_ on average (at least for heavy-hex
topologies).  This may be because the effect on the heuristic is
overweighted, or that the depth tracking resets after each gate is
routed (and occasionally in between) to be flat across all qubits,
rather than reflecting the actual depth each qubit is subject to.
2023-09-07 12:53:08 +00:00
Jake Lishman 7252db3723
Reuse scratch space for Sabre best-swap choice (#10783)
* Reuse scratch space for Sabre best-swap choice

This re-uses the same growable scratch space for storing the temporary
swaps for each choice.  This particular space typically needed to grow
several times for each swap choice, which was taking up a non-negligible
amount of the time we spent in Rust space, especially for large circuits
on big coupling maps.

* Add comment on scratch space
2023-09-06 19:50:33 +00:00
Jake Lishman 180f19a8fb
Use `SmallVec` in `NeighborTable` for cache locality (#10784)
* Use `SmallVec` in `NeighborTable` for cache locality

A reasonable chunk of our time in Sabre is spent reading through the
`NeighborTable` to find the candidate swaps for a given layout.  Most
coupling maps that we care about have a relatively low number of edges
between qubits, yet we needed to redirect to the heap for each
individual physical-qubit lookup currently.

This switches from using a `Vec` (which is always a fat pointer to heap
memory) to `SmallVec` with an inline buffer space of four qubits.
With the qubit type being `u32`, the `SmallVec` now takes up the same
stack size as a `Vec` but can store (usually) all the swaps directly
inline in the outer `Vec` of qubits.  This means that most lookups of
the available swaps are looking in the same (up to relatively small
offsets) in memory, which makes the access patterns much easier for
prefetching to optimise for.

* Pickle via `PyList` instead of duplicate conversion

`SmallVec` doesn't have implementations of the PyO3 conversion trait, so
it needs to be done manually.  The previous state used to convert to a
Rust-space `Vec` that then needed to have its data moved from the Python
heap to the Rust heap.  This instead changes the conversions to interact
directly with Python lists, rather than using intermediary structures.
2023-09-06 19:50:06 +00:00
Jake Lishman 4a57411fd5
Enforce type-safety in `NeighborTable` (#10774)
This hides the internal `.neighbors` field in favour of instead
implemented `Index<PhysicalQubit>` on the entire `NeighborTable` struct.
This is done because indexing into `.neighbors` required calling
`PhysicalQubit::index` to retrieve a `usize`, but a similar method also
exists on `VirtualQubit`.  This meant that it was previously a normal
API pattern to do `neighbors.neighbors[qubit.index()]`, and this threw
away the type safety: it would compile without warning whether `qubit`
was physical or virtual.

To support the hiding of the `.neighbors` field, the constructor of the
coupling map is moved to be an associated function on `NeighborTable`,
so the unsafe access only happens within the context of all other unsafe
operations.
2023-09-05 22:55:28 +00:00
Jake Lishman 3075f14d66
Handle final comments with no terminating newline in OpenQASM 2 (#10773)
* Handle final comments with no terminating newline in OpenQASM 2

Previously, if an OpenQASM 2 program to be parsed ended in a comment
with no terminating '\n', the lexer would fail to notice the end of the
file and would instead attempt to emit the second '/' of the comment
introduction as a 'Slash` token.

* Run `cargo fmt`

* Testing extra cases

---------

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

---------

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
2023-09-05 21:20:29 +00:00
Jake Lishman 887bb9c594
Use qubit-index newtypes in Rust space (#10761)
* Use qubit-index newtypes in Rust space

This converts all of our Rust-space components that are concerned with
virtual and physical qubits (via the `NLayout` class) to represent those
integers with newtypes wrapping them as half-size indices, and changes
the `NLayout` API to only allow access via these types and not by raw
integers.

The way this is done should have no overhead in time usage from Rust,
and is actually a reduction in memory usage because all the qubits are
stored at half the width they were previously (for most systems).  This
is done to add type safety to all our components that were concerned
with the mixing of these two qubits.  The implementation of this commit
already turned up the logical bug fixed by gh-10756.

* Separate out type-safe enforcement in `NeighborTable` to another commit

This reverts the changes to the coupling-map generation and the indexing
into `NeighborTable` that were designed to make it more type safe in
favour of doing that in a separate commit.
2023-09-05 18:28:45 +00:00
Jake Lishman 1606ca3544
Fail gracefully on bad `SabreDAG` construction (#10724)
* Fail gracefully on bad `SabreDAG` construction

This is a private, internal Rust type, but it doesn't cost us anything
(meaningful) to bounds-check the accessors and ensure we fail gracefully
rather than panicking if we ever make a mistake in Python space. This
more faithfully fulfills the return value of `SabreDAG::new`, which
previously was an effectively infallible `Result`.

* Run `cargo fmt`
2023-09-04 15:15:44 +00:00
Matthew Treinish dcec79ef0a
Only run a single inner routing trial for layout stage in SabreLayout (#10741)
* Only run a single inner routing trial for layout stage in SabreLayout

In the SabreLayout routing pass we internally run sabre swap multiple
times forward and backwards over the circuit and transform the layout
based on the swaps that would be inserted by the routing pass.
Previously we were running multiple routing trials for this internal
execution of routing and then selecting the routing result with the
least numbers of swaps inserted. However, this heuristic of least swaps
does not necessarily result in a better layout. When increasing the
number of swap trials used for sabre layout the output quality could
result in more swaps being necessary. This points to the heuristic for
the best routing output to use for a layout is not the minimal number of
swaps. Until a more suitable heuristic can be developed for selecting
the best routing output to use for an intermediate layout transform this
commit removes the use of multiple trials for layout purposes and only
runs a single trial. We still use multiple swap trials for the final
routing as the swap count heuristic works there, but for layout we only
run a single trial.

* Avoid rayon use when running a single routing trial
2023-08-31 11:24:55 +00:00
Matthew Treinish 48cfab601e
Fix non-determinism in SabreSwap rust code (#10740)
In the SabreSwap rust module there were 2 potential sources of
non-determinism that could cause variation in results even with a fixed
seed, the ExtendedSet struct's nodes attribute and the decremented
tracking when populating the extended set. Both were caused by the same
root cause iterating over a HashMap object. Iteration order on a HashMap
(or a HashSet) is dependent on the internal hash seed of the hasher and
iteration order is explicitly not guaranteed. In the case of the
decrementer it's unlikely to have any effect even if the iteration order
is not guaranteed but it is switched to using an indexmap regarldess
just out of best practice. But for the nodes attribute in the
ExtendedSet struct there is a potential issue there because when the
total_score() method is called the nodes are iterated over, the distance
is looked up for each swap and then summed. As the distances are all
floating point values the iteration order could result in different
values being output. In both cases the `hashbrown::HashMap<K, V>` is
changed to be an `indexmap::IndexMap<K, V, ahash::RandomState>` which
will have deterministic iteration order (it uses insertion order).
2023-08-31 09:10:03 +00:00
Jake Lishman dbc450630b
Fix virtual/physical-qubit distinction in Sabre (#10712)
* Fix virtual/physical-qubit distinction in Sabre

`SabreLayout` in particular previously had a very confused notion of
virtual and physical qubits in Rust space; on each iteration, it rewrote
the `SabreDAG` to "apply" a layout.  This is not logically what
`SabreDAG` represents, though; that defines the circuit purely in terms
of virtual qubits, which by definition do not change as the mapping of
them to physical qubits changes.

This commit modifies that internal logic so that there is a clear
distinction between the virtual DAG and the changing layout.  This
significantly simplies the logic within the Sabre layout Rust component.
This commit is RNG-compatible with its parent.

The Python entry points to the Rust components of both layout and
routing are modified to return a final permutation, rather than a final
layout, as this is what `TranspileLayout.final_layout` actually is.

The application of the Sabre result to a DAG is also updated to reflect
the correct virtual/physical relationship.  With the roles of everything
clarified, this now means that in the Sabre layout case, it
automatically does the job of `ApplyLayout` _and_ the subsequent
swap-mapping in one iteration, rather than rewriting the DAG once with
`ApplyLayout` only to rewrite it immediately after with the swap-mapped
form; the initial layout is after all only valid as far as the first
inserted swap.

The Sabre routing inputs are slightly tweaked, so the clone of the
layout that the routing pass mutates to track its state as it progresses
happens internally.  _Technically_, there could have been situations
where it was preferable for the caller in Rust-space to give the output
object (if it didn't care about losing the initial layout), but in
practice, we always cloned on entry.  The cost of the layout clone is
not high even in the worst case, and this makes the ownership,
mutation and return-value interfaces clearer.

* Fix out-of-date types

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: Kevin Hartman <kevin@hart.mn>

* Improve efficiency of interfaces

---------

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
Co-authored-by: Kevin Hartman <kevin@hart.mn>
2023-08-30 08:46:46 +00:00
Matthew Treinish 4c88f07578
Remove workaround for abi3 BigUint -> Python int conversio (#10683)
In #10120 we moved to using the Python stable C API for the qiskit
binaries we build. In that PR we encountered a limitation with PyO3 at
the time when using abi3 it was unable to convert a BigUInt into a
Python int directly. To workaround this we side stepped the issue by
generating a string representation of the integer converting that to
python and then having python go from a string to a int. This has some
performance penalty and also prevented parallelism because a GIL handle
was needed to do the conversion. In PyO3 0.19.1 this limitation was
fixed and the library can handle the conversion directly now with abi3
and this commit restores the code that existed in the marginalization
module prior to #10120.
2023-08-22 11:19:10 +00:00
Matthew Treinish e6c431e306
Fix performance of Sabre rust<->Python boundary (#10652)
* Fix performance of Sabre rust<->Python boundary

In #10366 the SabreLayout and SabreSwap passes were refactored to
support nested control flow blocks. As part of that refactor a new
struct SabreResult was created to store the nested results for each
block. This new class however resulted in PyO3 cloning the full swap map
on every access. Since we have at least 1 access per gate in the circuit
(and another one for each swap) this extra clone() adds a lot of extra
overhead for deep circuits. In extreme cases this regression could be
quite extreme. To address this the result format is changed to be a
tuple (as it was originally), while this is less ergonomic the advantage
it provides is that for nested objects it moves the rust object to the
pyo3 interface so we avoid a copy as Python owns the object on the
return. However, for control flow blocks we're still using the
SabreResult class as it simplifies the internal implementation (which is
why #10366 introduced the struct). The potential impact of this is
mitigated by switching to only a single clone per control flow block,
by only accessing the SabreResult object's attribute on each recursive
call. However, if it is an issue in the future we can work on flattening
the nested structure before returning it to python to avoid any clones.

Fixes #10650

* Simplify recursive call logic in _apply_sabre_result

This commit simplifies the logic in the recursive call logic in
_apply_sabre_result to always use a tuple so we avoid an isinstance
check.

Co-authored-by: Kevin Hartman <kevin@hart.mn>

---------

Co-authored-by: Kevin Hartman <kevin@hart.mn>
2023-08-17 15:23:45 +00:00
Kevin Hartman 2062246191
Bump hashbrown to 0.14.0. (#10540)
* Bump hashbrown to 0.13.2.

* Bump hashbrown to 0.14.0 and indexmap to 2.0.0.
2023-08-15 20:22:29 +00:00
Raynel Sanchez f6207c0184
Optimize ConsolidateBlocks further (#10467)
* Initial commit: Added convert_2q_block_rust

* Feat: Perform final matrix multiplication in rust

* Feat: `blocks_to_matrix` performs all operations

* Fix: Prevent certain copying in Rust.

* Fix: Adapted to newest changes

* Fix: Small modifications to blocks_to_matrix

Small modifications based on previous reviews were made.

* Fix: Basis change without Matrix Multiplication.
- Added `change_basis` function to switch the qubits in a 2-qubit gate.

* Remove:`calculate_matrix` function

* Fix: Use swap to swap rows

* Fix: Skip initial matrix multiplication.

* Fix: Deal with empty list edege case
2023-08-10 10:27:59 +00:00
Jake Lishman 290305a2b0
Update minimum Rust version to 1.64 (#10541)
Raising the minimum Rust version lets us access workspace dependencies,
which are a convenient way of managing shared metadata between the
different crates in the project, which deduplicates a good amount of
our metadata.  This also lets us share the PyO3 version and minimum
feature set between crates, reducing the number of places that need to
be updated on a Python version bump.

`Cargo.lock` is completely regenerated for this commit with the new
unification, with the minor tweak of having run

        cargo update -p 'indexmap@2.0.0' --precise '1.9.3'

This is required to unify the `hashbrown` versions down to 0.12.3
between our dependencies and `pyo3`, which otherwise transitively
depends on `hashbrown ^0.14` via pulling in `indexmap 2.0`.  This caused
a build failure, since the `hashbrown` types that PyO3 adds `impl`s of
its traits to are not the same types that our extension modules attempt
to use with it.
2023-08-03 14:13:44 +00:00
dependabot[bot] 28113b6a9f
Bump pyo3 from 0.19.1 to 0.19.2 (#10543)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.19.1 to 0.19.2.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.19.1...v0.19.2)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-01 12:48:14 +00:00
Jake Lishman e75893d455
Fix empty-barrier handling in OpenQASM 2 (#10469)
The new parser would allow a `barrier;` statement, implicitly
broadcasting it across all qubits in scope.  This is technically not
supported by the OpenQASM 2 specification, but is a useful
quality-of-life extension to the specification (in the same way that
Qiskit interprets barriers, and the OpenQASM 3 specification defines the
`barrier;` statement).  The precise rule is added to the new parser's
`strict` mode.

The OpenQASM 2 _exporter_ similarly should not have been putting out
`barrier;` statements.  These could only occur in Qiskit when a barrier
was explicitly constructed with zero elements (as opposed to the call
`QuantumCircuit.barrier()`, which has the all-in-scope behaviour), and
consequently have no actual meaning or effect.  The exporter is modified
to simply skip such instructions, for as long as Qiskit permits the
qubitless barrier statement.
2023-07-24 20:04:05 +00:00
Jake Lishman 84aed0c3ea
Bump version numbers post 0.25.0rc1 (#10464)
This opens development on `main` for the next minor version of *Qiskit*
(no longer to be called Terra).  The version number is jumping to 0.45
to bring the version of `qiskit-terra` in line with `qiskit` (currently
the metapackge); starting from "Qiskit 0.45", this repository will be
called `qiskit` only, and the packages `qiskit` and `qiskit-terra` will
be unified, at least as far as Python packaging allows us to do.
2023-07-21 17:49:47 +00:00
Kevin Hartman 49b383a978
Support control flow in `SabreSwap` and `SabreLayout`. (#10366)
* Initial commit.

* Downgrade hashbrown to 0.12.3 for compat with Rustworkx.

* Implement gen_swap_epilogue.

* Add Python wrappers for structs.

* Implement DAG -> SabreDAG.

* Apply block results in sabre_swap.py.

* Fix node ID lookup issue.

Previously, we were using original DAG node IDs to look up nodes
in the expanded nested DAGs, but these IDs are of course not the
same.

* Fix bug where block circuits started out non-empty!

* Move DAG building and result application to functions.

* Implement control flow handling for Sabre layout.

* Fix qreg indexing bug for new swaps versus routed gates.

* Run Python formatting.

* Fix bug where root_dag was used instead of mapped_dag.

* Fix bug where swap_epilogue was in terms of physical bits instead of logical.

* Add more tests from stochastic swap.

* Fix bug mapping inner block qubits to outer circuit qubits.

* Update sabre swap testing.

* Update TODOs.

* Fix bug where a 2Q CF nodes would be mistakenly added to the extended set.

* Port more testing from stochastic swap.

* Run formatting.

* Port remaining stochastic swap tests.

* Mark Sabre routing and layout as known good for CF.

* Add random circuit valid output testing for Sabre.

* Run cargo fmt.

* Fix lint issues.

* Fix lint issues.

* Update 'test_invalid_methods_raise_on_control_flow'

* Make gen_swap_epilogue consume 'from_layout'.

* Add release note.

* Update TODO comment about num_qubits.

* Add comment about forward DAG.

* Explicitly mark NodeBlockResults as a mapping.

* Use closure instead of lambda noun.

* Add comment to make gate placement handling clearer.

* Use hashbrown::HashMap in SabreDAG.

* Add caching of circuit_to_dag.

* Simplify parameters to _build_sabre_dag.

- Makes it more explicit that the num_qubits used in a SabreDAG
  should be the number of physical qubits on the device.
- We no longer pass clbit indices because they are always local to
  the block, i.e. there's no current reason for them to be consistent
  across the root DAG and inner blocks, like we must do for qubits.

* Copy cregs during empty_dag.

* Comment-out assert.

* Use intersection_update.

* Remove unused import.

* Add caching for block dict.

* Fix import order.

* Follow types consistently in test.
2023-07-18 23:09:02 +00:00
dependabot[bot] 9bfee5612e
Bump pyo3 from 0.19.0 to 0.19.1 (#10378)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.19.0 to 0.19.1.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.19.0...v0.19.1)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-07 02:09:31 +00:00
Matthew Treinish c463b3c474
Use stable Python C API for building Rust extension (#10120)
* Use stable Python C API for building Rust extension

This commit tweaks the rust extension code to start using the PyO3 abi3
flag to build binaries that are compatible with all python versions, not
just a single release. Previously, we were building against the version
specific C API and that resulted in needing abinary file for each
supported python version on each supported platform/architecture. By
using the abi3 feature flag and marking the wheels as being built with
the limited api we can reduce our packaging overhead to just having one
wheel file per supported platform/architecture.

The only real code change needed here was to update the memory
marginalization function. PyO3's abi3 feature is incompatible with
returning a big int object from rust (the C API they use for that
conversion isn't part of the stable C API). So this commit updates the
function to convert to create a python int manually using the PyO3 api
where that was being done before.

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Set minimum version on abi3 flag to Python 3.8

* Fix lint

* Use py_limited_api="auto" on RustExtension

According to the docs for the setuptools-rust RustExtension class:
https://setuptools-rust.readthedocs.io/en/latest/reference.html#setuptools_rust.RustExtension
The best setting to use for the py_limited_api argument is `"auto"` as
this will use the setting in the PyO3 module to determine the correct
value to set. This commit updates the setup.py to follow the
recommendation in the docs.

* Update handling of phase input to expval rust calls

The pauli_expval module in Rust that Statevector and DensityMatrix
leverage when computing defines the input type of the phase argument as
Complex64. Previously, the quantum info code in the Statevector and
DensityMatrix classes were passing in a 1 element ndarray for this
parameter. When using the the version specific Python C API in pyo3 it
would convert the single element array to a scalar value. However when
using abi3 this handling was not done (or was not done correctly) and
this caused the tests to fail. This commit updates the quantum info
module to pass the phase as a complex value instead of a 1 element numpy
array to bypass this behavior change in PyO3 when using abi3.

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>

* Set py_limited_api explicitly to True

* DNM: Test cibuildwheel works with abi3

* Add abi3audit to cibuildwheel repair step

* Force setuptools to use abi3 tag

* Add wheel to sdist build

* Workaround abiaudit3 not moving wheels and windows not having a default repair command

* Add source of setup.py hack

* Add comment about pending pyo3 abi3 bigint support

* Revert "DNM: Test cibuildwheel works with abi3"

This reverts commit 8ca24cf1e4.

* Add release note

* Simplify setting abi3 tag in built wheels

* Update releasenotes/notes/use-abi3-4a935e0557d3833b.yaml

Co-authored-by: Jake Lishman <jake@binhbar.com>

* Update release note

* Update releasenotes/notes/use-abi3-4a935e0557d3833b.yaml

---------

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
Co-authored-by: Jake Lishman <jake@binhbar.com>
2023-06-12 13:45:27 +00:00
dependabot[bot] cff51cea9b
Bump rustworkx-core from 0.12.1 to 0.13.0 (#10237)
Bumps [rustworkx-core](https://github.com/Qiskit/rustworkx) from 0.12.1 to 0.13.0.
- [Release notes](https://github.com/Qiskit/rustworkx/releases)
- [Commits](https://github.com/Qiskit/rustworkx/compare/0.12.1...0.13.0)

---
updated-dependencies:
- dependency-name: rustworkx-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-07 13:30:39 +00:00
Matthew Treinish f409015bd7
Bump pyo3 and rust numpy version to 0.19.0 (#10186)
* Bump pyo3 and rust numpy version to 0.19.0

PyO3 0.19.0 and rust-numpy 0.19.0 were just released. This commit
updates the version used in qiskit to these latest releases. At the same
time this updates usage of text signature for classes that was
deprecated in the PyO3 0.19.0 release. While not fatal for normal builds
this would have failed clippy in CI because we treat warnings as errors.

* Apply suggestions from code review
2023-05-31 21:25:39 +00:00
Kevin J. Sung 06a5b9e00e
define __getstate__ and __setstate__ for OneQubitGateErrorMap (#10092)
* define __getstate__ and __setstate__ for OneQubitGateErrorMap

* add test

* fix test docstrings

* add assert in test

* add release note
2023-05-10 12:12:26 +00:00
Matthew Treinish 0e44c5e380
Fix interaction graph vf2 scoring to include 1q component (#10084)
* Fix interaction graph vf2 scoring to include 1q component

In #9148 a bug was introduced into the vf2 scoring code. In that PR the
vf2 passes were changed to treat standalone qubits as a special case to
improve the algorithmic efficiency of the pass. However, that PR
broke the scoring algorithm so that it was no longer factoring in the 1q
component of the interaction graph when scoring a layout. This meant
that when scoring a potential layout only the 2q error rates were been
factored into the score and the pass was potentially selecting worse
performing qubits. This commit fixes this error and ensures the scoring
is looking at all the error rates.

* Update qiskit/transpiler/passes/layout/vf2_utils.py
2023-05-08 14:52:10 +00:00
Matthew Treinish 908adb3432
Bump main branch version post 0.24.0rc1 tag (#10005)
Now that the first release candidate for the 0.24.0 release has been
tagged, the stable branch for the 0.24 series has been created and we
can start developing the 0.25.0 release on main. This commit bumps all
the version strings from 0.24.0 to 0.25.0 (and the backport branch for
mergify to 0.24) accordingly to differentiate the main branch from
0.24.*.
2023-04-20 21:58:50 +00:00
dependabot[bot] ccf78ae592
Bump pyo3 from 0.18.2 to 0.18.3 (#9964)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.18.2 to 0.18.3.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.18.2...v0.18.3)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-14 12:54:29 +00:00
Jake Lishman dec20b0139
Wrap io::Error in QASM2ParseError on failed file read (#9958)
Previously, if Python thought the target file for `qasm2.load` existed,
but Rust was unable to open it, the result `io:Error` would be
propagated up to Python space verbatim, and these situations usually
have confusing error messages.  This could happen, for example, if the
target was a directory on Windows.
2023-04-13 14:57:40 +00:00
Jake Lishman 73602b06d2
Add Rust-based OpenQASM 2 converter (#9784)
* Add Rust-based OpenQASM 2 converter

This is a vendored version of qiskit-qasm2
(https://pypi.org/project/qiskit-qasm2), with this initial commit being
equivalent (barring some naming / documentation / testing conversions to
match Qiskit's style) to version 0.5.3 of that package.

This adds a new translation layer from OpenQASM 2 to Qiskit, which is
around an order of magnitude faster than the existing version in Python,
while being more type safe (in terms of disallowing invalid OpenQASM 2
programs rather than attempting to construction `QuantumCircuit`s that
are not correct) and more extensible.

The core logic is a hand-written lexer and parser combination written in
Rust, which emits a bytecode stream across the PyO3 boundary to a small
Python interpreter loop.  The main bulk of the parsing logic is a simple
LL(1) recursive-descent algorithm, which delegates to more specific
recursive Pratt-based algorithm for handling classical expressions.

Many of the design decisions made (including why the lexer is written by
hand) are because the project originally started life as a way for me to
learn about implementations of the different parts of a parser stack;
this is the principal reason there are very few external crates used.
There are a few inefficiencies in this implementation, for example:

- the string interner in the lexer allocates twice for each stored
  string (but zero times for a lookup).  It may be possible to
  completely eliminate allocations when parsing a string (or a file if
  it's read into memory as a whole), but realistically there's only a
  fairly small number of different tokens seen in most OpenQASM 2
  programs, so it shouldn't be too big a deal.

- the hand-off from Rust to Python transfers small objects frequently.
  It might be more efficient to have a secondary buffered iterator in
  Python space, transferring more bytecode instructions at a time and
  letting Python resolve them.  This form could also be made
  asynchronous, since for the most part, the Rust components only need
  to acquire the CPython GIL at the API boundary.

- there are too many points within the lexer that can return a failure
  result that needs unwrapping at every site.  Since there are no tokens
  that can span multiple lines, it should be possible to refactor so
  that almost all of the byte-getter and -peeker routines cannot return
  error statuses, at the cost of the main lexer loop becoming
  responsible for advancing the line buffer, and moving the non-ASCII
  error handling into each token constructor.

I'll probably keep playing with some of those in the `qiskit-qasm2`
package itself when I have free time, but at some point I needed to draw
the line and vendor the package.  It's still ~10x faster than the
existing one:

    In [1]: import qiskit.qasm2
       ...: prog = """
       ...:     OPENQASM 2.0;
       ...:     include "qelib1.inc";
       ...:     qreg q[2];
       ...: """
       ...: prog += "rz(pi * 2) q[0];\ncx q[0], q[1];\n"*100_000
       ...: %timeit qiskit.qasm2.loads(prog)
       ...: %timeit qiskit.QuantumCircuit.from_qasm_str(prog)
    2.26 s ± 39.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    22.5 s ± 106 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

`cx`-heavy programs like this one are actually the ones that the new
parser is (comparatively) slowest on, because the construction time of
`CXGate` is higher than most gates, and this dominates the execution
time for the Rust-based parser.

* Work around docs failure on Sphinx 5.3, Python 3.9

The version of Sphinx that we're constrained to use in the docs build
can't handle the `Unpack` operator, so as a temporary measure we can
just relax the type hint a little.

* Remove unused import

* Tweak documentation

* More specific PyO3 usage

* Use PathBuf directly for paths

* Format

* Freeze dataclass

* Use type-safe id types

This should have no impact on runtime or on memory usage, since each of
the new types has the same bit width and alignment as the `usize` values
they replace.

* Documentation tweaks

* Fix comments in lexer

* Fix lexing version number with separating comments

* Add test of pathological formatting

* Fixup release note

* Fix handling of u0 gate

* Credit reviewers

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>

* Add test of invalid gate-body statements

* Refactor custom built-in gate definitions

The previous system was quite confusing, and required all accesses to
the global symbol table to know that the `Gate` symbol could be present
but overridable.  This led to confusing logic, various bugs and
unnecessary constraints, such as it previously being (erroneously)
possible to provide re-definitions for any "built-in" gate.

Instead, we keep a separate store of instructions that may be redefined.
This allows the logic to be centralised to only to the place responsible
for performing those overrides, and remains accessible for error-message
builders to query in order to provide better diagnostics.

* Credit Sasha

Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>

* Credit Matthew

Co-authored-by: Matthew Treinish <mtreinish@kortar.org>

* Remove dependency on `lazy_static`

For a hashset of only 6 elements that is only checked once, there's not
really any point to pull in an extra dependency or use a hash set at
all.

* Update PyO3 version

---------

Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
Co-authored-by: Kevin Hartman <kevin@hart.mn>
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
2023-04-12 16:00:54 +00:00
dependabot[bot] aacbc665d8
Bump pyo3 from 0.18.1 to 0.18.2 (#9854)
Bumps [pyo3](https://github.com/pyo3/pyo3) from 0.18.1 to 0.18.2.
- [Release notes](https://github.com/pyo3/pyo3/releases)
- [Changelog](https://github.com/PyO3/pyo3/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pyo3/pyo3/compare/v0.18.1...v0.18.2)

---
updated-dependencies:
- dependency-name: pyo3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 19:13:15 +00:00
Jake Lishman 5a9d04156c
Remove useless `into_iter()` on `Range` (#9806)
Clippy has started complaining about this on the stable branch, and it's
probably correct to do so.
2023-03-16 18:50:07 +00:00
Matthew Treinish bbd023b5e1
Leverage Rust circuit sequence construction for `OneQubitEulerDecomposer` (#9583)
* Leverage Rust circuit sequence construction for OneQubitEulerDecomposer

This commit is a follow-up to #9578 which added a rust implementation
of the second half of the single qubit euler decomposition routines and
leveraged them for the Optimize1qGatesDecomposition transpiler pass.
With that PR the Optimize1qGatesDecomposition no longer was dependent on
the OneQubitEulerDecomposer class. This commit continues from that PR
and updates the OneQubitEulerDecomposer to leverage the same Rust
implementation internally. Calling a decomposer object will internally
call the rust function to generate a circuit sequence and then return
either a QuantumCircuit or DAGCircuit (depending on the options).
Similarly all the angle computation is done directly in Rust.

* Add missing atol clamping to mod_2pi

The python version of the OneQubitEulerDecomposer class had atol
clamping on it's output from mod_2pi, when this function was ported to
rust this was not included. At the time it was because nothing set the
atol parameter when calling mod_2pi (the angle calculation in #9185 did
not have atol and the expansion to construct circuits for
Optimize1qGatesDecomposition always used the default value). However,
now that we're expanding OneQubitEulerDecomposer to internally do all
the calculations in rust we need to support an adjustable atol which
includes the missing endpoint clamping in mod_2pi. This commit adds this
missing functionality to the function.

* Add docstring to mod_2pi rust function

* Remove mod_2pi python function
2023-03-16 18:44:44 +00:00
Jake Lishman c6cd0d577b
Add structure for multiple Rust crates (#9742)
* Add structure for multiplie Rust extension crates

This is a precursor to adding an entirely separate and self-contained
crate to handle parsing of OpenQASM 2 (not 3 - this is kind of like a
trial run for that).  It could conceivably still live within
`qiskit._accelerate`, but having separate crates helps us enforce more
sane API barriers, and has improvements in the incremental build time
when working on only one of the Rust extensions.

The intent after this commit is still to have `qiskit._accelerate` as an
easy catch-all for accelerators for Python.  Developers should not need
to be concerned with defining a new crate for every new feature, and for
the most part `_accelerate` is still logically interoperative within
itself (for example, `NLayout` is used all over).  This is just laying
out the groundwork so more complex crate additions _can_ also be made.

Some of the niceties to do with Cargo workspaces only became stabilised
in Rust 1.64.  In particular, inheritance from the workspace root for
things like the package version, Rust version, and dependencies only
came in then.  For now, the `workspace.packages` key in the root
`Cargo.toml` is ignored with a small warning during the build, but I've
put it in place mostly to keep track of what we can change once the MSRV
becomes 1.64 or greater (likely not til at least Terra 0.26).

* Add README.md to crates/accelerate

* Correct licence metadata
2023-03-07 23:12:39 +00:00