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

clean up Bit._register and Bit._index #44

Open
wants to merge 596 commits into
base: fixes/10744/1
Choose a base branch
from
Open

Conversation

1ucian0
Copy link
Owner

@1ucian0 1ucian0 commented Nov 2, 2023

Summary

On top of Qiskit#10996

Details and comments

Cleaning up Bit._register and Bit._index is hard.

@1ucian0 1ucian0 changed the title clean up Bit._register clean up Bit._register and Bit._index Nov 2, 2023
aeddins-ibm and others added 28 commits April 18, 2024 14:52
* add _evolve_ecr()

- Adds support for Pauli (and related classes) to evolve through ECR gates encountered in a quantum circuit.
- Also moved the dicts of special-case gates (`basis_1q`, `basis_2q`, `non-clifford`) outside the subroutine definition. They are now just after the `_evolve_*()` functions they reference.

* fix pauli.evolve bug for certain circuit names

- Should fix qiskit issue Qiskit#12093
- Bug happened after converting circuit to instruction, which AFAICT was not necessary. Now if input is a QuantumCircuit, that part of the code is bypassed.
- Removed creation of a look-up dict of bit locations, since `QuantumCircuit.find_bit` already provides one.

* add ECRGate to `evolve()` tests

* mark gate-dicts as private

* add test evolving by circuit named 'cx'

Test showing issue Qiskit#12093 is solved.

* add release note for pauli-evolve fixes

* Update test_pauli_list.py
Qiskit#12214)

This commit updates the documentation for the
generate_preset_pass_manager() function to clearly indicate that the
function will accept a integer list for the initial_layout field. This
already was supported but it wasn't documented. As it's now a documented
part of the API a unittest is added to ensure we don't regress this
functionality in the future.

Fixes Qiskit#11690
`num_custom_gates` is not actually part of the `CIRCUIT_HEADER` structs
in any version of QPY.  The number of custom-instruction objects is
instead stored as a `uint64_t` inline in the `CUSTOM_DEFINITIONS` part
of the file, so separately to the rest of the header.
This commit removes the use of intermediate DAGCircuit objects and
calling substitute_node_with_dag() in the Optimize1qGatesDecomposition
pass. Since everything is 1q it's very easy to just directly insert the
nodes on the DAG prior to the run and then remove the old nodes. This
avoids a lot of extra operations and overhead to create a second dagcircuit
for each identified run and then substiting that dag in place of the
run.
* fix docstring

* import

* exposing additional plugin arguments

* tests

* lint

* release notes
* add mapping features to data_bin

* Update qiskit/primitives/containers/data_bin.py

Co-authored-by: Ian Hincks <[email protected]>

* add values

* change iterable with list

* Update qiskit/primitives/containers/data_bin.py

Co-authored-by: Ian Hincks <[email protected]>

* Apply suggestions from code review

Co-authored-by: Christopher J. Wood <[email protected]>

* reno

* change return types

---------

Co-authored-by: Ian Hincks <[email protected]>
Co-authored-by: Christopher J. Wood <[email protected]>
* Increase heuristic effort for optimization level 2

This commit tweaks the heuristic effort in optimization level 2 to be
more of a middle ground between level 1 and 3; with a better balance
between output quality and runtime. This places it to be a better
default for a pass manager we use if one isn't specified. The
tradeoff here is that the vf2layout and vf2postlayout search space is
reduced to be the same as level 1. There are diminishing margins of
return on the vf2 layout search especially for cases when there are a
large number of qubit permutations for the mapping found. Then the
number of sabre trials is brought up to the same level as optimization
level 3. As this can have a significant impact on output and the extra
runtime cost is minimal. The larger change is that the optimization
passes from level 3. This ends up mainly being 2q peephole optimization.
With the performance improvements from Qiskit#12010 and Qiskit#11946 and all the
follow-on PRs this is now fast enough to rely on in optimization level
2.

* Add test workaround from level 3 to level 2 too

* Expand vf2 call limit on VF2Layout

For the initial VF2Layout call this commit expands the vf2 call limit
back to the previous level instead of reducing it to the same as level 1.
The idea behind making this change is that spending up to 10s to find a
perfect layout is a worthwhile tradeoff as that will greatly improve the
result from execution. But scoring multiple layouts to find the lowest
error rate subgraph has a diminishing margin of return in most cases as
there typically aren't thousands of unique subgraphs and often when we
hit the scoring limit it's just permuting the qubits inside a subgraph
which doesn't provide the most value.

For VF2PostLayout the lower call limits from level 1 is still used. This
is because both the search for isomorphic subgraphs is typically much
shorter with the vf2++ node ordering heuristic so we don't need to spend
as much time looking for alternative subgraphs.

