* Fix pass-manager drawing tests for pydot 3.0
Two changes in pydot 3 changed the reference output:
1. previously, attributes were sorted before being output. Pydot 3
stores them in declaration order. Here, we sort our attributes to
maintain the closest behaviour between the two versions.
2. Text fields (like `label`) that contain special characters now have
their values enclosed in quote marks. This is a difference between
the two versions, and we update the reference files to the new
version since that's what we'll be using in CI.
Qiskit is still compatible with pydot 2 in general usage, it's just our
tests that are a little more tied to the current version.
* Add test-only constraint on pydot
* Oxidize two qubit local invariance functions
This commit migrates the two functions in the private module
`qiskit.synthesis.two_qubit.local_invariance` to primarily be
implemented in rust. Since the two_qubit_local_invariants() function is
being used in #12727 premptively porting these functions to rust will
both potentially speed up the new transpiler pass in that PR and also
facilitate a future porting of that pass to rust. The two python space
functions continue to exist as a small wrapper to do input type
checking/conversion and rounding of the result (since the python API for
rounding is simpler). There is no release note included for these
functions as they are internal utilities in Qiskit and not exposed as a
public interface.
* Add docstring to rust function with citation
* Store adjoint magic array statically
* Use arraview1 instead of slice for local_equivalence()
* Fix rustfmt
* Add missing gate definitions
* Reorder gates, following number of qubits and a sort of alphabetical order. Make definitions and matrices consistent with new gate order. Remove C4XGate (second mcx) from list.
* remove some of the entries
* fixing obscure expcetion handleing for comparison
* remove all the modules
* ignore "Treating CircuitInstruction as an iterable is deprecated" in Aer
* remove allow_DeprecationWarning_module and revert ignore/default
* revert
This commit updates the minimum rustworkx version to 0.15.0 to pull in
the new PyDiGraph.remove_node_retain_edges_by_id() method introduced
in that release. This new function is used for the
DAGCircuit.remove_op_node() method instead of the
PyDiGraph.remove_node_retain_edges() function. This new method has much
better scaling characteristics and should improve the performance
characteristics of removing very wide operations from a DAGCircuit.
Fixes#11677
Part of #12156
This commit updates the BasisTranslator transpiler pass. It builds off
of #12692 and #12701 to adjust access patterns in the python transpiler
path to avoid eagerly creating a Python space operation object. The goal
of this PR is to mitigate the performance regression introduced by the
extra conversion cost of #12459 on the BasisTranslator.
* initial commit
* release notes
* fixing synthesis plugin options
* finalize merge conflicts
* fixing default option values for qft plugins'
* additional tests for qft plugins
* renaming QftGate to QFTGate
* Also renaming Qft to QFT in synthesis method names
* appplying Jake's suggestion from code review
* inlining _basic_definition into _define
* docstring improvements
* more docstring improvements
* renaming do_swaps to reverse_qubits in the new code
* typos
* adding synth_qft_full to __init__
* round of suggestions from code review
* another round of code review suggestions
* fixes
* also adding QFTGate plugins to the docs
* Use rust gates for ConsolidateBlocks
This commit moves to use rust gates for the ConsolidateBlocks transpiler
pass. Instead of generating the unitary matrices for the gates in a 2q
block Python side and passing that list to a rust function this commit
switches to passing a list of DAGOpNodes to the rust and then generating
the matrices inside the rust function directly. This is similar to what
was done in #12650 for Optimize1qGatesDecomposition. Besides being faster
to get the matrix for standard gates, it also reduces the eager
construction of Python gate objects which was a significant source of
overhead after #12459. To that end this builds on the thread of work in
the two PRs #12692 and #12701 which changed the access patterns for
other passes to minimize eager gate object construction.
* Add rust filter function for DAGCircuit.collect_2q_runs()
* Update crates/accelerate/src/convert_2q_block_matrix.rs
---------
Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
* Add C3X (MCX), extend rust tests to multi-controlled gates.
* Add macro to generate multi-controlled gates. Add CU, CU1, CU3, C3SX, C4X, CCZ.
* Kill C4XGate
* Finish adding gates, add circuit construction methods when possible.
* Add import paths, fix drawer test.
* Establish CGates with non-default control states as non-standard in circuit_instruction.rs. Add unit test.
* Fix merge conflicts
* Apply macro on missing gates
* Add RCCX gate and RC3X (RCCCX) gate.
* Make equivalence tests more explicit
* Fix lint
* Modify circuit methods for consistency
* Fix default ctrl state for 3q+ gates, add test for CCZ
* Apply comments from Matt's code review
* Fix ctrl_state logic
* Rename c3x to mcx?
* Brackets didn't match explanation
* Make sure controlled test doesn't use custom ControlledGate instances.
* Rename c4x to mcx in Rust space.
* Return PyResult rather than panic on error
* Add suggestion from Matt's code review
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
---------
Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
* [WIP] adds the output argument to the internal atomic evolution
* meta: modernize type hints
* refactor: change callable structure of atomic evolution
This changes the structure of the `atomic_evolution` callable in the
`ProductFormula` synthesis class. This is motivated by the significant
performance improvements that can be obtained by appending to the
existing circuit directly rather than building out individual evolution
circuits and iteratively composing them.
* refactor: deprecate the legacy atomic_evolution signature
* refactor: add the wrap argument to ProductFormula
This can be used to recover the previous behavior in which the single
individually evolved Pauli terms get wrapped into gate objects.
* fix: insert the missing barriers between LieTrotter repetitions
* refactor: align SuzukiTrotter and LieTrotter
* Propoagate deprecation notice
* fix: the labels of wrapped Pauli evolutions
* fix: respect the insert_barriers setting
* docs: add a release note
* Apply suggestions from code review
Co-authored-by: Julien Gacon <gaconju@gmail.com>
* fix: missing `wrap` forward in SuzukiTrotter
* docs: improve documentation of the `atomic_evolution` argument
Co-authored-by: Julien Gacon <gaconju@gmail.com>
* docs: also document the deprecated form of `atomic_evolution`
* docs: call out ProductFormula docs in release note
* refactor: change to PendingDeprecationWarning
* refactor: explicitly convert to Gate when wrapping
This is slightly faster than the `.compose`-based operation done
previously as it performs fewer checks. Thanks to @jakelishman for the
suggestion offline.
* Update qiskit/synthesis/evolution/lie_trotter.py
Co-authored-by: Julien Gacon <gaconju@gmail.com>
* docs: update after pending deprecation
---------
Co-authored-by: Julien Gacon <gaconju@gmail.com>
* Implement convert_index
This allows to convert a Python-like signed index into an unsigned index suitable in Rust notation.
* Jake's comments
- refactor PySeqIndex.with_len to use convert_idx
- cleanup the tests
* mock QISKIT_SETTINGS to avoid interfering with my own env
* set a dummy QISKIT_SETTINGS to avoid interfering with local env
* apply to all of them
* revert
In the recently merged #12650 a new rust function was added for the
filter function of the collect_1q_runs() method's internal filter
function. As part of this we need to do exclude any non-DAGOpNode dag
nodes passed to the filter function. This was previously implemented
using the pyo3 extract() method so that if the pyobject can be coerced
into a DAGOpNode for later use we continue but if it errors we know the
input object is not a DAGOpNode and return false. However, as we don't
need to return the error to python we should be using downcast instead
of extract (as per the pyo3 performance guide [1]) to avoid the error
conversion cost. This was an oversight in #12650 and I only used
extract() out of habit.
[1] https://pyo3.rs/v0.22.0/performance#extract-versus-downcast
* Accept Option<&str> instead of &Option<String>, etc
In a few places, this removes unnecessary object copies.
Accept a wider range of input types, and more idiomatic input types
in a few functions. This affects code added in the gates-in-rust PR.
The great majority of the changes here were obsoleted by #12594.
The original commit has been cherry picked on top of main.
* Remove unnecessary as_ref()
* Add warning about Tweedledum support in ClassicalFunction
* Update qiskit/circuit/classicalfunction/__init__.py
Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
* Update __init__.py
line break to comply to pylint
---------
Co-authored-by: Luciano Bello <bel@zurich.ibm.com>
* Avoid Python op creation in commutative cancellation
This commit updates the commutative cancellation and commutation
analysis transpiler pass. It builds off of #12692 to adjust access
patterns in the python transpiler path to avoid eagerly creating a
Python space operation object. The goal of this PR is to mitigate the
performance regression on these passes introduced by the extra
conversion cost of #12459.
* Remove stray print
* Don't add __array__ to DAGOpNode or CircuitInstruction
* Use rust gates for Optimize1QGatesDecomposition
This commit moves to using rust gates for the Optimize1QGatesDecomposition
transpiler pass. It takes in a sequence of runs (which are a list of
DAGOpNodes) from the python side of the transpiler pass which are
generated from DAGCircuit.collect_1q_runs() (which in the future should
be moved to rust after #12550 merges). The rust portion of the pass now
iterates over each run, performs the matrix multiplication to compute the
unitary of the run, then synthesizes that unitary, computes the
estimated error of the circuit synthesis and returns a tuple of the
circuit sequence in terms of rust StandardGate enums. The python portion
of the code then takes those sequences and does inplace substitution of
each run with the sequence returned from rust.
Once #12550 merges we should be able to move the input collect_1q_runs()
call and perform the output node substitions in rust making the full
pass execute in the rust domain without any python interaction.
Additionally, the OneQubitEulerDecomposer class is updated to use
rust for circuit generation instead of doing this python side. The
internal changes done to use rust gates in the transpiler pass meant we
were half way to this already by emitting rust StandardGates instead of
python gate objects. The dag handling is still done in Python however
until #12550 merges.
This also includes an implementation of the r gate, I temporarily added
this to unblock this effort as it was the only gate missing needed to
complete this. We can rebase this if a standalone implementation of the
gate merges before this.
* Cache target decompositions for each qubit
Previously this PR was re-computing the target bases to synthesize with
for each run found in the circuit. But in cases where there were
multiple runs repeated on a qubit this was unecessary work. Prior to
moving this code to rust there was already caching code to make this
optimization, but the rust path short circuited around this. This commit
fixes this so we're caching the target bases for each qubit and only
computing it once.
* Optimize rust implementation slightly
* Avoid extra allocations by inlining matrix multiplication
* Remove unnecessary comment
* Remove stray code block
* Add import path for rust gate
* Use rust gate in circuit constructor
* Remove duplicated op_name getter and just use existing name getter
* Apply suggestions from code review
Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
* Simplify construction of target_basis_vec
* Fix rebase issue
* Update crates/accelerate/src/euler_one_qubit_decomposer.rs
Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
* Update crates/accelerate/src/euler_one_qubit_decomposer.rs
---------
Co-authored-by: John Lapeyre <jlapeyre@users.noreply.github.com>
After the recently merged #12543 when working with Rust 1.79 cargo fmt
makes a small formatting change that rust 1.70 wouldn't and clippy makes
flags a &Vec<_> that should be a slice &[_] instead. This commit makes
these two small chagnes so they're not an issue for people building with
the latest stable version of rust, not just our MSRV.
* Avoid Python operation creation in transpiler
Since #12459 accessing `node.op` in the transpiler eagerly creates a
Python object on access. This is because we now are no longer storing a
Python object internally and we need to rebuild the object to return the
python object as expected by the api. This is causing a significant
performance regression because of the extra overhead. The longer term
goal is to move as much of the performance critical passes to operate in
rust which will eliminate this overhead. But in the meantime we can
mitigate the performance overhead by changing the Python access patterns
to avoid the operation object creation. This commit adds some new getter
methods to DAGOpNode to give access to the inner rust data so that we
can avoid the extra overhead. As a proof of concept this updates the
unitary synthesis pass in isolation. Doing this fixes the regression
caused by #12459 for that pass. We can continue this migration for
everything else in follow up PRs. This commit is mostly to establish the
pattern and add the python space access methods.
* Remove unused import
* Add path to avoid StandardGate conversion in circuit_to_dag
* Add fast path through dag_to_circuit
* Fix ' into `
* More typos on release notes and on API documentation
* change `self.filter` for `Schedule.filter`
* change `Schedule` -> `ScheduleBlock` in its `filter()` reference
- Expose `operation_type_to_py`, `operation_type_and_data_to_py`, `convert_py_to_operation_type`, methods to other rust crates.
- Expose `OperationTypeConstruct` struct to other crates.
* add warning for bad justify input in circuit_drawer
* change justify after raising error
* typo indentation + improving warning string
* Undo max_lenght limit by autoformater (120 > 105)
* Make lines fullfill 105 max lenght requirement
* Solve regex matching parenthesis problem and don't trigger the wanring for default value
* Change justify default value to "left", & add deprecation wrapper
* Change and extend warnings tests
* Solve various layers of same argument DeprecationWarning
* Added a clarification comment for the solution, about multiple deprecationwarnings
* Ignore cyclic import error, as above
* Apply suggestions from code review
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
* Apply suggestions from code review
* Improve DeprecationWarning readability, and fix warning checks tests
* Remove `_is_valid_justify_arg` from `@deprecate_arg`, for solving circular import
* in `deprecate_arg` change `since` to "1.2.0"
* black formater suggestion
* negate conditions for `predicate` in `@deprecate_arg`
* remove `pending=True`, since then warning is not raised
* change qiskit version on tests
* remove assert Regex for DeprecationWarning
* Add release note, and remove two undesired changes in imports
* changing release note naming from "_" to "-"
* Add extra line in the end, for lint
* Redid release file from start, with shorter name, and correct spacings
* Remove final spaces in all lines...
* Try without deprecations_visualization section..
* Solve, bad Sphinx spacing, go back to deprecations_visualization
* Go back to `None` as default value
* Simplifying deprecation logic
* Remove unused imports and changed missing default value
* Improve docstring for public methods
* Improve error readbility and testing of it with regex
---------
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
This encapsulates a lot of the common logic around Python sequence-like
indexers (`SliceOrInt`) into iterators that handle adapting negative
indices and slices in `usize` for containers of a given size.
These indexers now all implement `ExactSizeIterator` and
`DoubleEndedIterator`, so they can be used with all `Iterator` methods,
and can be used (with `Iterator::map` and friends) as inputs to
`PyList::new_bound`, which makes code simpler at all points of use.
The special-cased uses of this kind of thing from `CircuitData` are
replaced with the new forms. This had no measurable impact on
performance on my machine, and removes a lot noise from error-handling
and highly specialised functions.