* Move 2q peephole outside of optimization loop in O2

Due to potential instability in the 2q peephole optimization we run we
were using the `MinimumPoint` pass to provide backtracking when we reach
a local minimum. However, this pass adds a significant amount of
overhead because it deep copies the circuit at every iteration of the
optimization loop that improves the output quality. This commit tweaks
the O2 pass manager construction to only run 2q peephole once, and then
updates the optimization loop to be what the previous O2 optimization
loop was.
* Remove FakeBackendV2

* Fix lint
…2145)

* Provider abstraction is not very useful

* udpate docs

* ignore deprecations

* not triggered on CI

* deprecation warnings in visual tests

* set up

* set up without warning?

* setUpClass

* more test adjust

* raise at setUpClass

* warms

* test_circuit_matplotlib_drawer.py

* skip Aer warning

* Apply suggestions from code review

Co-authored-by: Matthew Treinish <[email protected]>

* reno

* Run black

* Update release note

* linter

---------

Co-authored-by: Matthew Treinish <[email protected]>
* adding annotated argument to power methods

* release notes

* Apply suggestions from code review

---------

Co-authored-by: Matthew Treinish <[email protected]>
This class is hard to make the most efficient, due to how abstract the
base class is, with many different options and many private methods that
subclasses override.  Still, in cases where, _at the point of build_, we
can detect that rotation or entanglement layers are simple applications
of a single standard-library gate, we can skip the entire `copy` +
`assign` + `compose` pipeline and simply construct the gates in-place
with the correct parameters.  This skips huge tracts of overhead that
using the high-level, abstract interfaces (which are somewhat
necessarily more optimised to work with large operands) in tight inner
loops adds, culminating in about a 10x improvement in build time.

`NLocal` is so abstract that it's hard to hit similar performance to an
idiomatic direct construction of the relevant structure, but to be fair,
the concept of a circuit library is not necessarily to make the absolute
fastest constructors for tight loops, but to make it much simpler to
just get a circuit that works as intended.
…t_barriers`` (Qiskit#11878)

* deprecate args show_idle and show_barrier

* reno

* Update qiskit/visualization/timeline/interface.py

Co-authored-by: Matthew Treinish <[email protected]>

* pending=True

---------

Co-authored-by: Matthew Treinish <[email protected]>
* fix mid-circuit measure problem

* Update qiskit/transpiler/passes/scheduling/base_scheduler.py

Co-authored-by: Naoki Kanazawa <[email protected]>

* Update releasenotes/notes/add-scheduler-warnings-da6968a39fd8e6e7.yaml

Co-authored-by: Naoki Kanazawa <[email protected]>

* Update qiskit/transpiler/passes/scheduling/base_scheduler.py

Co-authored-by: Naoki Kanazawa <[email protected]>

* Move runtime warning about reset and measurement durations outside of calibration if statement

* Replace raise with warn

* Switch import orders

---------

Co-authored-by: Naoki Kanazawa <[email protected]>
* consolidate circuits with the same number of shots

* update BackendEstimatorV2

* add job size limit tests

* Apply suggestions from code review

Co-authored-by: Ian Hincks <[email protected]>

* fix errors

* refactor

* revise comments

* reno

* fix an error

---------

Co-authored-by: Ian Hincks <[email protected]>
* adding note for nested-min-max for linting

* updating note for nested-min-max for linting
…skit#12109)

* Add support for returning a DAGCircuit to TwoQubitBasisDecomposer

This commit adds a new flag, use_dag, to the constructor for the
TwoQubitBasisDecomposer. When set to True, the __call__ method will
return a DAGCircuit instead of a QuantumCircuit. This is useful when the
two qubit basis decomposer is called from within a transpiler context,
as with the UnitarySynthesis pass, to avoid an extra conversion step.

* Pivot to argument on __call__ and add to XXDecomposer too

This commit moves the use_dag flag to the __call__ method directly
instead of storing it as an instance variable. To make the interface
consistent between the 2 built-in decomposers the flag is also added to
the XXDecomposer class's __call__ method too. This was needed because
the unitary synthesis pass calls the decomposers interchangeably and to
be able to use them without type checking they both will need the flag.
…h `BackendV2Converter` (Qiskit#11996)

* Convert to V2 inside transpile, deal with small changes in tests.

* Fix lint

* Add reno and apply comment from Ray's review
* Finalise support for Numpy 2.0

This commit brings the Qiskit test suite to a passing state (with all
optionals installed) with Numpy 2.0.0b1, building on previous commits
that handled much of the rest of the changing requirements:

- Qiskitgh-10890
- Qiskitgh-10891
- Qiskitgh-10892
- Qiskitgh-10897
- Qiskitgh-11023

Notably, this commit did not actually require a rebuild of Qiskit,
despite us compiling against Numpy; it seems to happen that the C API
stuff we use via `rust-numpy` (which loads the Numpy C extensions
dynamically during module initialisation) hasn't changed.

The main changes are:

- adapting to the changed `copy=None` and `copy=False` semantics in
  `array` and `asarray`.
- making sure all our implementers of `__array__` accept both `dtype`
  and `copy` arguments.

Co-authored-by: Lev S. Bishop <[email protected]>

* Update `__array__` methods for Numpy 2.0 compatibility

As of Numpy 2.0, implementers of `__array__` are expected and required
to have a signature

    def __array__(self, dtype=None, copy=None): ...

In Numpys before 2.0, the `copy` argument will never be passed, and the
expected signature was

    def __array__(self, dtype=None): ...

Because of this, we have latitude to set `copy` in our implementations
to anything we like if we're running against Numpy 1.x, but we should
default to `copy=None` if we're running against Numpy 2.0.

The semantics of the `copy` argument to `np.array` changed in Numpy 2.0.
Now, `copy=False` means "raise a `ValueError` if a copy is required" and
`copy=None` means "copy only if required".  In Numpy 1.x, `copy=False`
meant "copy only if required".  In _both_ Numpy 1.x and 2.0,
`ndarray.astype` takes a `copy` argument, and in both, `copy=False`
means "copy only if required".  In Numpy 2.0 only, `np.asarray` gained a
`copy` argument with the same semantics as the `np.array` copy argument
from Numpy 2.0.

Further, the semantics of the `__array__` method changed in Numpy 2.0,
particularly around copying.  Now, Numpy will assume that it can pass
`copy=True` and the implementer will handle this.  If `copy=False` is
given and a copy or calculation is required, then the implementer is
required to raise `ValueError`.  We have a few places where the
`__array__` method may (or always does) calculate the array, so in all
these, we must forbid `copy=False`.

With all this in mind: this PR sets up all our implementers of
`__array__` to either default to `copy=None` if they will never actually
need to _use_ the `copy` argument within themselves (except perhaps to
test if it was set by Numpy 2.0 to `False`, as Numpy 1.x will never set
it), or to a compatibility shim `_numpy_compat.COPY_ONLY_IF_NEEDED` if
they do naturally want to use it with those semantics.  The pattern

    def __array__(self, dtype=None, copy=_numpy_compat.COPY_ONLY_IF_NEEDED):
        dtype = self._array.dtype if dtype is None else dtype
        return np.array(self._array, dtype=dtype, copy=copy)

using `array` instead of `asarray` lets us achieve all the desired
behaviour between the interactions of `dtype` and `copy` in a way that
is compatible with both Numpy 1.x and 2.x.

* fixing numerical issues on mac-arm

* Change error to match Numpy

---------

Co-authored-by: Lev S. Bishop <[email protected]>
Co-authored-by: Sebastian Brandhofer <[email protected]>
Previously the module of this was set incorrectly (stemming from its
move in Qiskitgh-9064), at which point the `__getstate__`/`__setstate__`
pickling wouldn't work correctly any more.  Also, however, there was no
`__getnewargs__` and `new` didn't have a zero-argument form, so this
wouldn't have worked either.
* extend clifford docs

* mimor fix

* minor fix

* update docs following comment

* update following review
)

* removing use-dict-literal from lint exclusions and updates

* removing unnecessary destructuring and restructuring in test_result.py
* Add QPY format version table to the docs

This commit adds a new table to the QPY module docs that outlines all
the supported QPY format versions for every qiskit/qiskit-terra release
that had qpy. This information is potentially useful when trying to
navigate generating QPY files across versions.

Fixes Qiskit#12283

* Update qiskit/qpy/__init__.py
* Add Rust-based `SparsePauliOp.to_matrix`

This rewrites the numerical version of `SparsePauliOp.to_matrix` to be
written in parallelised Rust, building up the matrices row-by-row rather
than converting each contained operator to a matrix individually and
summing them.

The new algorithms are complete row-based, which is embarrassingly
parallel for dense matrices, and parallelisable with additional copies
and cumulative sums in the CSR case.

The two new algorithms are an asymptotic complexity improvement for both
dense and sparse matrices over the "sum the individual matrices"
version.  In the dense case, the cost goes from

        O(4 ** num_qubits * num_ops)

to

        O(4 ** num_qubits + (2 ** num_qubits) * reduced_num_ops)

where the first term is from the zeroing of the matrix, and the second
is from updating the elements in-place.  `reduced_num_ops` is the number
of explicitly stored operations after Pauli-operator uniqueness
compaction, so is upper-bounded as `4 ** num_qubits`.  (The Pauli
compaction goes as `O(num_ops)`, so is irrelevant to the complexity
discussion.) The CSR form of the algorithm goes as

        O(2 ** num_qubits * reduced_num_ops * lg(reduced_num_ops))

which (I think! - I didn't fully calculate it) is asymptotically the
same as before, but in practice the constant factors and intermediate
memory use are *dramatically* reduced, and the new algorithm is
threadable with an additional `O(2 ** num_qubits * reduced_num_ops)`
intermediate memory overhead (the serial form has only
`O(reduced_num_ops)` memory overhead).

The `object`-coefficients form is left as-is to avoid exploding the
complexity in Rust space; these objects are already slow and unsuited
for high-performance code, so the effects should be minimal.

* Add non-blocking Miri to CI

As we begin to include more `unsafe` code in the Rust-accelerated
components, it is becoming more important for us to test these in an
undefined-behaviour sanitiser.  This is done in a separate CI job
because:

- we do not yet know how stable Miri will be, so we don't want to block
  on it.

- some dependencies need their version-resolution patching to
  Miri-compatible versions, but we want to run our regular test suites
  with the same versions of packages we will be building against.

* Parallelise cumulative nnz sum

This parallelises the previously serial-only cumulative sum of the
`indptr` array of number of non-zero entries at the end.  In practice, I
didn't actually see any change in performance from this, but
philosophically it feels like the right thing to do.

* Update Miri pin to later version of crossbeam-epohc

* Improve error handling and messages

* Simplify unnecessary match

* Add link to environment variable configuration

* Add link to Rayon plumbing README

* Add explicit test of serial and parallel modes
* add permutation reverse lnn function

* update init files

* update other synthesis functions

* add tests

* add release notes

* add helper function _append_reverse_permutation_lnn_kms

* add more cases to test
1ucian0 and others added 30 commits July 11, 2024 11:27
)

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 Qiskit#11677
Part of Qiskit#12156
* Update generic_backend_v2.py

* reno

* Update barebone-backend-option-675c86df4382a443.yaml

* ...

* suggestions from code review

* Update barebone-backend-option-675c86df4382a443.yaml

* tests, typo
* add clifford gates to collect_cliffords

* replace hard coded clifford names by clifford_circuit names

* move import

* replace hard coded clifford names in random_clifford_circuit

* add release notes

* add permutation to collect_clifford gate 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
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.61 to 1.0.62.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](dtolnay/thiserror@1.0.61...1.0.62)

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

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add: `iter()` method to `CircuitData`
- Make `PackedInstruction` public.

* Docs: Remove "rust-native method" from docstring.
* 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.
* 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 Qiskit#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
* 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
…iskit#12772)

* Optimization for the MCX Recursive Gate

Change the recursive method for the Lemma 9 of arXiv:1501.06911, first shown in Lemma 7.3 of https://link.aps.org/doi/10.1103/PhysRevA.52.3457

Co-Authored-By: Rafaella Vale <[email protected]>
Co-Authored-By: Jefferson Deyvis <[email protected]>

* Revert "Optimization for the MCX Recursive Gate"

This reverts commit 507d5b3.

Co-Authored-By: Rafaella Vale <[email protected]>
Co-Authored-By: Jefferson Deyvis <[email protected]>

* Revert "Revert "Optimization for the MCX Recursive Gate""

This reverts commit 4671b7e.

* Optimization for MCX Recursive

Fixing co-authors

Co-Authored-By: Rafaella Vale <[email protected]>
Co-Authored-By: Jefferson Deyvis <[email protected]>
Co-Authored-By: Adenilton Silva <[email protected]>

* Optimization of MCX Recursive

Now with fixed co-authors

Co-Authored-By: Rafaella Vale <[email protected]>
Co-Authored-By: Jefferson Deyvis <[email protected]>
Co-Authored-By: Adenilton Silva <[email protected]>

* refactored MCXRecursive and unused method deleted

* fixed qasm string for mcx test with variants

* remove draw

* fix qasm file in test_circuit_qasm_with_mcx_gate_variants

* update the MCXRecursive class docstring

* add a test of the upper bound limit of the number of CX gates

* fix failing qasm test

* fix qasm file in test_export in qasm2 tests

* fix format lint errors in qasm strings

* add release notes

* update references format

* update release notes after review

---------

Co-authored-by: Thiago Melo <[email protected]>
Co-authored-by: Rafaella Vale <[email protected]>
Co-authored-by: Jefferson Deyvis <[email protected]>
Co-authored-by: Adenilton Silva <[email protected]>
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.62 to 1.0.63.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](dtolnay/thiserror@1.0.62...1.0.63)

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

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
)

* riverlane paper

* docs

* improvement

* empty

* fix linting and add abs

* Update qiskit/primitives/backend_estimator_v2.py

Co-authored-by: Takashi Imamichi <[email protected]>

* CR

* Update qiskit/primitives/backend_estimator_v2.py

Co-authored-by: Ian Hincks <[email protected]>

* CR

* indent

* Update releasenotes/notes/backend-estimator-v2-variance-905c953415ad0e29.yaml

Co-authored-by: Takashi Imamichi <[email protected]>

---------

Co-authored-by: Takashi Imamichi <[email protected]>
Co-authored-by: Ian Hincks <[email protected]>
* added circuit functions

* updated circuits functions

* added qasm files

* added benchmarking metrics

* cleaning up circuits

* updated tests

* updated tests

* formatting

* removed unused import

* clifford synthesis circ test

* lint test
* initial commit

* release notes

* fixing synthesis plugin options

* finalize merge conflicts

* fixing default option values for qft plugins'

* additional tests for qft plugins

* starting to experiment

* porting code

* messy code porting

* printing statements to enable debugging

* fixes

* fixing phase

* removing some of the printing statements

* fixing inaccuracy for cost computation

* Moving some of the functionality to SymplecticMatrix class

* reducing the number of warnings

* formatting

* replacing expensive adjoint and compose operations for symplectic matrices by significantly cheaper in-place prepend operations

* resolving merge conflicts

* cleanup

* code cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* cleanup

* using fast lookup

* cleanup

* clippy

* including params in gate_seq to avoid mapping

* removing unnecessary inner function

* cleanup

* renaming

* changes on the python side

* reno

* adding error handling

* improved error handling

* removing redundant Ok(Some(...))

* using random_clifford in tests

* reorganizing clifford code

* fixes

* formatting

* improved error handling

* do not panic

* formatting

* Applying refactoring suggestions d/utils.rs from code review

* release notes update

* starting to port code

* continuing to port code

* porting + fixing

* polishing

* changes on the python side; modifying tests to include missing testcases and to use random_clifford instead of random_clifford_circuit since the former provides better randomness guarantees

* release notes (last but not least)

* Correct reported speedups

* applying suggestion from code review

* resolving even more merge conflicts
* Rewrite OpenQASM 3 exporter symbol table

This rewrites the symbol handling of the OpenQASM 3 exporter to decouple
object identities from the necessary object identifiers.  As part of
this, we use the same trick of standard-gate reparametrisation to
produce gate-definition sources for Qiskit built-ins, which fixes many
cases of bad parametrisation of gates like `rzx`.

This kind of rewrite was necessary to fix the now-bad assumption within
the OQ3 exporter that "gate identity" is always static within a circuit.
Since standard gate `Gate` instances are now only generated on demand,
there is no guarantee of stability of them.  The fix to the definition
source for these makes them independent of object identity.
User-defined gates can still use the identity, as these are still
guaranteed static.

This commit fixes almost all of the "bad parametrisation" tests in the
test suite.  There are several other changes in the test suite
necessary:

* since the uniqueness of the identifier is now independent of how the
  lookup of a Qiskit object works, there is no need to include the
  highly non-deterministic `id` in the generated symbols for user gates.
  Several tests changed to use the new, simple count-based unique names.

* the escaping and uniqueness rules now apply uniformly to all gate
  definitions, fixing several bad test cases that previously were
  testing invalid OpenQASM 3.

* the escaping rules changed slightly for naming collisions with
  keywords, making them slightly more consistent with how other renaming
  rules worked.

* Add test for bug fix for issue Qiskit#7335

* Rename qiskit gates whose names are OQ3 hardware qubit identifiers

If a custom qiskit gate is given a name that is a valid identifer for a
hardware qubit in OQ3, then, before this commit, the name would not be
escaped when writing the OQ3 gate definition.

This commit fixes this by escaping the leading dollar sign as it would
be in any other position in the name. That is, the dollar sign is
replaced by underscore.

Co-authored-by: Jake Lishman <[email protected]>

* Reduce overloading of word "definition"

Much of what we're doing with the "definition source" is actually a form
of object canonicalisation for comparison purposes.  It's clearer to use
this terminology.

* Remove unnecessary getattr

* Fix isinstance/issubclass naming

---------

Co-authored-by: John Lapeyre <[email protected]>
* Validate order kwarg in BitArray

* Added releasenotes for bugfix

* Added pytest to check order

* Reformatted files

* Update releasenotes/notes/fix-kwarg-validation-BitArray-1bf542a1fb5c15c6.yaml

Co-authored-by: Takashi Imamichi <[email protected]>

---------

Co-authored-by: Takashi Imamichi <[email protected]>
* added functionality for porting

* updated functionality

* formatting

* lint changes

* resolved error

* updated docstring

* formatting

* formatting
* Update version of OpenQASM 3.0 standard library

This is just a file vendored from the OpenQASM project, but it's been
updated since the last time we vendored it to fix a couple of problems.
This one is vendored from openqasm/openqasm@4ca1d793833b24a1.

* Clarify git link
* Add troubleshooting section to docs-build dev docs

There are a couple of known failure modes for the documentation build
that require additional setup.  This documents these, to consolidate the
knowledge.

* Update CONTRIBUTING.md

Co-authored-by: Elena Peña Tapia <[email protected]>

---------

Co-authored-by: Elena Peña Tapia <[email protected]>
* Rebalance `CircuitInstruction` and `PackedInstruction`

This is a large overhaul of how circuit instructions are both stored in
Rust (`PackedInstruction`) and how they are presented to Python
(`CircuitInstruction`).  In summary:

* The old `OperationType` enum is now collapsed into a manually managed
  `PackedOperation`.  This is logically equivalent, but stores a
  `PyGate`/`PyInstruction`/`PyOperation` indirectly through a boxed
  pointer, and stores a `StandardGate` inline.  As we expect the vast
  majority of gates to be standard, this hugely reduces the memory
  usage.  The enumeration is manually compressed to a single pointer,
  hiding the discriminant in the low, alignment-required bytes of the
  pointer.

* `PackedOperation::view()` unpacks the operation into a proper
  reference-like enumeration `OperationRef<'a>`, which implements
  `Operation` (though there is also a `try_standard_gate` method to get
  the gate without unpacking the whole enumeration).

* Both `PackedInstruction` and `CircuitInstruction` use this
  `PackedOperation` as the operation storage.

* `PackedInstruction` is now completely the Rust-space format for data,
  and `CircuitInstruction` is purely for communication with Python.

On my machine, this commit brings the utility-scale benchmarks to within
10% of the runtime of 1.1.0 (and some to parity), despite all the
additional overhead.

Changes to accepting and building Python objects
------------------------------------------------

* A `PackedInstruction` is created by copy constructor from a
  `CircuitInstruction` by `CircuitData::pack`.  There is no `pack_owned`
  (really, there never was - the previous method didn't take ownership)
  because there's never owned `CircuitInstruction`s coming in; they're
  Python-space interop, so we never own them (unless we clone them)
  other than when we're unpacking them.

* `PackedInstruction` is currently just created manually when not coming
  from a `CircuitInstruction`.  It's not hard, and makes it easier to
  re-use known intern indices than to waste time re-interning them.
  There is no need to go via `CircuitInstruction`.

* `CircuitInstruction` now has two separated Python-space constructors:
  the old one, which is the default and takes `(operation, qubits,
  clbits)` (and extracts the information), and a new fast-path
  `from_standard` which asks only for the standard gate, qubits and
  params, avoiding operator construction.

* To accept a Python-space operation, extract a Python object to
  `OperationFromPython`.  This extracts the components that are separate
  in Rust space, but joined in Python space (the operation, params and
  extra attributes).  This replaces `OperationInput` and
  `OperationTypeConstruct`, being more efficient at the extraction,
  including providing the data in the formats needed for
  `PackedInstruction` or `CircuitInstruction`.

* To retrieve the Python-space operation, use
  `CircuitInstruction::get_operation` or
  `PackedInstruction::unpack_py_op` as appropriate.  Both will
  cache and reuse the op, if `cache_pygates` is active.  (Though note
  that if the op is created by `CircuitInstruction`, it will not
  propagate back to a `PackedInstruction`.)

Avoiding operation creation
---------------------------

The `_raw_op` field of `CircuitInstruction` is gone, because `PyGate`,
`PyInstruction` and `PyOperation` are no longer pyclasses and no longer
exposed to Python.  Instead, we avoid operation creation by:

* having an internal `DAGNode::_to_circuit_instruction`, which returns a
  copy of the internal `CircuitInstruction`, which can then be used with
  `CircuitInstruction.replace`, etc.

* having `CircuitInstruction::is_standard_gate` to query from Python
  space if we should bother to create the operator.

* changing `CircuitData::map_ops` to `map_nonstandard_ops`, and having
  it only call the Python callback function if the operation is not an
  unconditional standard gate.

Memory usage
------------

Given the very simple example construction script:

```python
from qiskit.circuit import QuantumCircuit

qc = QuantumCircuit(1_000)
for _ in range(3_000):
    for q in qc.qubits:
        qc.rz(0.0, q)
    for q in qc.qubits:
        qc.rx(0.0, q)
    for q in qc.qubits:
        qc.rz(0.0, q)
    for a, b in zip(qc.qubits[:-1], qc.qubits[1:]):
        qc.cx(a, b)
```

This uses 1.5GB in max resident set size on my Macbook (note that it's
about 12 million gates) on both 1.1.0 and with this commit, so we've
undone our memory losses.  The parent of this commit uses 2GB.

However, we're in a strong position to beat 1.1.0 in the future now;
there are two obvious large remaining costs:

* There are 16 bytes per `PackedInstruction` for the Python-operation
  caching (worth about 180MB in this benchmark, since no Python
  operations are actually created).

* There is also significant memory wastage in the current
  `SmallVec<[Param; 3]>` storage of the parameters; for all standard
  gates, we know statically how many parameters are / should be stored,
  and we never need to increase the capacity.  Further, the `Param` enum
  is 16 bytes wide per parameter, of which nearly 8 bytes is padding,
  but for all our current use cases, we only care if _all_ the
  parameters or floats (for everything else, we're going to have to
  defer to Python).  We could move the discriminant out to the level of
  the parameters structure, and save a large amount of padding.

Further work
------------

There's still performance left on the table here:

* We still copy-in and copy-out of `CircuitInstruction` too much right
  now; we might want to make all the `CircuitInstruction` fields
  nullable and have `CircuitData::append` take them by _move_ rather
  than by copy.

* The qubits/clbits interner requires owned arrays going in, but most
  interning should return an existing entry.  We probably want to switch
  to have the interner take references/iterators by default, and clone
  when necessary.  We could have a small circuit optimisation where the
  intern contexts reserve the first n entries to use for an all-to-all
  connectivity interning for up to (say) 8 qubits, since the transpiler
  will want to create a lot of ephemeral small circuits.

* The `Param` vectors are too heavy at the moment; `SmallVec<[Param;
  3]>` is 56 bytes wide, despite the vast majority of gates we care
  about having at most one single float (8 bytes).  Dead padding is a
  large chunk of the memory use currently.

* Fix clippy in no-gate-cache mode

* Fix pylint unused-import complaints

* Fix broken assumptions around the gate model

The `compose` test had a now-broken assumption, because the Python-space
`is` check is no longer expected to return an identical object when a
standard gate is moved from one circuit to another and has its
components remapped as part of the `compose` operation.  This doesn't
constitute the unpleasant deep-copy that that test is preventing. A
custom gate still satisfies that, however, so we can just change the
test.

`DAGNode::set_name` could cause problems if it was called for the first
time on a `CircuitInstruction` that was for a standard gate; these would
be created as immutable instances.  Given the changes in operator
extraction to Rust space, it can now be the case that a standard gate
that comes in as mutable is unpacked into Rust space, the cache is some
time later invalidated, and then the operation is recreated immutably.

* Fix lint

* Fix minor documentation
* Use Rust gates for 2q unitary synthesis

This commit builds off of what Qiskit#12650 did for the 1q decomposer and
moves to using rust gates for the 2q decomposer too. This means that the
circuit sequence generation is using rust's StandardGate representation
directly instead of relying on mapping strings. For places where
circuits are generated (calling `TwoQubitWeylDecomposition.circuit()` or
or `TwoQubitBasisDecomposer.__call__` without the `use_dag` flag) the
entire circuit is generated in Rust and returned to Python.

* Run cargo fmt and black post rebase
* Move generate_preset_pass_manager to generate_preset_pass_manager.py

* Add top-level import and reno

* Apply suggestions from Matt's code review

Co-authored-by: Matthew Treinish <[email protected]>

* Add import path from qiskit.transpiler too

* Fix cyclic import issue

* Fix cyclic import issue in tools/pgo_scripts

* Address cyclic import issues. Reorder imports alphabetically when relevant.

* Fix docstring issue

* Update releasenotes/notes/add-generate-preset-pm-global-import-efb12f185f3f738b.yaml

Co-authored-by: Matthew Treinish <[email protected]>

---------

Co-authored-by: Matthew Treinish <[email protected]>
…it (Qiskit#12785)

* Deprecate accidentally public qc helper methods

* Fix lint

* Complete reno and add removal timeline

* Update qiskit/circuit/quantumcircuit.py

Co-authored-by: Julien Gacon <[email protected]>

* Update remaining docstrings and removal timeline.

* Trailing whitespace

---------

Co-authored-by: Julien Gacon <[email protected]>
* Oxidize TwoQubitDecomposeUpToDiagonal

This commit ports the TwoQubitDecomposeUpToDiagonal class from Python to
rust. This internal private class is used internally by the quantum
shannon decomposition code, and while not performance critical was
simple to port. One difference is while the original Python
implementation was a class, it acted more like a function in practice.
So the new rust version is exposed as a function.

Co-authored-by: Luciano Bello <[email protected]>
Co-authored-by: Elena Peña Tapia <[email protected]>
Co-authored-by: Sebastian Brandhofer <[email protected]>
Co-authored-by: Jake Lishman <[email protected]>
Co-authored-by: John Lapeyre <[email protected]>
Co-authored-by: Julien Gacon <[email protected]>
Co-authored-by: Eli Arbel <[email protected]>
Co-authored-by: Raynel Sanchez <[email protected]>
Co-authored-by: Henry Zou <[email protected]>
Co-authored-by: Shelly Garion <[email protected]>
Co-authored-by: Alexander Ivrii <[email protected]>

* Build circuit from rust

Since Qiskit#12459 recently merged we now have a mechanism to build a circuit
from rust. This commit updates the synthesis function to build the
circuit directly in rust instead of returning a circuit sequence and
building the circuit from Python. This should speed up the construction
substantially.

* Remove unused private Python class

This commit removes the Python implementation of the function. This is
now unused in Qiskit and was never a public class so nothing external
should be depending on it. Since it's not used we should just remove it.

* Remove unused import

* Calculate best_nbasis in unwrap_or_else()

---------

Co-authored-by: Luciano Bello <[email protected]>
Co-authored-by: Elena Peña Tapia <[email protected]>
Co-authored-by: Sebastian Brandhofer <[email protected]>
Co-authored-by: Jake Lishman <[email protected]>
Co-authored-by: John Lapeyre <[email protected]>
Co-authored-by: Julien Gacon <[email protected]>
Co-authored-by: Eli Arbel <[email protected]>
Co-authored-by: Raynel Sanchez <[email protected]>
Co-authored-by: Henry Zou <[email protected]>
Co-authored-by: Shelly Garion <[email protected]>
Co-authored-by: Alexander Ivrii <[email protected]>
* Fix oversight from Qiskit#12185 where two input parsing functions were not migrated from transpile to generate_preset_pm  with the others.

* Add fix to reno from Qiskit#12185
* linting

* linting...relax check for 3-qubit circuit

* update test docstrings

* black update

* bind RZZ to pi/2 if Rzz(theta) in basis

* Apply suggestions from code review

---------

Co-authored-by: Matthew Treinish <[email protected]>
* deprecate qobj and assemble

* reno

* shallow deprecation of assemble

* test.python.compiler.test_disassembler

* fakebackend pulse

* test.python.circuit.test_parameters

* PulseQobjInstruction  is used by GenericBackendV2

* test.python.scheduler.test_basic_scheduler

* test.python.result.test_result

* test.python.pulse.test_calibration_entries

* test.python.compiler.test_assembler

* test.python.transpiler.test_star_prerouting

* test.python.pulse.test_instruction_schedule_map

* test.python.providers.basic_provider.test_basic_simulator

* test.python.primitives.test_backend_sampler_v2

* test.python.compiler.test_disassembler

* test.python.compiler.test_compiler

* test.python.circuit.test_scheduled_circuit

* test.python.providers.test_fake_backends

* test.python.circuit.test_unitary

* test.python.transpiler.test_sabre_swap

* test.python.providers.fake_provider.test_fake_backends

* Aer using Provider ABC

* aer warnings

* reno

* another pass on reno

* test.python.pulse

* test.python.compiler.test_compiler

* add module to fiterwarning

* test.python.compiler.test_transpiler

* fixing obscure expcetion handleing for comparison

* Apply suggestions from code review

Co-authored-by: Elena Peña Tapia <[email protected]>

* remove catch

* new deprecate warning message

* lint qiskit/assembler/assemble_circuits.py

* concurrency warnings

* ignore aer warnings

* Update test/python/providers/fake_provider/test_fake_backends.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* Update test/python/circuit/test_parameters.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* Update qiskit/providers/models/pulsedefaults.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* Update test/python/providers/fake_provider/test_fake_backends.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* Update test/python/providers/fake_provider/test_generic_backend_v2.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* lint

* Qiskit#12649 (comment)

* Qiskit#12649 (comment)

* Update test/python/transpiler/test_sabre_swap.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* Update qiskit/providers/models/pulsedefaults.py

Co-authored-by: Elena Peña Tapia <[email protected]>

* ignore Treating CircuitInstruction...

* another unnecessary catch from aer

* another unnecessary catch from aer, again

* removing more unnecesary catches

---------

Co-authored-by: Elena Peña Tapia <[email protected]>
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.