├── 0001-ansatz-rfc ├── ansatz_rep.jpg └── ansatz_scheme.jpg ├── 0014-overhaul-qiskit-experiments ├── ex3_dag.png ├── ex4_dag.png ├── scaling.png ├── seq_diagram_current.png └── seq_diagram_proposed.png ├── 0005-Aqua_circuit_interoperability ├── output_7_0.png └── output_8_0.png ├── 0004-error-mitigation └── 202001_ErrorMitigation_summary.png ├── .github └── ISSUE_TEMPLATE │ └── rfc-implementation-epic.md ├── CODE_OF_CONDUCT.md ├── .gitignore ├── 0000-template.md ├── 0018-primitive-options-type.md ├── 0002-Aqua_0.7_release_priorities_and_plan.md ├── README.md ├── CONTRIBUTING.md ├── 0017-base-primitive-unification.md ├── 0009-interface-for-circuit-operations.md ├── 0013-algorithms-migration.md ├── LICENSE ├── 0011-repo-rename.md ├── 0004-error-mitigation.md ├── 0005-Aqua_circuit_interoperability.md ├── 0016-sampler-interface.md ├── 0012-Pulse-Compiler-and-IR.md ├── 0010-simple-classical-representations.md ├── 0020-release_cycle.md ├── 0008-unify-pulse-commands-and-instructions.md └── 0006-rfc-generalized-unroller-and-equivalence-library.md /0001-ansatz-rfc/ansatz_rep.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0001-ansatz-rfc/ansatz_rep.jpg -------------------------------------------------------------------------------- /0001-ansatz-rfc/ansatz_scheme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0001-ansatz-rfc/ansatz_scheme.jpg -------------------------------------------------------------------------------- /0014-overhaul-qiskit-experiments/ex3_dag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0014-overhaul-qiskit-experiments/ex3_dag.png -------------------------------------------------------------------------------- /0014-overhaul-qiskit-experiments/ex4_dag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0014-overhaul-qiskit-experiments/ex4_dag.png -------------------------------------------------------------------------------- /0014-overhaul-qiskit-experiments/scaling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0014-overhaul-qiskit-experiments/scaling.png -------------------------------------------------------------------------------- /0005-Aqua_circuit_interoperability/output_7_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0005-Aqua_circuit_interoperability/output_7_0.png -------------------------------------------------------------------------------- /0005-Aqua_circuit_interoperability/output_8_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0005-Aqua_circuit_interoperability/output_8_0.png -------------------------------------------------------------------------------- /0004-error-mitigation/202001_ErrorMitigation_summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0004-error-mitigation/202001_ErrorMitigation_summary.png -------------------------------------------------------------------------------- /0014-overhaul-qiskit-experiments/seq_diagram_current.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0014-overhaul-qiskit-experiments/seq_diagram_current.png -------------------------------------------------------------------------------- /0014-overhaul-qiskit-experiments/seq_diagram_proposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Qiskit/RFCs/HEAD/0014-overhaul-qiskit-experiments/seq_diagram_proposed.png -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/rfc-implementation-epic.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: RFC implementation epic 3 | about: Create an epic on an RFC implementation to track its progress 4 | title: 'Epic - Implementation of `RFC 0000`: ' 5 | labels: RFC implementation epic 6 | assignees: '' 7 | 8 | --- 9 | 10 | Tasks to implement `RFC 0000`: 11 | 12 | - [ ] Link to issue/PR 13 | - [ ] Link to issue/PR 14 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Code of Conduct 4 | All members of this project agree to adhere to the Qiskit Code of Conduct listed at [https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md](https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md) 5 | 6 | ---- 7 | 8 | License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), 9 | Copyright Contributors to Qiskit. 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *,cover 47 | .hypothesis/ 48 | test-output.html 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Scrapy stuff: 55 | .scrapy 56 | 57 | # PyBuilder 58 | target/ 59 | 60 | # IPython Notebook 61 | .ipynb_checkpoints 62 | 63 | # pyenv 64 | .python-version 65 | 66 | # virtualenv 67 | venv/ 68 | ENV/ 69 | 70 | # MkDocs documentation 71 | site/ 72 | 73 | # pdf 74 | *.pdf 75 | 76 | # PyCharm 77 | *.idea 78 | 79 | #Mac OS X 80 | .DS_Store 81 | -------------------------------------------------------------------------------- /0000-template.md: -------------------------------------------------------------------------------- 1 | # RFC Title 2 | 3 | | **Status** | **Proposed/Accepted/Deprecated** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | #### | 6 | | **Authors** | First Author (first.author@ibm.com), ... | 7 | | **Deprecates** | RFC that this RFC deprecates | 8 | | **Submitted** | YYYY-MM-DD | 9 | | **Updated** | YYYY-MM-DD | 10 | 11 | RFC markdown filename should be of the form `####-rfc-title.md`. Where #### will 12 | be set as `max(rfc_####) + 1` after the acceptance of the RFC, but before its 13 | merger. If the RFC requires supporting files, a folder may be created with the 14 | same name as the RFC, `####-rfc-title`, in which the RFC should reside. 15 | 16 | ## Summary 17 | One paragraph explanation of the feature. 18 | 19 | ## Motivation 20 | - Why are we doing this? 21 | - What will this enable? 22 | - What will be the outcome? 23 | - Who will benefit? 24 | 25 | ## User Benefit 26 | - Who are the target users of this work? 27 | - How will users or contributors benefit from the work proposed? 28 | 29 | ## Design Proposal 30 | This is the focus of the document. Explain the proposal from the perspective of 31 | educating another user on the proposed features. 32 | 33 | This generally means: 34 | - Introducing new concepts and nomenclature 35 | - Using examples to introduce new features 36 | - Implementation and Migration path with associated concerns 37 | - Communication of features and changes to users 38 | 39 | Focus on giving an overview of impact of the proposed changes to the target 40 | audience. 41 | 42 | Factors to consider: 43 | - Performance 44 | - Dependencies 45 | - Maintenance 46 | - Compatibility 47 | 48 | ## Detailed Design 49 | Technical reference level design. Elaborate on details such as: 50 | - Implementation procedure 51 | - If spans multiple projects cover these parts individually 52 | - Interaction with other features 53 | - Dissecting corner cases 54 | - Reference definition, eg., formal definitions. 55 | 56 | ## Alternative Approaches 57 | Discuss other approaches to solving this problem and why these were not 58 | selected. 59 | 60 | ## Questions 61 | Open questions for discussion and an opening for feedback. 62 | 63 | ## Future Extensions 64 | Consider what extensions might spawn from this RFC. Discuss the roadmap of 65 | related projects and how these might interact. This section is also an opening 66 | for discussions and a great place to dump ideas. 67 | 68 | If you do not have any future extensions in mind, state that you cannot think 69 | of anything. This section should not be left blank. 70 | -------------------------------------------------------------------------------- /0018-primitive-options-type.md: -------------------------------------------------------------------------------- 1 | # Primitive options type change 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0018 | 6 | | **Authors** | Jessie Yu (jessieyu@us.ibm.com) | 7 | | **Submitted** | 2023-10-20 | 8 | 9 | ## Summary 10 | 11 | This RFC proposes using Python and `pydantic` dataclasses as the object type of primitive options. This allows users to discover supported options without having to read the documentation. It also supports auto-complete, nested options in the `x.y` format, and field validation. 12 | 13 | ## Motivation 14 | 15 | `BasePrimitive` currently accept an `options` parameter of type `dict` to its constructor. The underlying expectation is that all options would be stored in this dictionary. However, due to the large number of options, both Qiskit Runtime and Qiskit Aer primitive implementations use a more structured approach. Transpiler options, for example, is specified via `transpile_options` in Aer and `options.transpilation.x` in Qiskit Runtime. 16 | 17 | While `BasePrimitive` takes a dictionary `options` as an input, its `options` property actually returns a `qiskit.providers.Options` instance, which is another inconsistency. There is little reason to use `qiskit.providers.Options`, which has a lot of complicated code designed to maintain backward compatibility with Qiskit Experiments. `qiskit.providers.Options` does allow setting of validators, but that feature is not used by any of known primitive implementations. 18 | 19 | In addition, there are features users requested around accessing options that this RFC wishes to address: 20 | - auto-complete, this can include nested auto-complete with `x.y` 21 | - an easy way to discover the different options for each primitive 22 | - validation on values 23 | - consistent way to specify the same options across different providers 24 | - the ability to specify experimental or undocumented options 25 | - the ability to make a copy of the options 26 | 27 | ## User Benefit 28 | 29 | All users of the primitives stand to benefit from this proposal. It will allow users to more easily discover available options, auto-complete field names, and get prompted for invalid values when specifying them. 30 | 31 | It will also decouple `qiskit.providers.Options` from primitives, if Qiskit wants to retire that class. 32 | 33 | ## Design Proposal 34 | 35 | 1. Use Python dataclass as the input/output type for primitive options. Dataclass allows auto-complete, and users can easily discover what fields are available. 36 | 37 | 2. The `options` property would return the dataclass, and a user can do `estimator.options.x`, to get/set the specific option. The users can also use the builtin `asdict` method to convert the dataclass to a dictionary if they wish. 38 | 39 | 2. Instead of a `set_options()` method attached to the primitive, the dataclass will have an `update()` method for bulk updates. 40 | 41 | 4. Providers that have more complex options, such as Qiskit Runtime, can use more advanced dataclass type such as the one in `pydantic`. 42 | 43 | 5. It is still up to each provider on how they want to support undocumented/experimental options. 44 | 45 | 46 | Per #51, we will start versioning the primitives. Therefore, no backward compatibility is needed, and the changes will only apply to v2 primitives. 47 | 48 | ## Detailed Design 49 | 50 | - `BasePrimitive` would accept either a dictionary or a dataclass for `options`. 51 | - A new `BasePrimitiveOptions` dataclass will serve as the base class, since there is no type hint for dataclasses. 52 | - `_options_class` class attribute is used to identify the dataclass the subclass wishes to use. 53 | - The `options` property wll return the dataclass. 54 | - The options dataclass will have a `update()` method for bulk update 55 | 56 | ```python 57 | from dataclasses import dataclass, replace 58 | 59 | @dataclass 60 | class BasePrimitiveOptions: 61 | 62 | test_attr: int = 1 63 | 64 | def update(self, **kwargs): 65 | for key, val in kwargs.items(): 66 | setattr(self, key, val) 67 | 68 | 69 | class BasePrimitiveV2: 70 | """Primitive abstract base class.""" 71 | 72 | _options_class = BasePrimitiveOptions 73 | 74 | def __init__(self, options: dict | BasePrimitiveOptions | None = None): 75 | if isinstance(options, dict): 76 | self.options = self._options_class(**options) 77 | elif options is None: 78 | self.options = self._options_class() 79 | else: 80 | self.options = options 81 | ``` 82 | 83 | ``` 84 | >>> base = BasePrimitive() 85 | >>> base.options.test_attr 86 | 1 87 | >>> base.options 88 | BasePrimitiveOptions(test_attr=1) 89 | >>> base.options.update(test_attr=2) 90 | >>> base.options.test_attr 91 | 2 92 | ``` 93 | 94 | ## Alternative Approaches 95 | 96 | An alternative considered was using `pydantic.BaseModel`. This class offers all the features Python dataclasses and pydantic dataclasses have, plus many useful methods, such as determining whether a field was explicitly set or defaulted to. 97 | 98 | Unfortunately, these useful methods would also show up when you attempt to do auto-complete and could cause confusion on which ones are the actual options. 99 | 100 | ## Questions 101 | 102 | 103 | ## Future Extensions 104 | -------------------------------------------------------------------------------- /0002-Aqua_0.7_release_priorities_and_plan.md: -------------------------------------------------------------------------------- 1 | # Aqua 0.7 Release Priorities and Plan 2 | 3 | | **Status** | **Deprecated** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0002 | 6 | | **Authors** | Donny Greenberg (donny@ibm.com) | 7 | | **Deprecates** | NA | 8 | | **Submitted** | 2019-12-04 | 9 | | **Updated** | 2023-05-10 | 10 | 11 | _Release target: 17-Mar-2020_ 12 | 13 | ## Design & Review Process 14 | 15 | Socialization and consensus of large project designs are critical for a decentralized software team to function, especially working on such complicated and diverse code as Aqua. For this release cycle, Aqua will follow a standard Design Doc+Design Review process. For large projects, owners are expected to write a design doc, book a 30 minute slot in design review, and present their design. Broader members of the software or research team to which a particular design is relevant should be invited to the review. Owners and teams should attempt not to begin investing time in code and systems which have not been socialized and agreed upon in review. 16 | 17 | ## Prioritized Features 18 | 19 | _If you are interested in joining any effort below, please reach out to [donny@ibm.com](mailto:donny@ibm.com) or to the project owner on Qiskit Slack._ 20 | 21 | ### Aqua Core Primitives Redesign - Algorithm, Operator, Ansatz, Circuits 22 | 23 | * QuantumAlgorithm Hierarchy - *Owner: Donny* 24 | * Base Classes for QuantumAlgorithms of common purpose (e.g. MinEigensolver) to relate interchangeable algorithms and enforce consistent methods and properties 25 | * Break up algorithms which rely on common code so each hold algorithm-primitive objects of more generic utility 26 | * Operator Refactor 2.0 - *Owner: Donny, Chris Wood* 27 | * Split Operator into Terra operators and ExpectationValue and Evolution Algorithms 28 | * Coordinate with LadderOperator addition in Chemistry 29 | * *Reach: Expectation Value Tomography reconciliation with Ignis Tomography* 30 | * Aer ExpectationValue RemoteAlgorithm 31 | * Laying the API groundwork for high priority RemoteAlgorithms (e.g. variational optimization, expectation values) 32 | * Ansatz (FKA: VariationalForm / FeatureMap) refactor - *Owner: Julien* 33 | * Hierarchy and structural flexibility: Ansatz Base Utility Class, TwoLocalAnsatz, OperatorEvolutionAnsatz 34 | * Individual parameter access to shared parameters in Ansatze 35 | * *Reach: Analytical Gradients expansion* 36 | * Circuit Primitives Redesign - *Owner: Julien* 37 | * Move arithmetic and primitive circuits into Terra, make into gates (including tests) 38 | * Deprecate Circuit Factories (blocked on Terra introducing controlled gates) 39 | * Replace QuantumRegister passing with Gate/Instruction passing across Aqua 40 | 41 | ### Improving Code Clarity and Navigability 42 | 43 | * JSON Removal - *Owner: Manoel* 44 | * Deprecation design 45 | * Implementation across Aqua and tutorials 46 | * Deprecation messages in code and GUI in minor version release (Dec 17) 47 | * Repository structure redesign - *Owner: Donny, Manoel* 48 | * Break out application-specific code into applications directories 49 | * Modify nomenclature and directory navigation to match user expectations and canonical conventions 50 | * Shard applications-specific components into applications stacks and move algorithmic primitives into the algorithm stack (e.g. QPE) 51 | * Documentation Revamp - *Owner: Steve, Manoel* 52 | * Long-term plan for Documentation and Docstrings 53 | * _Out of scope: full documentation rewrite_ 54 | 55 | ### Performance Improvements in Simulation and Hardware 56 | 57 | * Performance Enhancements - *Owner: Donny, Chris Wood* 58 | * Pass a parameterized Qobj rather than list of many deepcopied circuits for each parameterization when taking expectation values in Aer and BasicAer 59 | * Replace “matrix mode” statevector simulation with QASM simulation so full statevector doesn’t need to be returned 60 | * Error Mitigation - *Owner: Donny, George Barron* 61 | * Clear and extensible interface for employing error mitigation, including possible combinations of techniques (Ignis) 62 | * Gate-based Richardson Extrapolation (Ignis) 63 | * Pulse-based Richardson Extrapolation Error Mitigation (Ignis) 64 | * Submatrix Measurement Error Mitigation (Ignis) 65 | 66 | ### Physics Software Stack 67 | *Owner: Panos* 68 | 69 | * Support generic building blocks for Lattice Gauge Theory, including popular lattice models and Hamiltonian forms (e.g. QCD, Fermi-Hubbard) 70 | * Light-matter interaction 71 | * Magnetism 72 | * Protein Folding 73 | 74 | 75 | ### Chemistry Software Stack 76 | *Owner: Panos* 77 | 78 | * Stack design v2 79 | * LadderOperators refactor 80 | * Z2 Symmetry Logic _(Steve)_ 81 | * Basis Optimization 82 | * Rotated Hamiltonian Basis _(Pauline)_ 83 | * Q-UCCSD extension ansatze _(Igor)_ 84 | * Stack design - ElectronicGroundState, ElectronicExcitedState, DissociationCurve 85 | * DFT Drivers 86 | 87 | 88 | ### Optimization Software Stack 89 | *Owner: Stefan* 90 | 91 | * Stack design v0 - CPLEX OptimizationProblem specification, QUBO/MBO Solver and Result interfaces, IsingQUBOSolver 92 | * Driver interfaces - CPLEX and Convex Solver 93 | * Slack variable MBO Solver 94 | 95 | 96 | ### Finance Software Stack 97 | *Owner: Stefan* 98 | 99 | * Stack design v0 100 | * AmplitudeEstimation hierarchy 101 | 102 | 103 | ### ML Software Stack 104 | *Owner: Donny* 105 | 106 | * Stack design v0 - SVC, qGAN, HHL 107 | * Recommendation Systems, qSVE Linear Solver 108 | * Driver interfaces - Pytorch, Scikit 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiskit RFCs 2 | 3 | The purpose of a Qiskit Request for Comments (RFC) is to communicate and engage 4 | with the wider community in the development and direction of Qiskit. RFCs enable 5 | engineering and research stakeholders to communicate design changes to any 6 | component of the larger Qiskit project. 7 | 8 | Many changes, including bug fixes and documentation improvements can be 9 | implemented and reviewed via the normal GitHub pull request workflow. 10 | 11 | Some changes though are "substantial", and we ask that these be put through a 12 | bit of a design process and produce a consensus among the Qiskit community and 13 | the sub-teams. 14 | 15 | This repository is for any project in the Qiskit project to make these design 16 | proposals and review and discuss the changes. An RFC can be contained to a 17 | single project or it can span multiple projects, if a design decision requires 18 | some planning and discussion before implementation an RFC can be used to 19 | facilitate that and collect feedback prior to implementation. 20 | 21 | | RFC | Status | References/Discussion | 22 | | --- | ------ | --------------------- | 23 | | `0021` [Sparse observables with extended alphabets](0021-sparse-observable.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/74) \| [Implementation](https://github.com/Qiskit/RFCs/issues/75) | 24 | | `0020` [Qiskit release cycle and versioning](0020-release_cycle.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/34/) \| [Implementation](https://github.com/Qiskit/RFCs/issues/64) | 25 | | `0019` [Classical storage and load instructions](0019-classical-stores.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/50/) \| [Implementation](https://github.com/Qiskit/qiskit/issues/10922) | 26 | | `0018` [Primitive options type change](0018-primitive-options-type.md) | Implementation in progress | [RFC PR](https://github.com/Qiskit/RFCs/pull/52/) \| [Implementation](https://github.com/Qiskit/RFCs/issues/72) | 27 | | `0017` [Base Primitive and Units of Primitive Work](0017-base-primitive-unification.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/53/) \| [Implementation](https://github.com/Qiskit/qiskit/pull/11524) | 28 | | `0016` [SamplerV2](0016-sampler-interface.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/56/) \| [Implementation](https://github.com/Qiskit/RFCs/issues/71) | 29 | | `0015` [Extended Estimator Interface](0015-estimator-interface.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/51) \| [Implementation](https://github.com/Qiskit/RFCs/issues/69) | 30 | | `0014` [Overhaul Qiskit Experiments](0014-overhaul-qiskit-experiments.md) | [Not planned](https://github.com/Qiskit/RFCs/pull/73) | [RFC PR](https://github.com/Qiskit/RFCs/pull/47) \| [Implementation](https://github.com/Qiskit-Extensions/qiskit-experiments/issues/1268) | 31 | | `0013` [Plan to move `Qiskit/qiskit-terra/algorithms` module to `qiskit-community/qiskit-algorithms` independent repo](0013-algorithms-migration.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/44/) \| [Implementation](https://github.com/Qiskit/RFCs/issues/48)| 32 | | `0012` [Pulse Compiler & IR](0012-Pulse-Compiler-and-IR.md) | [Not planned](https://github.com/Qiskit/RFCs/pull/73) | [RFC PR](https://github.com/Qiskit/RFCs/pull/45) \| [Implementation](https://github.com/Qiskit/qiskit/issues/10759)| 33 | | `0011` [Plan to rename `Qiskit/qiskit-terra` repo to `Qiskit/qiskit`](0011-repo-rename.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/31) \| [Implementation](https://github.com/Qiskit/RFCs/issues/41) | 34 | | `0010` [Preliminary representation of rvalue classical expression in Qiskit](0010-simple-classical-representations.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/30) \| [Implementation](https://github.com/Qiskit/qiskit-terra/issues/10239) | 35 | | `0009` [`Operation`: the interface for valid `QuantumCircuit` operations](0009-interface-for-circuit-operations.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/25) \| [Implementation](https://github.com/Qiskit/qiskit-terra/pull/7087)| 36 | | `0008` [Unify Pulse Commands and Instructions](0008-unify-pulse-commands-and-instructions.md) | Implemented | [RFC PR](https://github.com/Qiskit/RFCs/pull/12) \| [Implementation](https://github.com/Qiskit/qiskit-terra/issues/3750) 37 | | `0007` [Dataframe for Qiskit Experiments](0007-experiment-dataframe.md) | Implemented | [RFC PR](https://github.com/Qiskit/rfcs/pull/28) \| [Implementation](https://github.com/Qiskit/RFCs/issues/62) | 38 | | `0006` [Generalized Unroller and Equivalence Library](0006-rfc-generalized-unroller-and-equivalence-library.md) | Implemented | [RFC PR](https://github.com/Qiskit/rfcs/pull/6) \| [Implementation](https://github.com/Qiskit/qiskit-terra/pull/3946)| 39 | | `0005` [Aqua Circuit Interoperability Update](0005-Aqua_circuit_interoperability.md) | Deprecated | [RFC PR](https://github.com/Qiskit/RFCs/pull/17) | 40 | | `0004` [Richardson error mitigation](0004-error-mitigation.md) | Implemented | [RFC PR](https://github.com/Qiskit/rfcs/pull/3) \| [Original PR](https://github.com/Qiskit/qiskit-metapackage/pull/768) \| [Implementation](https://github.com/qiskit-community/prototype-zne) | 41 | | `0003` [Aqua 0.7 Operator Redesign](0003-Aqua_0.7_operator_redesign.md) | Deprecated | [RFC PR](https://github.com/Qiskit/rfcs/pull/8) \| [Original PR](https://github.com/Qiskit/qiskit-aqua/pull/742)| 42 | | `0002` [Aqua 0.7 Release Priorities and Plan](0002-Aqua_0.7_release_priorities_and_plan.md) | Deprecated |[RFC PR](https://github.com/Qiskit/rfcs/pull/7) \| [Original PR](https://github.com/Qiskit/qiskit-aqua/pull/785)| 43 | | `0001` [Aqua 0.7: Ansatz Design Doc](0001-ansatz-rfc.md) | Deprecated |[RFC PR](https://github.com/Qiskit/rfcs/pull/5) \| [Original PR](https://github.com/Qiskit/qiskit-aqua/pull/747) | 44 | 45 | 46 | # How to RFC? 47 | Use the [Qiskit RFC template](0000-template.md) to prepare your RFC. Make sure you read [CONTRIBUTING.md](CONTRIBUTING.md) first. 48 | 49 | ## License 50 | [License]: #license 51 | 52 | This repository is licensed under 53 | 54 | Apache License, Version 2.0, ([LICENSE](LICENSE) or ) 55 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Qiskit Request for Comments (RFC) process 2 | 3 | The purpose of a Qiskit Request for Comments (RFC) is to communicate and engage 4 | with the wider community in the development and direction of Qiskit. RFCs enable 5 | engineering and research stakeholders to communicate design changes to the larger 6 | Qiskit ecosystem, as weel as to document the desion making process. 7 | 8 | Some changes though are "substantial", and we ask that these be put through a 9 | bit of a design process and produce a consensus among the Qiskit community and 10 | the core team. 11 | 12 | # When Should You Write an RFC? 13 | 14 | RFC's should be reserved for 'substantial' changes to any Qiskit project 15 | and the RFC process itself. By this, we mean changes where the implementation 16 | path is not immediately clear and needs to be deconstructed by the Qiskit team. 17 | 18 | To understand whether a change is considered substantial some questions you 19 | might ask yourself are: 20 | 21 | - Will the implementation involve many developers? 22 | - Will the implementation span across multiple points in the Qiskit stack? 23 | - Will the changes cause ramifications for the average user? 24 | - Will the changes require collaboration with outside sources? 25 | 26 | if the answer to any of these is yes, than it probably is a substantial change 27 | and going through the RFC process is recommended. 28 | 29 | # Process 30 | - Fork the [rfcs repository](https://github.com/Qiskit/rfcs) 31 | - Copy the template [0000-template.md](0000-template.md) to 32 | `####-rfc-title.md`, do not yet assign a number. If the RFC requires additional 33 | files, it may be placed in the `text` folder with the name `####-rfc-title`. 34 | - Fill in the template with your RFC. Be thorough and convincing, use proper 35 | grammar and technical language where appropriate. The aim of an RFC is to 36 | convey both a change and a vision for the future it will enable, you must 37 | convince the larger Qiskit team that it is valuable. 38 | - Each RFC will be labeled with the relevant packages, so that the respective 39 | maintainers of the packages may be notified of the RFC. 40 | - The RFC will be triaged and if it is of sufficient quality a 41 | *review committee* will be formed by assigning the PR to a group of 42 | *committee members* who are each maintainer(s) of the relevant Qiskit packages. 43 | Committee members are responsible for moderating the development of the RFC and 44 | acceptance or closure of the RFC. It is expected that RFC should fail in the 45 | early, rather than later stages of the development cycle. If the RFC author is 46 | themselves a maintainer of one of the relevant packages, they should not be a 47 | committee member for their own RFC. 48 | - Interested parties should discuss and modify the RFC within the pull-request. 49 | Efforts should be made to summarize offline discussions within the PR. The aim 50 | is to capture the outcome of discussion within the RFC, and the flow of 51 | development within the PR. 52 | - The RFC will go through many iterations at this stage, *do not* squash/rebase 53 | the RFC commits. The aim is to capture the history of the document. 54 | - When the RFC has satisfied a committee member, they should review and approve 55 | the PR. If it is not progressing satisfactorily, or supported by the review 56 | committee it may be closed at any time. This may be petitioned by reopening the 57 | PR, along with a potential request for a new review committee. 58 | - Upon approval by all review committee members, the RFC will be assigned a 59 | number of `max(rfc_####) + 1`, the filename will be updated to reflect this and 60 | the author list should be validated. Note that as Qiskit is still undergoing 61 | rapid-development there is no required grace period between acceptance and 62 | merger, as the project matures this is expected to change. 63 | - The RFC will then be merged by one of the committee members. 64 | - After acceptance, the implementation of the contents of the RFC may proceed. 65 | 66 | ## The RFC life-cycle 67 | 68 | Once an RFC becomes "active" (i.e. is approved and merged) then authors may 69 | implement it and submit the feature as a pull request to the relevant Qiskit 70 | repos. Being "active" is not a rubber stamp, and in particular still does not 71 | mean the feature will ultimately be merged; it does mean that in principle all 72 | the major stakeholders have agreed to the feature and are amenable to merging 73 | it. 74 | 75 | Furthermore, the fact that a given RFC has been accepted and is "active" 76 | implies nothing about what priority is assigned to its implementation, nor does 77 | it imply anything about whether a Qiskit developer has been assigned the task of 78 | implementing the feature. While it is not *necessary* that the author of the 79 | RFC also write the implementation, it is by far the most effective way to see 80 | an RFC through to completion: authors should not expect that other project 81 | developers will take on responsibility for implementing their accepted feature. 82 | 83 | Modifications to "active" RFCs can be done in follow-up pull requests. We 84 | strive to write each RFC in a manner that it will reflect the final design of 85 | the feature; but the nature of the process means that we cannot expect every 86 | merged RFC to actually reflect what the end result will be at the time of the 87 | next major release. 88 | 89 | In general, once accepted, RFCs should not be substantially changed. Only very 90 | minor changes should be submitted as amendments. More substantial changes 91 | should be new RFCs, with a note added to the original RFC. Exactly what counts 92 | as a "very minor change" is up to the sub-team to decide; check 93 | [Sub-package guidelines] for more details. 94 | 95 | # RFC Postponement 96 | 97 | Some RFC pull requests are tagged with the "postponed" label when they are 98 | closed (as part of the rejection process). An RFC closed with "postponed" is 99 | marked as such because we want neither to think about evaluating the proposal 100 | nor about implementing the described feature until some time in the future, and 101 | we believe that we can afford to wait until then to do so. This normally means 102 | a topic for discussion after the Qiskit 1.0 release. Postponed pull 103 | requests may be re-opened when the time is right. We don't have any formal 104 | process for that, you should ask members of the relevant sub-team. 105 | 106 | Usually an RFC pull request marked as "postponed" has already passed an 107 | informal first round of evaluation, namely the round of "do we think we would 108 | ever possibly consider making this change, as outlined in the RFC pull request, 109 | or some semi-obvious variation of it." (When the answer to the latter question 110 | is "no", then the appropriate response is to close the RFC, not postpone it.) 111 | 112 | # Contributors 113 | An *RFC author* write and champions and RFC through the process. 114 | 115 | A *community member* provides feedback on an RFC either as a PR comment, or an 116 | edit to the RFC. 117 | 118 | A *review committee* is the group *committee members*, all of which are RFC PR 119 | assignees and are maintainers of one or many of the Qiskit meta-package 120 | projects. The committee is responsible for guiding, reviewing and finally 121 | closing/approving the RFC. 122 | 123 | # Template 124 | Use the [Qiskit RFC template](0000-template.md) to prepare your RFC. 125 | 126 | ## License 127 | [License]: #license 128 | 129 | This repository is licensed under 130 | 131 | Apache License, Version 2.0, ([LICENSE](LICENSE) or http://www.apache.org/licenses/LICENSE-2.0) 132 | -------------------------------------------------------------------------------- /0017-base-primitive-unification.md: -------------------------------------------------------------------------------- 1 | # Base Primitive and Units of Primitive Work 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0017 | 6 | | **Authors** | Lev Bishop (lsbishop@us.ibm.com) | 7 | | | Ian Hincks (ian.hincks@ibm.com) | 8 | | | Blake Johnson (blake.johnson@ibm.com) | 9 | | | Chris Wood (cjwood@us.ibm.com) | 10 | | **Submitted** | 2023-10-26 | 11 | | **Updated** | 2023-12-20 | 12 | 13 | ## Summary 14 | 15 | The primitives form an execution framework for QPUs and their simulators. 16 | Each primitive specializes at some computational task. 17 | For example, the `Estimator` specializes at computing expectation values of user-provider observables. 18 | 19 | Different types of primitives are implemented as different abstract subclasses of `BasePrimitive` (e.g. `BaseEstimator`), and different primitive implementations as further subclasses (e.g. `qiskit_aer.primitives.Estimator`). 20 | This RFC proposes the structure and format of various container types that can be used by base primitives to store input and output values. 21 | 22 | ## Motivation 23 | 24 | The central motivation of this RFC is to more clearly emphasize that primitives are an execution framework on top of which applications (not just algorithms) can be built. 25 | We aim to help each type of primitive to clearly state what units of quantum work it is able to perform. 26 | We do this by proposing a set of containers that various `run()` methods can use (possibly subclassed) as input and output types. 27 | In doing so, we are also proposing a set of names that can help us standardize the way we talk about execution in documentation, and throughout the stack. 28 | 29 | ## User Benefit 30 | 31 | We expect that users will generally benefit from a more homogenous experience across the primitives, in terms of how they would submit jobs, and in how they would collect the data out of their results. 32 | These containers would also make it possible for base primitives to have multiple, named output types. 33 | This would enable, for example, primitives to have separate output fields for each output variable of a particular circuit, or to take standard error/confidence intervals out of the metadata and put it right alongside the first moment data. 34 | 35 | ## Design Proposal 36 | 37 | We propose to encourage base primitives, like `BaseSampler` and `BaseEstimator`, to have a `run` method typed as 38 | 39 | ```python 40 | class BaseFoo: 41 | def run(self, pubs: FooPubLike | Iterable[FooPubLike]) -> Job[PrimitiveResult[FooPubResult]]: 42 | """Run one or more input PUB (Primitives Unified Bloc) and return a result for each one.""" 43 | ``` 44 | 45 | where `FooPub` is equal to or derives from `Pub`, `FooPubLike` is a union type that is easily coercible into a `FooPub` via the static method `FooPub.coerce`, and where `FooPubResult` derives from `PubResult`. 46 | 47 | The base containers `PrimitiveResult,`, `Pub`, and `PubResult` are described in the next sections. 48 | `Job[T]` is any `qiskit.provider.JobV1` whose result method returns type `T`. 49 | 50 | Any primitive following the above pattern could be used as follows: 51 | 52 | ```python 53 | # instantiate the primitive 54 | foo = Foo() 55 | 56 | # run the primitive with three PUBs 57 | job = foo.run([pub0, pub1, pub2]) 58 | 59 | # block for results 60 | result = job.result() 61 | 62 | # get data from second PUB 63 | result1 = result[1] 64 | 65 | # get particular data from this result (the available fields depend on the primitive type and PUB, 66 | # and this example is not proposing any specific names) 67 | alpha_data = result1.data.alpha 68 | beta_data = result1.data.beta 69 | expectation_values = result1.data.expectation_values 70 | ``` 71 | 72 | ## Detailed Design 73 | 74 | ### PUBs 75 | 76 | We propose the concept of a _PUB (Primitive Unified Blocs)_, which we define as _a single circuit along with auxiliary data required to execute the circuit relative to the primitive in question_. This concept is general enough that it can be used for all primitive types, current and future, where we stress that what the “auxiliary data” is can vary between primitive types. 77 | 78 | ```python 79 | # prototype implementation for the RFC 80 | @dataclass(frozen=True) 81 | class Pub: 82 | circuit: QuantumCircuit 83 | ``` 84 | 85 | Different primitive types (such as `Estimator`) are intended to subclass this class, adding auxiliary fields as 86 | required. 87 | 88 | ### DataBin 89 | 90 | A data bin is a namespace for storing data. 91 | The fields in the namespace, in general, depend on the PUB that was executed (not the `type` of the PUB). 92 | For example, a `Sampler` will have fields for each output (as defined by the OpenQASM 3 spec, but in Qiskit, you can currently take "output" to mean the names of the classical registers) of the PUB's circuit. 93 | The value of each field will store the corresponding data. 94 | 95 | All primitives will store their data in `DataBin`s. 96 | There will not be subclassing to the effect of `SamplerDataBin < DataBin`; look instead to `PubResult` for such needs. 97 | 98 | ```python 99 | # Make a new DataBin class. make_data_bin() is analagous to dataclasses.make_dataclass(). 100 | # The shape is an optional argument which indicates that all values are to share the same leading shape. 101 | # To put the following generic example into context, if it helps, imagine that this code lives in the 102 | # BaseSampler implementation, and a data bin class is being created to store the results from 103 | # particular SamplerPub instance whose circuit has two output registers named alpha and beta, and 104 | # that the PUB itself has shape (5, 4). 105 | data_bin_cls = make_data_bin({"alpha": NDArray[np.float], "beta": NDArray[np.uint8]}, shape=(5, 4)) 106 | 107 | # make an instance with particular data 108 | data_bin = data_bin_cls( 109 | alpha=np.empty((5, 4, 1024), dtype=np.float), 110 | beta=np.empty((5, 4, 1024, 127)) 111 | ) 112 | 113 | # access items as attributes 114 | alpha_data = data_bin.alpha 115 | 116 | # access items with subscripts 117 | alpha_data = data_bin["alpha"] 118 | ``` 119 | 120 | ### PubResult 121 | 122 | A `PubResult` is the result of running a single `Pub` and does three things: 123 | 124 | * Stores a `DataBin` instance containing the data from execution. 125 | * Stores the metadata that is possibly implementation-specific, and always specific to the executed PUB. 126 | * (subclasses) Contains methods to help transform the data into standard formats, including migration helpers. 127 | 128 | We generally expect each primitive type to define its own subclass of `PubResult` to accomodate the third item, though `PubResult` has no methods that need to be abstract. 129 | 130 | We elect to have a special container for the data (`DataBin`) so as not to pollute the `PubResult` namespace with pub-specific names, and to keep data quite distinct from metadata. 131 | 132 | ```python 133 | # return a DataBin 134 | pub_result.data 135 | 136 | # return a metadata dictionary 137 | pub_result.metadata 138 | ``` 139 | 140 | 141 | ### PrimitiveResult 142 | 143 | `PrimitiveResult` is the type returned by `Job.result()` and is primarily a `Sequence[PubResult]`, with one entry for each `Pub` input into the primitive's run method. 144 | 145 | Secondarily, it has a metadata field for those metadata which are not specific to any single PUB. 146 | -------------------------------------------------------------------------------- /0009-interface-for-circuit-operations.md: -------------------------------------------------------------------------------- 1 | # `Operation`: the interface for valid `QuantumCircuit` operations 2 | 3 | | **Status** | **Implemented** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0009 | 6 | | **Authors** | Jake Lishman (jake.lishman@ibm.com) | 7 | | **Deprecates** | None | 8 | | **Submitted** | 2022-05-31 | 9 | | **Updated** | 2023-05-10 | 10 | 11 | 12 | ## Summary 13 | 14 | Currently, only subclasses of `Instruction` can be put on `QuantumCircuit`, but 15 | this interface has become unwieldy and includes too many methods and attributes 16 | for general-purpose objects. We propose to put a new interface in place that is 17 | far more stripped down, and to remove transpilation-specific methods from the 18 | objects themselves, and move them to make them transpiler behaviour. We propose 19 | that this new interface will be called `Operation`. 20 | 21 | 22 | ## Motivation 23 | 24 | - `Instruction` as a complete type has too many unrelated attributes and methods 25 | from the base interface, which not all "quantum operations" can reasonably 26 | fulfil. For example, `definition` (which is already circumvented in several 27 | cases), `duration` and `unit` (which only have meaning after transpilation), 28 | and `assemble` (which supposes that the object is immediately executable). 29 | 30 | Some of these are fine _after transpilation_, but are too restrictive for 31 | `Instruction` to be the only input type for the transpiler. 32 | 33 | - `Instruction` is defined as part of `qiskit.circuit`, which poses cyclic 34 | dependency issues for some lower-level objects (e.g. those based in 35 | `quantum_info` types). 36 | 37 | - Having a simpler, abstract interface (`Operation`) allows us to break the 38 | cyclical dependencies (it can be the lowest part of Terra), make more objects 39 | suitable for being "transpiler input", and reduce the memory/implementation 40 | complexity for those objects that can be. 41 | 42 | - `Instruction` need not be replaced by this; we still want something to 43 | represent "a transpiled operation". This is a greater restriction than "an 44 | operation that can be transpiled", so `Instruction` can (and will) also 45 | implement `Operation`. 46 | 47 | - Defining an immutable interface lets us re-use the same objects more during 48 | transpilation, which will save a lot of memory. For example, we will not need 49 | to repeatedly copy `definition` circuits just in case the parameters are 50 | mutated by some later pass, and we will not need to copy in case the 51 | `condition` of the instruction is modified. 52 | 53 | 54 | ## User Benefit 55 | 56 | - Users will have more freedom to work with a variety of objects (such as 57 | `quantum_info.Clifford`) and store them directly onto circuits, letting them 58 | interact again with the rich objects. 59 | 60 | - Developers gain a backwards-compatible way to reduce the dependence on some of 61 | the memory-hungriest components of `Instruction`. 62 | 63 | - Transpiler pass writers can use the rich methods of the objects without the 64 | additional memory usage (and type-unsafety) of wrapping each thing it its own 65 | `Instruction` subclass. 66 | 67 | - Transpiler pass writes will be able to more easily write synthesis methods 68 | that use more information from the transpiler. 69 | 70 | - Researchers will be able to more easily "plug in" their own synthesis methods 71 | for higher-order objects at transpilation run time, without needing to modify 72 | the objects themselves, or mess with pass managers. 73 | 74 | 75 | ## Design Proposal 76 | 77 | We propose an abstract interface that defines a circuit operation that can be 78 | input to the transpiler. We call this `Operation`. 79 | 80 | The propsed attributes on `Operation` are: 81 | 82 | - `name`: the name identifier, to provide a link between objects and `Target`, 83 | the API that backends use to describe what operations they support. 84 | 85 | - `num_qubits`: the logical number of qubits this instruction operates on. 86 | Synthesis methods may use more qubits than this to implement the operation, 87 | but this is the number of "data" qubits. This is to enable quantum resource 88 | tracking and type safety. 89 | 90 | - `parameter_spec`: number and types of the parameters that need to be supplied 91 | to this object at run-time (notably _not_ the parameters themselves). This is 92 | to enable classical resource tracking and type safety. 93 | 94 | - `state`: an opaque object that contains the full state of the object, which 95 | can be passed to some as-yet-undefined method to reconstruct the object. This 96 | is for serialisation. 97 | 98 | Some things `Operation` should not do: 99 | 100 | - force objects to make decisions about their synthesis 101 | - force all objects to be stateful (i.e. there should be a valid implementation 102 | of `HGate` that is a singleton) 103 | - require objects to construct / be able to construct a `QuantumCircuit` through 104 | any of the abstract methods 105 | 106 | These things mean that the following properties or methods should _not_ be part 107 | of `Operation`: 108 | 109 | - `condition`: this should be part of separate classical control flow, and its 110 | stateful nature is one of the current reasons for a lot of copying of 111 | `Instruction` instances. 112 | 113 | - `duration` and `unit`: these are properties of the output of the transpiler, 114 | and should also depend on the particular qubits in use. This likely wants to 115 | become part of `CircuitInstruction` (see Qiskit/qiskit-terra#8093). 116 | 117 | - `assemble`: this is particular to the conversion to the `Qobj` type, which may 118 | not exist in the long-term, but even in the short-term, this is conversion 119 | behaviour and the interfaces should be well-enough defined such that this does 120 | not need to be specialised. 121 | 122 | - `definition` or `_define`: this ties synthesis to the object, causing us to 123 | carry around extra circuits (and frequently copy them). 124 | 125 | 126 | ## Alternative Approaches 127 | 128 | It is in theory possible to maintain the status quo, and have `Instruction` be 129 | the definition of the transpiler-input interface. Some things (such as 130 | pluggable, controllable synthesis passes) are still possible to do in this 131 | structure. The memory problems are (at best) exacerbated by `Instruction`, 132 | though, and it is difficult to fix this will maintaining backwards 133 | compatibility. This also would do nothing to address the general design 134 | problems with operations currently needing to define their own synthesis. 135 | 136 | The memory usage is already showing problematic strain for scalability. See: 137 | 138 | - Qiskit/qiskit-terra#7485 139 | - Qiskit/qiskit-terra#6991 140 | - Qiskit/qiskit-terra#5895 141 | 142 | Having all operations have to define their own `definition` causes cyclic 143 | dependency and hierarchy issues: `quantum_info` classes generally should not 144 | need to care about the circuit model, since they are using a different 145 | formalism. This also means that objects with more than one synthesis method 146 | have to define a "preferred" synthesis method. This is an issue for things like 147 | the multi-controlled X. 148 | 149 | 150 | ## Questions 151 | 152 | 1. At this point, the exact requirements for `Operation` are not fully 153 | finalized. This RFC will not be ready for a complete implementation until they are. 154 | 155 | 2. Will classical operations also be `Operation`, or will we do something 156 | different with them? 157 | 158 | 3. What information about necessary qubits should we expose, bearing in mind 159 | that the "number of qubits needed" may be dependent on the synthesis method? 160 | 161 | 162 | ## Future Extensions 163 | 164 | This has generally come up as part of two additional strands of work: 165 | 166 | - richer, more controllable synthesis on complex objects 167 | - separation of concerns between "operations" and "operands" in `QuantumCircuit` 168 | 169 | Defining `Operation` completely ties a lot into both of these. 170 | 171 | For the richer synthesis to be a powerful, (relatively) easy-to-use tool, we 172 | need to make sure that the transpiler has all the information it needs within 173 | the `Operation` class to do its job while treating the objects as otherwise 174 | entirely opaque. The more the transpiler needs to know about an object, the 175 | more onerous and memory-hungry it is for general-purpose objects to implement 176 | the interface, which is a problem for scaling. 177 | 178 | The separation of concerns between the operations, operands, and circuit-level 179 | properties of given instructions is inherently tied in, because some components 180 | of `Instruction` can be made "operands", rather than needing to be tied to the 181 | instance. This is immediately `params` as part of `Instruction`. 182 | -------------------------------------------------------------------------------- /0013-algorithms-migration.md: -------------------------------------------------------------------------------- 1 | # Plan to move `Qiskit/qiskit-terra/algorithms` module to `Qiskit-community/qiskit-algorithms` independent repo 2 | 3 | | **Status** | **Proposed** | 4 | |:------------------|:------------------------------------------------------------------------------------------| 5 | | **RFC #** | 0013 | 6 | | **Authors** | [Elena Peña Tapia](https://github.com/ElePT) | 7 | | | [Steve Wood](https://github.com/woodsp-ibm) | 8 | | **Submitted** | 2023-07-05 | 9 | | **Updated** | 2023-08-31 | 10 | 11 | 12 | ## Summary 13 | 14 | This RFC was created to document discussions concerning the future of the `qiskit.algorithms` module. 15 | This module provides a series of interfaces and implementations of commonly used quantum algorithms based on 16 | Qiskit's core components. Historically, the module was created as part of Qiskit Aqua, together with the now 17 | community-based application modules (Nature, Machine Learning, Optimization, Finance). 18 | It [currently "lives" in `qiskit-terra`](https://github.com/Qiskit/qiskit), 19 | and over the past year has been refactored to use the Qiskit Primitives and sustain the 20 | Opflow and Quantum Instance deprecations. 21 | 22 | The content of `qiskit.algorithms` is heterogeneous. Some components are algorithm implementations, while others 23 | are "sub-routines" or algorithm utilities, such as gradients, optimizers or state fidelities. Some of these 24 | utilities are implementatons from scratch, others are wrappers over commonly used libraries (such as the 25 | SciPy optimizers). 26 | 27 | With Qiskit moving towards a leaner definition and focusing on primitives as quantum hardware access model, 28 | the future of `qiskit.algorithms` is being revisited. 29 | The classes in the module tend to hide the primitives interfaces and serve as convenience wrappers 30 | for abstractions, beyond the current definition of Qiskit. 31 | As such, they do provide value to users to it would be important to 32 | find a better suiting location for them while minimizing the disruption caused to users. 33 | 34 | **Note**: In this document, the terms `qiskit-terra` and `qiskit` are interchangeable. 35 | 36 | ## Design Proposal 37 | 38 | There are several design decisions to be made as part of this "`qiskit.algorithms` revision": 39 | 40 | 1. Which classes stay in `qiskit-terra` 41 | 2. Where do they stay within `qiskit-terra` (i.e. do they stay in `qiskit.algorithms`? or is the module 42 | renamed or split to better define its purpose?) 43 | 3. Where do the "non-chosen" classes go 44 | 45 | We have to keep in mind that these algorithms are extensively used by 46 | the community and until now, they have been one of the main access points to our stack. For example, the 47 | `MinimumEigensolver` class is a fundamental 48 | dependency for Qiskit Nature, which relies on this definition to interface with classical chemistry codes via 49 | plugins. 50 | 51 | Even if we stop their maintenance, it would still be highly valuable to have a self-contained, installable package 52 | that the community can access and add as a dependency to avoid having to reimplement research code or libraries. 53 | 54 | ### Main Idea 55 | 56 | We believe that fastest way to disentangle `qiskit.algorithms` from `qiskit-terra` while causing minimal 57 | disruption to users would 58 | be to create a standalone `qiskit-algorithms` repo with a similar setup to the applications repos (including CI, docs...), 59 | perform a history-preserving copy of the content of `qiskit.algorithms` to `qiskit_algorithms`, and document 60 | the migration path by raising a deprecation warning asking users to change the import. 61 | 62 | This repository can be created regardless of whether we decide to keep some algorithms in `qiskit-terra` or not. 63 | In the event that we decided to keep certain algorithms in `qiskit-terra`, there would be two possible paths: 64 | 65 | **Path 1** 66 | 67 | 1. All contents of `qiskit.algorithms` are moved over to `qiskit-algorithms`, and the module as a whole 68 | is deprecated. 69 | 2. Some components are moved back to `qiskit-terra`, potentially to a new location 70 | (`qiskit.gradients`, `qiskit.optimizers`, `qiskit.state_fidelities`...), and are potentially refactored during this move. 71 | 72 | This alternative allows to have a "clean slate" for developers with the downside of potentially moving some components 73 | out of qiskit and back into qiskit again in a short period of time. The migration path is easier in this alternative, but 74 | deprecations are a huge hassle for users, and if we 75 | are sure of which components we want to keep, (if we want to keep any) this might not 76 | be the best way (or the most popular) from a user-friendliness point of view. 77 | 78 | **Path 2** 79 | 80 | 1. Only part of the contents of `qiskit.algorithms` are moved over to `qiskit-algorithms`, and classes 81 | are deprecated individually. 82 | 2. This allows for refactorings to happen in-place as a second step 83 | 84 | This alternative is more conservative, and requires a better understanding of what the future components of 85 | `qiskit.algorithms` will be, and whether we want to keep the module's name and current structure. The plans 86 | to release Qiskit 1.0 should also be taken into account, as they imply a commitment to whatever is kept 87 | in Qiskit. 88 | 89 | **Decision** 90 | 91 | After analizing pros and cons for both options, our current plan is to design a migration plan that 92 | follows **Path 1**. This allows us to focus on the move to the new repository as an initial step, without 93 | deciding specifically which algorithms/utilities might be added back to Qiskit. 94 | Should new considerations be taken into account, this plan could change. 95 | 96 | ### Migration plan 97 | 98 | **Repos immediately affected by the plan**: `Qiskit/qiskit-terra` and `Qiskit/qiskit-tutorials` 99 | 100 | ### qiskit-terra 101 | 102 | 1. Open a PR to add a single deprecation message telling users to change their imports 103 | from `qiskit.algorithms` to `qiskit_algorithms`. The code will continue existing 104 | in `qiskit-terra` until the deprecation period is over [Blocker: release of `qiskit_algorithms-0.1.0`, 105 | see below]. 106 | 2. What should we do with the algorithms migration guide? we could leave it in terra during the deprecation period, 107 | for users still using `qiskit.algorithms` but make a copy in `qiskit-algorithms` (maybe the copy needs some editing 108 | for references etc). After the deprecation period, we can remove it from terra. 109 | 3. What about algorithms that depend on already deprecated code (i.e opflow)? 110 | Given that the deprecated code will still be available in `qiskit.algorithms`, we can just migrate the non-deprecated 111 | code to the new location and warn users about updating their code before migrating to the new package 112 | (direct to migration guides). This will provide a "clean slate" for `qiskit_algorithms`. 113 | 4. During the deprecation period, we can focus on moving issues, closing pending PRs, and finishing up other details 114 | 115 | ### qiskit-tutorials 116 | 117 | 1. There is already a plan to relocate the tutorials from `qiskit-tutorials` to `qiskit-terra` 118 | https://github.com/Qiskit/qiskit-tutorials/issues/1473. Instead of relocating to terra, we propose to move the tutorials 119 | to `qiskit-algorithms/docs` and be published as part of its docs as we do for Nature, ML et al. 120 | 2. During the deprecation period, a redirect could be set up to go from `qiskit.org/documentation/tutorials/algorithms/*` to 121 | `qiskit.org/ecosystem/algorithms/tutorials/index.html` 122 | 3. Which tutorials should be moved? All tutorials that use `qiskit_applications`. Other tutorials that build algorithms 123 | from scratch (such as https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/09_IQPE.ipynb) are 124 | better suited as educational material. 125 | 126 | 127 | ### qiskit-algorithms 128 | 129 | 1. Create a new `qiskit-algorithms` repo and perform a history preserving copy plus a move, and whatever namespace 130 | fix-ups are needed for imports, deprecation messages of the old algos etc. We have done this history preserving 131 | copy in the past. 132 | 2. Perform a history preserving copy of the relevant tutorials in `qiskit-tutorials` plus necessary code updates 133 | (imports, etc) 134 | 3. This new repo would need CI setup, the docs setup, etc, so they can 135 | publish out like apps repos do. And as mentioned above, the docs can include a copy of the algorithms migration - 136 | maybe the short url points to this published copy. 137 | 138 | ### docs 139 | 1. Similarly to the application modules, the algorithm docs could be rendered in `qiskit.org/ecosystem/algorithms` 140 | 2. During the deprecation, a redirect could be set up to go from `qiskit.org/documentation/` to `qiskit.org/ecosystem/algorithms` 141 | 142 | 143 | ### Alternatives considered but disregarded 144 | 145 | 1. Splitting `qiskit.algorithms`, keeping some algorithms, moving others to different locations (such as the apps modules): 146 | This idea was disregarded because of the disruption it will cause to users, to libraries for which `qiskit-algorithms` is 147 | a dependency (i.e, apps modules), and the lack of consensus on which algorithms go where. 148 | 2. Making `qiskit-algorithms` a git submodule of Terra instead of doing a redirect. The sub-module is linked by a 149 | specific commit as far as Steve recalls and its something that got discussed in the early days but was not well liked. 150 | The namespace strategy followed with qiskit.providers.aer redirecting to qiskit_aer works and keeps 151 | things more independent. 152 | 153 | 154 | ### Timeline 155 | 156 | As this is an urgent move, the deprecations and new installable package should be in place for the terra 0.25 release. 157 | Docs can be updated in between releases. 158 | The deprecation period should allow for the final decoupling to happen for 0.26. 159 | 160 | ## Open Questions 161 | 162 | There are 2 main open questions left: 163 | 164 | 1. Are any algorithms going to stay in terra? 165 | 2. If so, where would they stay? 166 | 167 | Under the assumption that we only want to keep 168 | "fundamental building blocks" for algorithm design, our current proposal would be to maintain 169 | sub-routines and utilities (gradients, fidelities, optimizers that are not wrappers), 170 | and replace specific algorithm implementations with well crafted tutorials/documentation. Because of the independent 171 | `qiskit-algorithms` repository, users that relied on other algorithm implementations would still have access to these 172 | classes. 173 | 174 | Specifically, if we look at the current non-deprecated contents of the module, the proposed distribution would be: 175 | 176 | - `amplitude_estimators` -> tutorial 177 | - `eigensolvers` -> tutorial 178 | - `gradients` -> **utility that stays** 179 | - `minimum_eigensolvers` -> tutorial 180 | - `optimizers` -> **those that don't wrap scipy ara a utility that stays** 181 | - `phase_estimators` -> tutorial 182 | - `state_fidelities` -> **utility that stays** 183 | - `time_evolvers` -> tutorial 184 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 IBM and its contributors 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright 2017 IBM and its contributors. 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | -------------------------------------------------------------------------------- /0011-repo-rename.md: -------------------------------------------------------------------------------- 1 | # Plan to rename `Qiskit/qiskit-terra` repo to `Qiskit/qiskit` 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0011 | 6 | | **Authors** | [Luciano Bello](https://github.com/1ucian0) | 7 | | | [Kevin Krsulich](https://github.com/kdk) | 8 | | **Submitted** | 2023-03-31 | 9 | | **Updated** | 2023-05-10 | 10 | 11 | 12 | ## Summary 13 | [In 2021](https://research.ibm.com/blog/qiskit-application-modules), Qiskit began an evolution from a large monolithic install, which included by default the Aer simulator, the IBM Quantum provider, and large characterization and application libraries, into a leaner and more modular structure. 14 | The results of that progression are a Qiskit based on core components of circuit construction, compilation, and device interfaces, and a new [ecosystem](https://qiskit.org/ecosystem/) of extensions which users can explore, install, and contribute to based on their interests. 15 | 16 | As Qiskit moved towards this leaner definition, the functionality in the current `qiskit-terra` has come to make up an increasing share of Qiskit's core. 17 | However, having separate `qiskit` and `qiskit-terra` repositories results in additional indirection when, for example, trying to identify where users should submit an issue when encountering a problem in Qiskit, or where a particular piece of source code or infrastructure lives. 18 | 19 | As a result, we are planning to rename the current `Qiskit/qiskit-terra` repository in GitHub as `Qiskit/qiskit`. 20 | This document traces a plan for that renaming, including migration paths for all of the content currently in `Qiskit/qiskit`, both to inform the community about the potential for upcoming breaking changes, and to ask help identifying and defining mitigations for usages that may be impacted by this change. 21 | 22 | ## Motivation 23 | 24 | This RFC seeks for the best way to mitigate the impact of current and future users brought on by the `Qiskit/qiskit-terra`-to-`Qiskit/qiskit` rename. Having a open an early discussion will help users to plan accordingly and express possible concerns and limitations. 25 | 26 | ## User Benefit 27 | 28 | A more straightforward GitHub naming will help new users to navigate the complex Qiskit software ecosystem. However, it comes at the cost of disturbance to current users and developers. This RFC is a plan to reduce that disturbance as much as possible. 29 | 30 | ## Design Proposal 31 | 32 | Renaming `qiskit/qiskit-terra` repository as `qiskit/qiskit` is problematic because the reutilization of the `qiskit/qiskit` repository namespace, currently used by the so called *metapackage*. 33 | To clarify the current usage of the `qiskit/qiskit` repository, it is straightforward to rename it something like `qiskit/qiskit-metapackage` which explains more clearly its purpose. 34 | 35 | When renaming `qiskit/qiskit` to `qiskit/qiskit-metapackage`, GitHub automatically will redirect users `qiskit/qiskit -> qiskit/qiskit-metapackage` seamlessly. That rename does not "free" the `qiskit/qiskit` repository namespace. User might continue using `qiskit/qiskit` without noticing any change until `qiskit/qiskit-terra` gets renames as `qiskit/qiskit`. 36 | 37 | **This proposal suggests to empty the current metapackage repository by distributing its content to other places. In this way, users and automation of the metapackage will slowly transition to other respective locations, minimizing the traffic to `qiskit/qiskit` that is expecting to find metapackage code. Once that is done, the metapackage can be archived and `qiskit-terra` can be renamed to `qiskit/qiskit`.** 38 | 39 | However, this solution is not perfect. 40 | There will be dangling instances that will continue pointing at `qiskit/qiskit` expecting to find `qiskit/qiskit-metapackage`. 41 | 42 | Currently, the metapackage repository stores: 43 | 44 | * the `setup.py` for the metapackage 45 | * the documentation root `conf.py` for `qiskit.org/documentation` 46 | * some documentation pages, like `Contributing to Qiskit` 47 | * the [benchmarking code](https://github.com/Qiskit/qiskit/tree/master/test/benchmarks) for 48 | * The ["global" Qiskit Code of Conduct](https://github.com/Qiskit/qiskit/blob/master/CODE_OF_CONDUCT.md). Practically, every Qiskit related repo points here. It needs to be copied to `qiskit/qiskit-terra` repo in order for links to still work after the rename. 49 | 50 | This is the code that needs to be moved and distributed while their users, issues, and PRs, get transitioned to their new places. 51 | This will be done in the main stage of the plan: empty-metapackage. This is the detailed timeline for each stage and task and their dependencies: 52 | 53 | ```mermaid 54 | gantt 55 | dateFormat YYYY-MM-DD 56 | tickInterval 1month 57 | todayMarker off 58 | axisFormat %b 59 | 60 | section planned releases 61 | %% From freeze to release 62 | 0.24 : crit, release024, 2023-04-06, 28d 63 | release 0.24 : milestone, 2023-05-04 64 | %% From freeze to release 65 | 0.25 : crit, release025, 2023-07-05, 22d 66 | release 0.25 : milestone, 2023-07-27 67 | section preparation 68 | metapackage-repo :metapackage-repo, 2023-03-31, 1d 69 | rfc-discussion :active, rfc-discussion, 2023-03-30, 10d 70 | rfc-merged :milestone, rfc-merged, after rfc-discussion, 0d 71 | section empty-metapackage 72 | %% These tasks are not interdepedendent and they need to be done before release025 73 | ibmq-docs-out-of-metapackage :ibmq-docs, after rfc-merged, 2w 74 | docs-out-of-metapackage :docs, after ibmq-docs, 4w 75 | benchmarks-out-of-metapackage :benchmarks, after docs, 4w 76 | tutorials-out-of-metapackage :tutorials, after benchmarks, 4w 77 | section archive-metapackage 78 | ibmq-out-of-metapackage :ibmq-archived, after release025, 1d 79 | move-setup-out-of-metapackage :setup, after release025, 1d 80 | pre-archive-doc :archive-doc, after release025, 2d 81 | archive-metapackage :archive-meta, after archive-doc setup, 1d 82 | section final 83 | final-rename : finalrename, after archive-meta, 1d 84 | fix-time: : fix-time, after finalrename, 2w 85 | final-announcement : milestone, finalannoun 86 | ``` 87 | 88 | ### preparation stage 89 | 90 | This stage covers the pre-work with the following independent tasks: 91 | 92 | * **metapackage-repo**: Renaming `qiskit/qiskit` to `qiskit/qiskit-metapackage` is independently desired, as the new name describes more correctly its content. 93 | * **rfc-discussion**: During 10 days after the submission of this RFC, this document will collect comments and feedback on the best way to mitigate the effects of this renaming. 94 | 95 | ### empty-metapackage stage 96 | 97 | The main stage of the plan is to empty the metapackage to minimize the traffic to `qiskit/qiskit` (at this point, `qiskit/qiskit-metapackage`) before the renaming `qiskit/qiskit-terra` to `qiskit-qiskit`. 98 | 99 | For each task in this stage, the code is moved with related issues and PRs. 100 | The tasks are independent and can start at any point, but they need to finish before the qiskit-terra release of July. 101 | 102 | * **ibmq-docs-out-of-metapackage**: Early in the stage, we can try to deploy `qiskit-ibmq-provider` documentation as stand-alone in `qiskit.org/ecosystem/qiskit-ibmq-provider`. This is optional, as the full documentation will be removed on July. 103 | * **docs-out-of-metapackage**: Move documents from `qiskit/qiskit-metapackage` to `qiskit/qiskit-terra`. All the ["general documents"](https://github.com/Qiskit/qiskit/tree/master/docs) in needs to be moved to the `qiskit/qiskit-terra` to be part of a single sphinx build process. The [`qiskit-ibmq-provider` documentation](https://qiskit.org/documentation/apidoc/ibmq-provider.html) cannot be move to `qiskit/qiskit-terra`. Therefore, the options are: 104 | * Wait until the stage ibmq-out-of-metapackage when the documentation can be removed as the repo `qiskit/qiskit-ibmq-provider` gets archived. 105 | * Create a landing page in `qiskit.org/documentation/ibmq-provider` or `qiskit.org/ecosystem/ibmq-provider` [like Aer did](https://github.com/Qiskit/qiskit-aer/pull/1589). 106 | * **benchmarks-out-of-metapackage**: The files in `test/benchmarks` construct . On this, there are the following options: (1) Create `qiskit/qiskit-benchmarks` or (2) move benchmark code `to Qiskit/qiskit-terra`. It is also possible to continue deploying the results in , in a different github page, or in . 107 | * **tutorials-out-of-metapackage**: The tutorials from `qiskit/qiskit-tutorials` are deployed to the website from the metapackage. They were designed to cover more than "just terra" when Qiskit was associated with multiple elements. The discussion on where those tutorials should go is independent of this task, which is about deploying them as stand-alone documentation. 108 | 109 | If users continue submitting issues on the metapackage for the moved parts, disabling issues for non-mainatainers is a last resort option. 110 | Historically, the issue traffic is relatively low so probably no need for that. 111 | 112 | ### ibmq-out-of-metapackage stage 113 | 114 | The `qiskit-ibmq-provider` documentation cannot be move to `qiskit/qiskit-terra`. 115 | In the [Qiskit release of July](https://github.com/Qiskit/qiskit-terra/milestone/30), the Qiskit metapackage only includes a single-dependency: `qiskit-terra` (without `qiskit-ibmq-provider` and `qiskit-aer`). The documentation The `qiskit/qiskit-ibmq-provider` repo is archived and the content associated with the `qiskit-ibmq-provider` package is removed from the metapackage (if it was not done before in empty-metapackage/ibmq-docs-out-of-metapackage) 116 | 117 | ### archive-metapackage stage 118 | 119 | At this point, the traffic to `qiskit/qiskit-metapackage` (and, as a consequence, to `qiskit/qiskit`) is the minimum that can be archived. The `qiskit/qiskit-metapackage` repository is getting ready to be can be archived. 120 | 121 | * **move-setup-out-of-metapackage**: Move metapackage setup.py to `qiskit/qiskit-terra`. The `qiskit/qiskit-terra` repo now build and publish the `qiskit` PyPI metapackage (with a single dependency) and the `qiskit-terra` PyPI package. 122 | * **pre-archive**: `qiskit/qiskit-metapackage` README file should link to the document in publish-plan stage, some instruction on how to navigate the history, and where the content is now. 123 | * **archive-metapackage**: Archive `qiskit-metapackage` repository. 124 | 125 | ### final stage 126 | 127 | * **final-rename**: The `qiskit/qiskit-terra` repository is renamed to `qiskit/qiskit`. [Github automatically retires repos with more than one 100 clones](https://github.blog/2018-04-18-new-tools-for-open-source-maintainers/#popular-repository-namespace-retirement) and the metapackage `qiskit/qiskit` is borderline popular. Luciano contacted GitHub Support and open an heads-up ticket (`#2073453`). If `qiskit/qiskit` repository namespace gets retired at metapackage-repo stage, at this point the GitHub ticket needs to be pinged and manually un-retired. 128 | * **fix-time**: There might be some broken scripts to update and some users that might require support 129 | * **final-announcement**: Blog post with announcement, covering the following items: 130 | 131 | * Explain to qiskit users that now they are qiskit devs now 132 | * "This clears up a lot of confusion" 133 | * Maybe a YouTube video, as it might be relevant to a more broader audience 134 | 135 | 136 | ### Support channels 137 | Besides the [regular support channels](https://qisk.it/support), affected users can: 138 | 139 | * ask questions in `#qiskit-repo-rename-support` in the [Qiskit Slack](https://qisk.it/join-slack). 140 | * Check FAQ in 141 | * Submit anonymous feedback to 142 | 143 | ## Questions 144 | 145 | **Why not manually moving `qiskit/qiskit-terra` code history, issues, and PRs to `qiskit/qiskit`?** 146 | 147 | There is no easy way to move PRs in GitHub. It is technically harder than renaming. Additionally, instead of mainly affecting metapackage users, the change would affect more `qiskit/qiskit-terra` developers. The current plan preserves the workflow of qiskit-terra developers which significantly outnumber metapackage developers. 148 | 149 | ## Future Extensions 150 | 151 | After archive-metapackage/move-setup-out-of-metapackage, the versions for packages `qiskit` and `qiskit-terra` are equalised and can be released at once and as one. This is planned for October release. 152 | -------------------------------------------------------------------------------- /0004-error-mitigation.md: -------------------------------------------------------------------------------- 1 | # Richardson error mitigation 2 | 3 | | **Status** | **Proposed/Accepted/Deprecated** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0004 | 6 | | **Authors** | Daniel Egger (deg@zurich.ibm.com) | 7 | | **Submitted** | 2020-05-20 | 8 | 9 | ## Summary 10 | Error mitigation can greatly improve results on noisy quantum hardware. 11 | This is done by running a given quantum circuit several times. 12 | In run i of the circuit the duration of all the gates is stretched by a factor c_i to increase the noise in the gates. 13 | An improved result is then obtained by extrapolating to the zero-order noise limit c->0. 14 | The purpose of this RFC is to discuss how to implement error mitigation in Qiskit such that it is usable in applications. 15 | 16 | ## Motivation 17 | Error mitigation allows users to significantly improve their results. 18 | It is expected that partners and members of the IBM Q network will benefit from this by being able to easily improve the quality of their results. 19 | 20 | ## User Benefit 21 | The target users of this work are those who run quantum circuits for applications of quantum computing. 22 | 23 | ## Design Proposal 24 | There are several ways to implement error mitigation. 25 | 26 | ### Simple error mitigation 27 | The simplest way to implement error mitigation is to run the quantum circuit several times. 28 | In each run the entangling two-qubit gate is replaced several entangling two-qubit gates such that the additional gates have no effect. 29 | For instance, replacing each CNOT gate in a quantum circuit by an odd number of CNOT gates results in the same quantum circuit in the ideal case. 30 | This has, for example, been implemented in https://arxiv.org/abs/1905.02666. 31 | This approach is also valid for other types of two-qubit gates such as the CZ gate. 32 | 33 | See https://github.com/Qiskit/qiskit-aqua/pull/683 which aims to implement this error mitigation method. 34 | 35 | **The advantage of this method is:** 36 | - Simplicity, it is easy to implement and understand. 37 | 38 | **The limitations of this method are**: 39 | - Quantum circuits that are already very deep may not see any gain since replacing each CNOT gate with three CNOT gates may produce circuits which, when executed, result in noise only. 40 | - It does not include single-qubit gates. 41 | - The effective stretch factors to chose from are very limited. 42 | - Some two-qubit gates, such as root-SWAP, need to be applied more than twice to compose to the identity. 43 | 44 | ### Backend constrained error mitigation 45 | When implementing error mitigation using stretch factors, as is done in https://arxiv.org/abs/1805.04492, new pulses must be defined and calibrated for the different stretch factors c_i. 46 | To implement error mitigation in the manner the backend could have a set of pre-defined calibrated pulses with different stretch factors. 47 | For instance, following Kandala et al., the backend could store calibrated pulses for c=1 (i.e. the pulses used in regular operations), c=1.1, c=1.25, and c=1.5. 48 | At execute time, the user would specify that he wants to run a quantum circuit using error mitigation. 49 | The assembler would then create four copies of the quantum circuit, each with a different stretch factor supported by the backend. 50 | Alternatively, the user could elect to use only a subset of the calibrate stretch factors. 51 | 52 | **The advantages of this method are:** 53 | - The user does not need to know much about error mitigation, a simple flag at execute time would most likely suffice. 54 | - This allows error mitigation to be applied on single-qubit and two-qubit gates. 55 | - Circuits that have many gates may still benefit from error mitigation as stetch factors such as c=1.1, c=1.25, and c=1.5 do not emphasis the noise as much as replacing each two-qubit gate by three two-qubit gates. 56 | - It is fast in that the user does not need to run many quantum circuits. 57 | 58 | **The limitations of this method are**: 59 | - The user cannot specify his own stretch factors. 60 | - It increases the amount of gates that the backend needs to calibrate. 61 | 62 | ### User specified error mitigation 63 | In a more complex implementation the user specifies which stretch factors to use. 64 | This will, therefore, require the user to run calibration procedures to calibrate the gates for each individual stretch factor before the intended quantum circuit can be run with error mitigation. 65 | This solution may be overly complex as the user has to calibrate himself the stretched gates. 66 | The calibration of stretched gates, could be automated to simplify the task for the user, but this would not decrease the run time. 67 | Qiskit-ignis would most likely need to be involved ontop of qiskit-aqua and qiskit-terra. 68 | 69 | **The advantages of this method are:** 70 | - It is very flexible. 71 | - This allows error mitigation to be applied on single-qubit and two-qubit gates. 72 | - The stretch factors may be chosen as a function of the depth of the quantum circuit. 73 | 74 | **The limitations of this method are**: 75 | - It requires a lot of knowledge from the user. 76 | - It requires that the user run many calibration jobs in addition to his quantum circuit. 77 | 78 | ## Detailed Design 79 | Here we focus on the implementation details of the Backend constrained error mitigation. 80 | An overview of this method is shown in the figure below. 81 | 82 | ![](0004-error-mitigation/202001_ErrorMitigation_summary.png) 83 | 84 | The backend will have a set of calibrated gates with different stretch factors that will be made available to Qiskit through the config file. 85 | A backend may implement as many stretch factors as is deemed reasonable by those who maintain the backend. 86 | A backend may also have the choice to not implement error mitigation at all. 87 | Ideally, each gate on the backend will be available with the same set of stretch factors. 88 | However, this may not always be the case. 89 | For example, a 20 qubit device may only have stretched gates calibrated for qubits zero to four. 90 | Therefore, the stretch factors will be specified in the `gateconfig` schema (see `qiskit/schemas/backend_configuration_schema.json`) which will be updated as follows 91 | ``` 92 | "gateconfig": { 93 | "type": "object", 94 | "required": ["name", "parameters", "qasm_def"], 95 | "properties": { 96 | ... 97 | "stretch_factor": { 98 | "type": "string" 99 | "description": "The stretch factor of the gate for error mitigation (if supported)." 100 | } 101 | } 102 | } 103 | ``` 104 | To facilitate the user experience, helper functions that show the available stretch factors, will be created. 105 | First, we define that a given qubit has stretch factor `c` available if all gates that involve this qubit are available with this stretch factor. 106 | The user will thus be able to query the backend to find out which stretch factors are available on a given list of qubits: 107 | ``` 108 | def available_stretch_factors(self, qubits: List) -> List: 109 | """Returns a list of stretch factors available for the given qubits.""" 110 | ``` 111 | For example to find the stretch factors available to qubits 0, 1, and 3, the user would do `backend.available_stretch_factors([0, 1, 3])`. 112 | Similarly, the user may query the backend to find out which qubits support a given list of stretch factors. 113 | This functionality may be useful for backends that have different stretch factors calibrated for different qubit sets. 114 | The following function implements this 115 | ``` 116 | def available_qubits(self, stretch_factors: List) -> List: 117 | """Returns a list of qubits for which the given stretch factors are available.""" 118 | ``` 119 | However, the user would need to know a priori which stretch factors are available on the backend. 120 | We would, therefore, only implement this function later on if we see a need for it. 121 | The user may also query the backend to find out how the error mitigation is configured. 122 | ``` 123 | def richardson_error_mitigation_config(self) -> List: 124 | """Returns a List of dict showing the available configuration of the richardson error mitigation.""" 125 | ``` 126 | The returned list would contain dictionaries of the form 127 | ``` 128 | {'stretch_factors': list, 'qubits': list}. 129 | ``` 130 | For example, the list 131 | ``` 132 | [ 133 | {'stretch_factors': ['1.0', '1.1', '1.25'], 'qubits': [0, 1, 2, 3]}, 134 | {'stretch_factors': ['1.0', '1.1'], 'qubits': [0, 1, 2, 3, 4]} 135 | ] 136 | ``` 137 | would imply that qubit 4 does not have stretch factor 1.25 available. 138 | 139 | To execute a quantum circuit with error mitigation, the user would do 140 | ``` 141 | execute(circ, backend, ..., error_mitigation='richardson') 142 | ``` 143 | to use all the stretch factors available to the qubits in the quantum register of `circ`. 144 | Additionally, the user may specify a subset of stretch factors to use by doing 145 | ``` 146 | execute(circ, backend, ..., error_mitigation='richardson', stretch_factors=[1.0, 1.25, 1.5]). 147 | ``` 148 | This will require a validation step, done in Qiskit Terra and based on the `config`, to check that the specified stretch factors are available for all of the qubits in the quantum register of `circ`. 149 | If this is not the case, an error will be raised. 150 | Here, `error_mitigation` specifies the error mitigation method to use. 151 | This value would by default be `None` when error mitigation is not used. 152 | The changes needed in Qiskit to implement error mitigation would require changes in the `assemble` function. 153 | `assemble` would detect that the user requires error mitigation and replace each circuit by several circuits, one for each stretch factor. 154 | The `experiments` in the resulting `qobj` would have an entry in the header that specifies the stretch factor. 155 | For example, the `qobj` for two circuits (`circA` and `circB`) to be run with error mitigation with three stretch factors would include six experiments, four of which would look like 156 | ``` 157 | print(qobj.experiments[0]) 158 | { 159 | 'config': {...}, 160 | 'header': {'name': 'circA_ef01a', 'stretch_factor': '1.0', ...}, 161 | 'instructions': {...} 162 | } 163 | 164 | print(qobj.experiments[1]) 165 | { 166 | 'config': {...}, 167 | 'header': {'name': 'circA_ef01b', 'stretch_factor': '1.1', ...}, 168 | 'instructions': {...} 169 | } 170 | print(qobj.experiments[3]) 171 | { 172 | 'config': {...}, 173 | 'header': {'name': 'circB_ec01a', 'stretch_factor': '1.0', ...}, 174 | 'instructions': {...} 175 | } 176 | 177 | print(qobj.experiments[4]) 178 | { 179 | 'config': {...}, 180 | 'header': {'name': 'circB_ec01b', 'stretch_factor': '1.1', ...}, 181 | 'instructions': {...} 182 | } 183 | ``` 184 | Here, the instructions for experiments 0, 1, and 2 are identical since they correspond to `circA`. 185 | The instructions for experiments 3, 4, and 5, are also identical since they correspond to `circB`. 186 | Therefore, the function `assemble_circuits`, called by assemble, will be modified. 187 | Currently, `assemble_circuits` contains a loop over the provided circuits: 188 | ``` 189 | for circuit in circuits: 190 | ... 191 | 192 | experiments.append(QasmQobjExperiment(instructions=instructions, header=header, 193 | config=config)) 194 | ``` 195 | We could modify this loop to be sensitive to error mitigation 196 | ``` 197 | for circuit in circuits: 198 | ... 199 | 200 | if error_mitigation == 'richardson': 201 | config = QasmQobjExperimentConfig(...) 202 | 203 | instructions = [] 204 | # code to create the instructions is unchanged 205 | 206 | for c in stretch_factors: 207 | header = QobjExperimentHeader(..., stretch_factor=c) 208 | 209 | experiments.append(QasmQobjExperiment(instructions=instructions, header=header, 210 | config=config)) 211 | else: 212 | header = QobjExperimentHeader(..., stretch_factor=None) 213 | experiments.append(QasmQobjExperiment(instructions=instructions, header=header, 214 | config=config)) 215 | ``` 216 | This implies that the header of the `QasmQobjExperiment` will need to be modified to include an attribute, namely the `stretch_factor`. 217 | 218 | ### Backend execution 219 | The backend will have to be able to detect that stretch factors are present in the header of the `qobj.experiments`. 220 | This will then signal to the backend what type of gates to use to execute each circuit. 221 | 222 | ### Result returned by the backend 223 | The result returned by the backend would contain the results for the circuits executed with different stretch factors. 224 | This result object could then be given to a Richardson error mitigation module in Qiskit Ignis that would perform the extrapolation to the zero-noise limit. 225 | This module would need to know which result is associated to which quantum circuit and stretch factor. 226 | This may be done by adding the required stretch factor as a parameter in the header of the result. For the example above, with `circA` and `circB`, the backend may return the `mitigated_result` in which the header of each result may look like 227 | 228 | ``` 229 | print(mitigated_result.results[0].header) 230 | Obj(name='circA', stretch_factor='1.0') 231 | print(mitigated_result.results[1].header) 232 | Obj(name='circA', stretch_factor='1.1') 233 | print(mitigated_result.results[3].header) 234 | Obj(name='circB', stretch_factor='1.0') 235 | print(mitigated_result.results[4].header) 236 | Obj(name='circB', stretch_factor='1.1') 237 | ``` 238 | 239 | Ideally, this module will give the user some freedom in how this extrapolation is done. 240 | 241 | Here are some additional considerations: 242 | - This implementation of error mitigation is only a meaningful option for quantum circuits and not for schedules. 243 | 244 | ## Alternative Approaches 245 | See section Simple error mitigation and section User specified error mitigation. 246 | 247 | Another alternative implementation is to encode the configuration of error mitigation in the `run_config` instanced passed to the `execute` function. 248 | This would avoid modyfing the signature of the `execute` function. 249 | 250 | ## Questions 251 | - The Backend constrained error mitigation requires extra effort from the backend to calibrate gates with different stretch factors. We need to check that the resulting overhead is acceptable. 252 | 253 | ## Future Extensions 254 | See section User specified error mitigation. 255 | -------------------------------------------------------------------------------- /0005-Aqua_circuit_interoperability.md: -------------------------------------------------------------------------------- 1 | # Aqua Circuit Interoperability Update 2 | 3 | | **Status** | **Deprecated** | 4 | |:------------------|:----------------------------------------------| 5 | | **RFC #** | 0005 | 6 | | **Authors** | Donny Greenberg (donny@ibm.com), Julien Gacon, Ali Javadi, Steve Wood | 7 | | **Submitted** | 2019-03-24 | 8 | | **Updated** | 2023-05-10 | 9 | 10 | 11 | ## Basic Vision & End Goal 12 | 13 | * Make Aqua use circuits as a first-class currency, and feel more like an algorithms library _next to_ Terra, as users expect, rather than an independent library on top of it 14 | * No more `construct_circuit()` wrappers in Aqua 15 | * Promote Aqua’s best circuity features into Terra to be broadly useful 16 | 17 | ## Proposal - Three steps 18 | 19 | 1. Circuit as a First-class Citizen in Aqua 20 | 1. Aqua algorithms accept circuits directly, no more circuit wrappers 21 | 1. Circuit Library with Enhanced QuantumCircuit Families and Convenient Prebuilts 22 | 1. Destination for most of Aqua's enhanced circuit wrappers 23 | 1. Critically, allows for lazily constructed circuit placeholders. 24 | 1. Usability Improvements to Promote up to QuantumCircuit 25 | 1. Make circuit construction in Terra more powerful with features in Aqua users like 26 | 27 | ## 1. Circuit as a First-class Citizen in Aqua 28 | 29 | * Anywhere previously calling `construct_circuit` now accepts circuits as-is, no questions asked 30 | * Typehints ask for a circuit, and are indifferent whether a circuit is from the circuit library (below) 31 | * Fully backwards compatible with Aqua's `construct_circuit`-based objects as long as we like 32 | * Maybe warnings where behavior is strange, e.g. no parameters in VQE ansatz 33 | 34 | ### Demo - VQC with newly built circuits 35 | 36 | Below, we demonstrate the execution of the Variational Quantum Classifier using no special circuit construction objects. 37 | 38 | 39 | ```python 40 | from qiskit import QuantumCircuit 41 | from qiskit.circuit import ParameterVector 42 | from qiskit.aqua.algorithms import VQC 43 | from qiskit.aqua.components.optimizers import SLSQP 44 | 45 | import numpy as np 46 | import itertools 47 | ``` 48 | 49 | 50 | ```python 51 | # Learning the one-hot encoding 52 | train_feats = np.eye(3).tolist() 53 | train_labels = [1,2,3] 54 | train = dict(zip(train_labels, train_feats)) 55 | print(train) 56 | ``` 57 | 58 | {1: [1.0, 0.0, 0.0], 2: [0.0, 1.0, 0.0], 3: [0.0, 0.0, 1.0]} 59 | 60 | 61 | 62 | ```python 63 | feat_params = ParameterVector('ɸ', length=len(train_feats[0])) 64 | feat_map = QuantumCircuit(3) 65 | depth = 3 66 | for _ in range(depth): 67 | feat_map.h(qubit=range(3)) 68 | [feat_map.rz(phi=p, qubit=i) for i, p in enumerate(feat_params)] 69 | [feat_map.crz(theta=p1*p2, control_qubit=q1, target_qubit=q2) 70 | for ((q1, p1), (q2,p2)) in itertools.combinations(enumerate(feat_params), 2)] 71 | feat_map.barrier() 72 | feat_map.draw(output='mpl') 73 | ``` 74 | 75 | 76 | 77 | 78 | 79 | ![png](0005-Aqua_circuit_interoperability/output_7_0.png) 80 | 81 | 82 | 83 | 84 | 85 | ```python 86 | # Note: I need to calculate this number 87 | classifier_params = ParameterVector('θ', length=19) 88 | classifier = QuantumCircuit(3) 89 | depth = 3 90 | cp_iter = iter(classifier_params) 91 | next(cp_iter) 92 | for _ in range(depth): 93 | [classifier.ry(theta=next(cp_iter), qubit=j) for j in classifier.qubits] 94 | [classifier.crx(theta=next(cp_iter), control_qubit=q1, target_qubit=q2) 95 | for (q1, q2) in itertools.combinations(classifier.qubits, 2)] 96 | classifier.barrier() 97 | classifier.draw(output='mpl') 98 | ``` 99 | 100 | 101 | 102 | 103 | 104 | ![png](0005-Aqua_circuit_interoperability/output_8_0.png) 105 | 106 | 107 | 108 | 109 | 110 | ```python 111 | vqc = VQC(optimizer=SLSQP(), 112 | data_circuit=feat_map, 113 | classifier_circuit=classifier, 114 | training_dataset=train, 115 | test_dataset=train) 116 | vqc.run() 117 | ``` 118 | 119 | ## 2. Circuit Library with Enhanced Flexibility Circuits and Convenient Prebuilts 120 | 121 | _Proposal: Move Aqua's circuit-constructor objects - e.g. Ansatze, QFTs, Arithmetic - into a broadly useful circuit-library as flexible QuantumCircuit objects with enhanced features._ 122 | 123 | #### New Concepts in the Circuit Library 124 | * Circuit Blueprints: Enhanced QuantumCircuit objects which are lazily populated and constructed, but print and interact as bona-fide circuits. 125 | * Not a new class, simply subclasses of QuantumCircuit which match the QuantumCircuit interface 126 | * Users generally shouldn't notice the difference, unless digging into circuit guts in debugging 127 | * Properties such as `.data`, `.parameters`, etc. which require real circuits, trigger construction and caching of constructed circuit 128 | * Meta-parameters, such as ansatz depth or connectivity, are mutable and edited lightly due to lazy construction. Setters trigger cached circuit wipe 129 | * Circuit Families 130 | * Collections of circuit blueprints or prebuilt circuits with extensions or use-case specific features - e.g. `PermutationCircuit`s can include properties which `ArithmeticCircuit`s do not. 131 | * Allow for more aggressive convenience functionality for specific use cases e.g. Ansatz automatically allocating parameters during construction. 132 | 133 | #### Options for Circuit Library Placement 134 | 1. Inside Terra, with integration tests 135 | 1. Pros - Consistent with user expectations that Terra contains circuit building blocks 136 | 1. Cons - Unlike other areas, Terra has many directories in the base qiskit level, include `qiskit/circuit/`. The library could not clearly be a `circuits` directory alongside Terra, but would likely be hidden inside `qiskit/circuit/library/`. May complicate Aqua development, requiring frequent multi-repo PRs and exactly synced releases. 137 | 1. Inside Aqua, with Qiskit-wide utility, no Aqua concepts 138 | 1. Pros - Can be placed in a `qiskit/circuit_library` directory alongside `qiskit/aqua`, giving clear delineation as an important library of circuits. 139 | 1. Cons - Users may not expect to find this in Aqua, and distinction between "complicated Terra gate" (e.g. MCT) and "simple library circuit" would make keeping these so far apart strange. 140 | 1. In its own repo 141 | 1. Pros - Clear importance and delineation. 142 | 1. Cons - Another repo. 143 | 144 | #### Options for Circuit Family Organization 145 | The circuit library is still a work in progress. In each of the below options, we can make all of the circuits importable from the base init, allowing us to iterate on the directory organization without breaking changes to circuit usage. This way, we can ensure that the circuits are in the correct location in Qiskit for Aqua to begin using them, rather than wait for the library to be complete, and then execute a breaking change to merge in Aqua's circuits. 146 | 147 | 1. **Organize By Circuit Purposes** 148 | 1. Data Preparation Circuits 149 | 1. Data Feature Maps 150 | 1. Probability Distributions 151 | 1. NLocal Circuits (name pending - needs to reflect purpose and availability of Optimization-specific features and properties, such as optimization_bounds and auto-parameterization). 152 | 1. TwoLocalCircuit 153 | 1. NLocalCircuit 154 | 1. Ry, RyRz, SwapRz 155 | 1. Arithmetic Circuits 156 | 1. Adders 157 | 1. Reciprocals 158 | 1. MCTs 159 | 1. Hamming weight 160 | 1. Basis Change Circuits 161 | 1. QFTs 162 | 1. QFT Placeholder/Base 163 | 1. QFT circuits 164 | 1. QWT Circuits 165 | 1. DCT Circuits 166 | 1. Pauli Basis Change 167 | 1. Oracle Circuits 168 | 1. Truth table 169 | 1. Logical expression 170 | 1. Phase oracle 171 | 1. Permutation oracle 172 | 1. Function Testing Circuits 173 | 1. Fourier Checking 174 | 1. Hidden shift with Bent Boolean functions 175 | 1. Ideal Hidden Linear Function circuits 176 | 1. Benchmarking 177 | 1. Near-Clifford / graph states 178 | 1. Random uniform 179 | 1. Quantum Volume 180 | 1. CNOT Dihedral (from Ignis) 181 | 182 | 1. **Organize By Circuit Form Factors** - Organization followed by internal quantum-circuits repo. Methodology is organization by the subcircuits and organization of the circuits themselves. 183 | 1. Random uniform 184 | 1. NLocal Circuits 185 | 1. NLocal, TwoLocal, Ry, RyRz, SwapRz 186 | 1. Linear rotation 187 | 1. Near-Clifford / graph states 188 | 1. Pauli Basis Change 189 | 1. Quantum volume 190 | 1. Quantum Fourier transform 191 | 1. Ideal HLF circuits 192 | 1. Hamming weight 193 | 1. Hidden shift with bent Boolean functions 194 | 1. Multiply-controlled NOT gate 195 | 1. IQP circuits 196 | 1. Fourier checking 197 | 1. Unresolved - It's unclear into which families the following circuits fall in the above grouping: 198 | 1. Artimetic 199 | 1. QFT vs. CNOT based adders 200 | 1. Cutoff vs. long-division based reciprocals 201 | 1. Oracle circuits 202 | 1. Data Feature Maps 203 | 1. Broader than forrelation by accepting different paulis to evolve, rather than just Z^n, but also each only half of a forrelation circuit 204 | 1. Can be other classes of hard circuits, not only forrelation-based 205 | 206 | 1. **Some Purpose, Some Complexity Families** - Allow both circuit purpose families and circuit form-factor families, allowing for custom enhancements or functionality in either family type. Circuits can act as placeholders (e.g. permutation) to be filled in by a choice of several synthesis implementations later. Circuits can also import circuits from other families so both practical and theoretical expectations are met without code duplication. 207 | 1. Data Preparation Circuits 208 | 1. Data Feature Maps 209 | 1. Probability Distributions 210 | 1. Arithmetic Circuits 211 | 1. Basis Change Circuits 212 | 1. Quantum Fourier Transform Circuits 213 | 1. Oracle Circuits 214 | 1. N Local Circuits 215 | 1. NLocal, TwoLocal, Ry, RyRz, SwapRz 216 | 1. Near-Clifford / Graph State Circuits 217 | 1. Quantum Volume Circuits 218 | 1. Ideal Hidden Linear Function Circuits 219 | 1. Hamming Weight Circuits 220 | 1. Hidden Shift with Bent Boolean Function Circuits 221 | 1. Multiply-controlled NOT Gate Circuits 222 | 1. IQP Circuits 223 | 1. Fourier Checking Circuits 224 | 225 | 1. **Two Subdirectories** - One corresponding to circuit purpose families, one corresponding to circuit complexity families. All circuits can be imported from `qiskit.circuit.library` so organization is aesthetic. 226 | 1. Circuit Purpose Families 227 | 1. Data Preparation Circuits 228 | 1. Data feature maps 229 | 1. probability_distributions 230 | 1. NLocal Circuits 231 | 1. TwoLocalCircuit, NLocalCircuit, Ry, RyRz, SwapRz 232 | 1. Arithmetic Circuits 233 | 1. Basis Change Circuits 234 | 1. QFT, QWT, DCT 235 | 1. Pauli Basis Change 236 | 1. Oracle Circuits - Truth table, Logical expression, Phase oracle, Permutation oracle 237 | 1. Circuit Complexity Families 238 | 1. Random uniform 239 | 1. Hardware efficient 240 | 1. Near-Clifford / graph states 241 | 1. Quantum volume 242 | 1. Quantum Fourier transform 243 | 1. Ideal HLF circuits 244 | 1. Hamming weight 245 | 1. Hidden shift with bent Boolean functions 246 | 1. Multiply-controlled NOT gate 247 | 1. IQP circuits 248 | 1. Fourier checking 249 | 250 | _Additional Proposal: HardwareEfficient base class - abstract `target_backend` setter (QFTs, adders, NLocal, etc. can choose how to interpret what to do with backend information and provide specially tailored circuits for hardware which are not available by transpilation alone.)_ 251 | 252 | ##### Organization Recommendation: Option 1 or 3 253 | Option 1 or 3 introduces the most broadly useful organization to both the algorithms and complexity theory users, attempting to align with both of their expectations for circuit placement. They provide the greatest chance of mutual exclusivity in families, allowing families to be grouped in whichever way most naturally delineates them from the other circuit families based on industry conventions (rather than attempt at some form of objective delineation, which is unlikely to be future-proof). Minimizing ambiguities is a worthwhile long-term investment when this library could reasonably grow to hundreds of classes. 254 | 255 | We recommend beginning with Option 1 _quietly_ to be able to migrate the circuits out of Aqua, and reorganize within the library as it is formally built out and new circuit families are added. This is functionally identical to Option 3, as the form-factor circuit families are not yet ready to be pushed to the library, and will need to be merged as a separate step. This will also allow for more time and deliberation about this complex organization question. Allowing all circuits to be imported from the base circuit library directory prevents the impending reorganizations from introducing breaking changes. 256 | 257 | ### Demo 2 - Powerful New QuantumCircuit Objects 258 | 259 | 260 | ```python 261 | from chemistry.code.molecule import Molecule 262 | from qiskit.chemistry.components.initial_states import HartreeFock 263 | from qiskit.aqua.algorithms import VQE 264 | # from qiskit.circuit_.library import RyRz 265 | 266 | from qiskit import BasicAer 267 | qasm = BasicAer.get_backend('qasm_simulator') 268 | ``` 269 | 270 | 271 | ```python 272 | hh = Molecule(geometry=[['H', [0., 0., 1.]], 273 | ['H', [0., 0.45, 1.]], 274 | ]) 275 | hamiltonian = hh.get_qubitop_hamiltonian() 276 | molecular_wf = HartreeFock(hh) + RyRz(depth=3, entanglement='linear') 277 | gse = VQE(wf_ansatz=molecular_wf, optimizer=SLSQP, backend=qasm).compute_minimum_eigenvalue(hamiltonian) 278 | print(gse) 279 | ``` 280 | 281 | 282 | ```python 283 | molecular_qf.target_backend = IBMQ.get_backend('ibmq_valencia') 284 | ``` 285 | 286 | ## 3. QuantumCircuit Usability Improvements 287 | 288 | Aqua's circuit_constructors have accumulated many powerful features not present in QuantumCircuit. No changes are strictly needed to QuantumCircuit to support the above proposals, but we can promote some of these improvements up to QuantumCircuit base to make these features broadly available. 289 | 290 | * Suggested for immediate promotion: 291 | * Mutable qubit number (delete qubits, or extend circuit) for anonymous register circuits 292 | * `.parameters` returns a list instead of a set, as parameter randomization is inconvenient 293 | * Further opportunities for radical circuit control 294 | * Lazy parameterization - When no parameter is specified in a parameterized standard gate, create a new one for the user. We can do this lazily, and only create the full list when `.parameters` is called, in which case the list is "locked in." 295 | * Lazy broadcasting - Similar to the NLocal Circuits. Allow the user to specify groups of qubits to which to apply a gate in circuit construction, but only construct these duplicates when the circuit data is actually needed. Allow users to manipulate these gate applications. 296 | * What we’d need to do to implement these two 297 | 298 | Demo 4 - Interface demo of further opportunities 299 | 300 | 301 | ```python 302 | # Working notes - Captures new features but doesn't highlight them exactly 303 | my_c = QuantumCircuit(4) 304 | my_c.h(qubits='all') 305 | my_c.cu3(qubits='full', theta=.5) # other two parameters are set to be parameterized under the hood 306 | my_c.h(qubits='all') 307 | my_c.rz(qubits='all', phi=Parameter('theta')) # Sets the same parameter for all of them 308 | ``` 309 | -------------------------------------------------------------------------------- /0016-sampler-interface.md: -------------------------------------------------------------------------------- 1 | # SamplerV2 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0016 | 6 | | **Authors** | Lev Bishop (lsbishop@us.ibm.com) | 7 | | | Ian Hincks (ian.hincks@ibm.com) | 8 | | | Blake Johnson (blake.johnson@ibm.com) | 9 | | | Chris Wood (cjwood@us.ibm.com) | 10 | | **Submitted** | 2023-10-03 | 11 | | **Updated** | 2023-12-18 | 12 | 13 | 14 | ## Summary 15 | 16 | This RFC proposes an interface for the next version of the `Sampler`. 17 | The changes proposed here mirror those accepted in [the paired Estimator interface RFC](https://github.com/Qiskit/RFCs/pull/51), where the arguments of the `Estimator.run()` signature were transposed to accept, instead of three iterable arguments, an iterable of "PUBs", with each PUB comprising a circuit and auxiliary execution information. 18 | In the case of the `Sampler`, a PUB consists only of a circuit and an array of parameter value sets if it is a parametric circuit. 19 | We aim to move the `Sampler` to be a viable replacement for `backend.run`, and eliminate the notion of sample weights (i.e. quasi-probabilities). 20 | 21 | ## Motivation 22 | 23 | We will propose a `Sampler` that 24 | 25 | * _Obeys program outputs._ Every circuit defines a set of classical registers whose output names and types are known before execution. The prototypical type is a bit-array, but the OpenQASM 3 specification allows many other types, too, which Qiskit aims to follow. The current return structure of the sampler does not handle this gracefully, squishing bitstrings from separate registers together. It also does not attempt make a careful distinction between sampling from a program's output registers, and sampling from the output state that it prepares---it did not need to as these two views are equivalent for circuits that measure all qubits at the end of the circuit. However, this proposal takes the former stance, and separates returned data according to its output names. The motivation for this choice is that it would make the `Sampler` fully compliant with dynamic circuits. 26 | * _Naturally allows multiple parameter value sets._ A common use case for many users is running the same parametric program with many parameter value sets in the same `run()` invocation. These changes will make it easier for implementations to do this efficiently with late-stage binding. Efficient invocation of the same parametric circuit between multiple `run()` invocations is out of scope of this RFC. 27 | * _Is a "`memory=True`" execution model._ We will break from the tradition of using a mapping structure as the default container type for circuit execution. Instead, results will always be returned in a format where one output axis iterates over shots, and maintains execution order. The motivation is that, in a program whose total output size is more than 100 qubits, due to gate and measurement noise, the chances that any two output values are equal to each other is too small to make special accomodation for via a hash map. When the output size is smaller than this loose threshhold, so that output value collisions are likely, the data will take up less space anyways. Container objects will contain methods returning count-like structures to ease migration. 28 | * _Has no sample weights._ The current sampler attaches real weights summing to one to all samples. In effect, it returns an estimate of a (quasi)-distribution instead of samples from the distribution. This proposal eliminates this feature and returns only samples, and without weights. The rationale is to make the `Sampler` into more of a streamlined circuit executor, paring down all frills. 29 | 30 | 31 | ## User Benefit 32 | 33 | Users will be able to transition from `backend.run` to `sampler.run` without any compromises in execution efficiency. They will be able to run dynamic circuits without having to specify special flags, or invoke a special program. They will get their outputs in a format where they don't need to manually separate bitstrings from different registers. 34 | 35 | As with the [(paired Estimator inteface RFC)[https://github.com/Qiskit/RFCs/pull/51]](https://github.com/Qiskit/RFCs/pull/51), implementations will more easily be able to enable features like late stage parameter value binding. 36 | 37 | ## Design Proposal 38 | 39 | We will lead the design proposal with an example. 40 | 41 | ```python 42 | # Our first circuit has many Parameters, but elects to do all measurement at 43 | # the end. Note that measure_all() chooses the register name "meas" for you. 44 | circuit1 = QuantumCircuit(9) 45 | ... 46 | 47 | ... 48 | circuit1.measure_all() 49 | 50 | # Specify 128 different parameter value sets for circuit1, in a 32x4 shape. 51 | parameter_values1 = np.random.uniform(size=(32, 4, 2039)) 52 | 53 | # Our second circuit happens to have no parameters, but three output registers 54 | # named alpha, beta, and gamma of various sizes 55 | alpha = ClassicalRegister(127, "alpha") 56 | beta = ClassicalRegister(10, "beta") 57 | gamma = ClassicalRegister(15, "gamma") 58 | circuit2 = QuantumCircuit(QuantumRegister(127), alpha, beta, gamma) 59 | ... 60 | 61 | ... 62 | 63 | # invoke a sampler 64 | sampler = Sampler(..., shots=1024) 65 | job = sampler.run([ 66 | (circuit1, parameter_values1), 67 | circuit2 68 | ]) 69 | 70 | # wait for the result 71 | job.result() 72 | 73 | # get a bundle of results for every PUB 74 | >> PrimitiveResult( 75 | >> SamplerPubResult( 76 | >> DataBundle(meas=BitArray()), 77 | >> 78 | >> ), 79 | >> SamplerPubResult( 80 | >> DataBundle( 81 | >> alpha=BitArray(), 82 | >> beta=BitArray(), 83 | >> gamma=BitArray() 84 | >> ), 85 | >> 86 | >> ), 87 | >> metadata= 88 | >> ) 89 | ``` 90 | 91 | The above example shows various features of the design. 92 | Notice the output results are placed in a `DataBundle`, a namespace container described [here](https://github.com/Qiskit/RFCs/pull/53), with one entry for each output of the corresponding PUB's circuits. 93 | These circuits only have bit-array outcomes, as allowed by Qiskit, and therefore all results have type `BitArray`, described later. 94 | For now, consider the following usage examples. 95 | 96 | ```python 97 | 98 | # get result from the second PUB above 99 | result = job.result()[1] 100 | 101 | # get the entire quasi-probability distribution 102 | result.get_quasiprobabilities() 103 | >> QuasiProbabilityDistribution({1351235663: 0.0009765625, 325: 0.0009765625, 45262346723465234523453: 0.0009765625, 35435345235234372457453: 0.0009765625, ...}) 104 | 105 | # marginalize a couple of indexes in the beta output 106 | result.data.beta.get_counts(marginalize_idxs=[0, 1]) 107 | >> Counts({"00": 189, "10": 11, "01": 801, "11": 123}) 108 | 109 | # flip all of the bits in the gamma according to some other compatibly-shaped bit-array 110 | flips = BitArray(my_flips, num_bits=15) 111 | flipped_gamma = result.data.gamma ^ flips 112 | ``` 113 | 114 | If a circuit had a non bit-array outcome, it would use a different type in place of `BitArray`. 115 | We suggest just using `numpy.ndarrays` with the closest appropriate `dtype` for non-bit-array outputs. 116 | The shape of such an array would be `(*pub_shape, num_samples, *output_register_shape)`. 117 | For particular types, like `angle`, if it is for some reason decided that no NumPy type is satisfactory, 118 | we can add more containers analagous to `BitArray`. 119 | 120 | The detailed signature is as follows: 121 | 122 | ```python 123 | T = TypeVar("T", bound=Job) 124 | 125 | BindingsArrayLike = Union[ 126 | BindingsArray, 127 | NDArray, 128 | Dict[Parameter | Tuple[Parameter], NDArray] 129 | ] 130 | 131 | SamplerPubLike = Union[ 132 | SamplerPub, 133 | QuantumCircuit, 134 | Tuple[QuantumCircuit, BindingsArrayLike] 135 | ] 136 | 137 | class SamplerBaseV2(PrimitiveBase[SamplerPub, SamplerPubResult]): 138 | ... 139 | def run( 140 | self, pubs: SamplerPubLike | Iterable[SamplerPubLike] 141 | ) -> Job[PrimitiveResult[SamplerPub, SamplerPubResult]]: 142 | pass 143 | ``` 144 | 145 | 146 | ## Detailed Design 147 | 148 | Most new types and conventions have been described in either [the paired Estimator RFC](https://github.com/Qiskit/RFCs/pull/51) or the (`BasePrimitive.run()` RFC)[https://github.com/Qiskit/RFCs/pull/53]. 149 | 150 | ### PUBs and PUB Results 151 | 152 | A PUB consists of a `QuantumCircuit` and, if it has parameters, a `BindingArray` that specifies an array of parameter value sets each of which to bind it against during execution. 153 | 154 | A `SamplerPubResult` is a subclass of `PubResult` with the addition of methods for convenience, and to ease migration. For example, 155 | 156 | ```python 157 | class SamplerPubResult(PubResult): 158 | def get_quasiprobabilities(self, loc: Tuple[int, ...] | None = None) -> QuasiProbabilityDistribution: 159 | """Join all bit-array output registers together into a new quasi-probability distribution. 160 | 161 | Args: 162 | loc: Which PUB coordinate to fetch. 163 | 164 | Raises: 165 | ValueError: If no ``loc`` is given and this PUB result is more than 0-D. 166 | """ 167 | 168 | def get_counts(self, loc: Tuple[int, ...] | None = None) -> Counts: 169 | """Join all bit-array output registers together into a new counts structure. 170 | 171 | Args: 172 | loc: Which PUB coordinate to fetch. 173 | 174 | Raises: 175 | ValueError: If no ``loc`` is given and this PUB result is more than 0-D. 176 | """ 177 | ``` 178 | 179 | ### BitArray 180 | 181 | To store lots of bit-array outcomes, to enable fast iteration over bitstrings, and to enable bitwise operations, we propose a container that has a contiguous memory model over the entire shot-loop, where 8-bits are packed to the byte. 182 | For this purpose, we choose to use a NumPy `uint8` array because, unlike `bytes` or `bytearray`, it has convenient methods for slicing and indexing multiple dimensions. 183 | Its buffer can be directly accessed for those not wishing to use NumPy, and, as seen both in the previous section and also below, we can include convenience methods for converting to, for example, a `Counts` object. 184 | We choose a convention where the second to last axis is over samples (shots), and the last dimension has a big-endian byte order which describes a single value of the output bit-array. 185 | For example, ``np.array([[1, 1], [2, 0]], dtype=np.uint8)`` would describe 2 shots with outcomes `257 = (1 << 8) + 1` and `512 = (2 << 8) + 0` in decimal, respectively. 186 | 187 | However, a `uint8` array alone is insufficient because, at the very least, it is incapabable of specifying whether it describes a bit-array register of size 14 or 16, for example, both of which require two bytes. 188 | For this reason, and to handle convenience methods, we introduce the `BitArray`. 189 | A bare bones sketch is below. 190 | Methods like `__or__` or static constructors from other formats are in-scope of the vision, but excluded for brevity. 191 | 192 | ```python 193 | class BitArray(ShapedMixin): 194 | """Stores bit-array outcomes.""" 195 | 196 | def __init__(self, array: NDArray, num_bits: int): 197 | """ 198 | Args: 199 | array: The data, where the last axis is over packed bits whose byte order is 200 | big-endian, the second last axis is over shots, and the preceding axes 201 | correspond to the shape of the experiment. 202 | num_bits: How many bit are in each outcome; the size of the bit-array register. 203 | """ 204 | self._array = np.array(array, copy=False, dtype=np.uint8) 205 | if self._array.ndim < 2: 206 | raise ValueError("The data arary needs to be at least 2-D") 207 | self._num_bits = num_bits 208 | if self._array.shape[-1] * 8 < self._num_Bits: 209 | raise ValueError("The last axis of the data array is not big enough.") 210 | # second last dimension is shots, last dimension is packed bits 211 | self._shape = self._array.shape[:-2] 212 | 213 | def __repr__(self): 214 | desc = f"" 215 | return f"BitArray({desc})" 216 | 217 | @property 218 | def array(self) -> NDArray[np.uint8]: 219 | """The raw array of data.""" 220 | return self._array 221 | 222 | @property 223 | def num_bits(self) -> int: 224 | """The number bits in each outcome.""" 225 | return self._num_bits 226 | 227 | @property 228 | def num_samples(self) -> int: 229 | """The number of samples.""" 230 | return self._array.shape[-2] 231 | 232 | def get_counts(self, loc: Tuple[int,...] | None = None, marginal_idxs: Tuple[int,...] | None = None) -> Counts: 233 | def get_counts(self, idx: Tuple[int, ...] | None = None) -> Counts: 234 | """Join all bit-array output registers together into a new counts structure. 235 | 236 | Args: 237 | idx: Which PUB coordinate to fetch. 238 | 239 | Raises: 240 | ValueError: If no ``idx`` is given and this PUB result is more than 0-D. 241 | """ 242 | ``` 243 | 244 | ### Measurement Levels 245 | 246 | [IBM's implementation](https://github.com/Qiskit/qiskit-ibm-provider/) of the `backend.run` interface has the notion of measurement levels which specify whether measurement instructions cause traces, complex phases, or discriminated bits to be returned. While this notion of measurement levels is not required by the existing `backend.run` interface, we wish to describe how to support this use case within this revised `Sampler`. 247 | Eventually, measurement levels should be specified inside of a circuit itself by measuring into complex valued registers, as described in the OpenQASM 3 specification. 248 | This would effectively enable a mix-and-match between different measurement levels, and also allow a circuit to determine its own output types. 249 | 250 | However, before this becomes available, in order to acheive feature parity with `backend.run`, we propose implementing this as a flag (similar to `backend.run`) whose value changes the type of all bit-array outputs from `BitArray`s to NumPy arrays with `dtype=np.complex128`. 251 | 252 | ```python 253 | class MeasLevel(enum.Enum): 254 | # TRACES = 0 unsupported 255 | PHASES = 1 256 | BITS = 2 257 | ``` 258 | 259 | Phases for each shot: 260 | 261 | ```python 262 | sampler.run([(circuit1, parameter_values1), circuit2], meas_level=MeasLevel.PHASES).result() 263 | >> PrimitiveResult( 264 | >> SamplerPubResult( 265 | >> DataBundle(meas=np.ndarray()), 266 | >> 267 | >> ), 268 | >> SamplerPubResult( 269 | >> DataBundle( 270 | >> alpha=np.ndarray( 271 | >> beta=np.ndarray( 272 | >> gamma=np.ndarray( 273 | >> ), 274 | >> 275 | >> ), 276 | >> metadata= 277 | >> ) 278 | ``` 279 | 280 | ## Migration Path 281 | 282 | We propose the same path as [the paired Estimator RFC](https://github.com/Qiskit/RFCs/pull/51). Convenience methods can be placed on result containers to transform into familiar return types. 283 | -------------------------------------------------------------------------------- /0012-Pulse-Compiler-and-IR.md: -------------------------------------------------------------------------------- 1 | # Pulse Compiler & IR 2 | 3 | | **Status** | **[Not planned](https://github.com/Qiskit/RFCs/pull/73)** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0012 | 6 | | **Authors** | Tsafrir Armon (tsafrir.armon@ibm.com) | 7 | | | Naoki Kanazawa (knzwnao@jp.ibm.com) | 8 | | **Submitted** | 2023-07-31 | 9 | | **Updated** | 2023-08-07 | 10 | 11 | ## Summary 12 | This RFC summarizes the proposal for new Pulse Compiler & IR. The introduction of the new compiler paves the way to the transition to frame aware model, which is also discussed. 13 | The proposal is based on a series of discussions 14 | within Qiskit Pulse's development team, and is brought here for the community to weigh in. The main changes proposed include: 15 | 16 | - Introduction of a new pass based Pulse Compiler and the supporting Pulse IR (intermediate representation). 17 | - Introduction of a new model to supplement the existing `Channel` model, that will allow writing backend-agnostic template pulse programs. 18 | 19 | Comments are welcome. 20 | 21 | ## Motivation 22 | Qiskit Pulse currently has no unified compilation pathway - Different tasks are handled by the different code segments. This not only creates code clutter which is hard to maintain, 23 | but also limits the ability of vendors to adapt Qiskit Pulse, or adjust Qiskit Pulse to new HW developments. The circuit module of Qiskit already uses a pass based compilation process, 24 | which gives the flexibility to add\change\adapt passes according to the changing needs. 25 | 26 | A prime example for the need for a better compilation process, is given by the second part of this proposal - rework of the `Channel` model. 27 | 28 | The legacy `Channel`s correspond to what the backend calls a mixed frame - a combination of specific HW port, and the frame (frequency and phase) needed to play pulses. 29 | However, to specify a Channel one must be aware of the backend mapping. For example, the following pulse schedule is an ECR pulse for qubits 3 and 4: 30 | 31 | ```python 32 | with builder.build() as ecr_schedule_q3q4: 33 | with align_sequential(): 34 | with align_left(): 35 | Play(GaussianSquare(...), ControlChannel(6)) 36 | Play(GaussianSquare(...), DriveChannel(4)) 37 | Play(Gaussian(...), DriveChannel(3)) 38 | with align_left(): 39 | Play(GaussianSquare(...), ControlChannel(6)) 40 | Play(GaussianSquare(...), DriveChannel(4)) 41 | ``` 42 | 43 | Note how one can't make sense of the code, without knowing the mapping of the control channels. 44 | Similarly, frame synchronization also has to be carried out manually and depends on the backend mapping. 45 | This dependency on the backend prohibits the ability to write a template code, which in turn complicates modules like Qiskit Experiments. 46 | 47 | Under the new proposal, the dependency on backend mapping will be removed, and Qiskit Pulse users (and particularly Qiskit Experiments users) will be able to write 48 | backend-agnostic template programs, which could be used across devices. Additionally, custom frames will make it easier to experiment with qudit control. 49 | However, supporting this change adds significant compilation needs, which are hard to implement in the current workflow. 50 | 51 | ## User Benefit 52 | - Qiskit contributors as well as vendors will have a unified compilation code which will be simpler to adjust for future needs and changes. 53 | - Qiskit Pulse users will have a clearer and more efficient way to write their Pulse programs. 54 | - Qiskit Experiments users will be able to write more streamlined template experiments. 55 | - Qiskit Pulse users will have easier access to qudit control. 56 | 57 | ## Design Proposal 58 | The new pulse compiler will be a pass based compiler. Dedicated passes will perform every analysis, 59 | transformation and validation operations needed to convert a pulse program into a desired output format. A detailed workflow will be described below, but the main tasks include 60 | concretely scheduling `ScheduleBlock` programs, mapping virtual qubits to physical ones, applying backend constraints, and converting to desired output format. To support this, 61 | the new IR will consist of nested instruction blocks, which will be transformed by the compiler as it operates. 62 | 63 | Regarding the `Channel` model rework, one can schematically split Qiskit Pulse's user interface into three layers - 64 | 65 | - Pulse level (`SymbolicPulse`,`WaveForm`) 66 | - Instruction level (`Play`,`Delay`...) 67 | - Program level (`Schedule`,`ScheduleBlock`) 68 | This rework focuses on the instruction level. The main goal is to allow for clear and simple backend agnostic (but not architecture agnostic) pulse templates. 69 | To do this, the legacy `Channel`s will be supplemented by `Frame`s and `LogicalElement`s. 70 | 71 | No API breaking changes are needed. New and legacy options can coexist. 72 | 73 | ## Detailed Design 74 | ### Channel rework 75 | To replace the legacy `Channel`s we propose to specify instructions in terms of `LogicalElement`s and `Frame`s: 76 | 77 | - `LogicalElement` - every type of element in the HW which the user can control ("play pulses on"). For example, a qubit is a `LogicalElement`, and not the specific port used to drive it. The most notable example of a logical element is of course the `Qubit`, but in the future one can imagine dedicated couplers, flux controls and so on. 78 | - `Frame` - a combination of frequency and phase. Subclasses used to identify the frame with a backend default. Notable examples are `QubitFrame` and `MeasurementFrame` associated with the default driving and measurement frequencies (respectively) of a qubit. 79 | 80 | Using these objects, the above code takes the form: 81 | 82 | ```python 83 | with builder.build() as ecr_schedule_q3q4: 84 | with align_sequential(): 85 | with align_left(): 86 | Play(GaussianSquare(...), Qubit(3),QubitFrame(4)) 87 | Play(GaussianSquare(...), Qubit(3),QubitFrame(3)) 88 | Play(Gaussian(...), Qubit(3),QubitFrame(3)) 89 | with align_left(): 90 | Play(GaussianSquare(...), Qubit(3),QubitFrame(4)) 91 | Play(GaussianSquare(...), Qubit(3),QubitFrame(3)) 92 | ``` 93 | 94 | The new code not only allows to work with virtual backend-agnostic qubits, but is also much clearer in conveying the actual actions in play (acting on qubit 3 with the frame of qubit 4 vs with the frame of qubit 3). 95 | 96 | On top of the `LogicalElement` and the `Frame`, another layer of `MixedFrame` will be introduced. 97 | The `MixedFrame` is simply a combination of a `LogicalElement` and a `Frame`, and in many ways is similar to the legacy `Channel`. 98 | The difference being that a `MixedFrame` does not depend on the backend mapping and has clear relations with other `MixedFrames` as opposed to a `Channel` which hasn't. 99 | Play\Delay instructions will be allowed to take one of `LogicalElement`+`Frame`, `MixedFrame` or `Channel` (for backwards compatibility). 100 | Set\Shift Frequency\Phase will be allowed to take one of `Frame` (to be broadcast to every associated `MixedFrame`), `MixedFrame` (not to be broadcasted) or `Channel`. 101 | 102 | It should be noted that custom `Frame` and `MixedFrame` will make it easier to control qudit experiments. 103 | 104 | Classes hierarchy: 105 | 106 | ```python 107 | class LogicalElement(ABC): 108 | @property 109 | def index(self) -> Tuple[int, ...] 110 | # index 111 | 112 | @property 113 | @abstractmethod 114 | def name(self) -> str: 115 | # opcode/string identifier 116 | 117 | class Qubit(LogicalElement): 118 | 119 | def __init__(self, index: int): 120 | .... 121 | 122 | @property 123 | def index(self) -> int 124 | return self._index 125 | 126 | @property 127 | def name(self) -> str: 128 | return f"Q{index}" 129 | 130 | class Coupler(LogicalElement): 131 | 132 | def __init__(self, index: Tuple[int, int]): 133 | self._index = index 134 | 135 | @property 136 | def index(self) -> Tuple[int, int] 137 | return self._index 138 | 139 | @property 140 | def name(self) -> str: 141 | qubits = ",".join(self._index) 142 | return f"Coupler({qubits})" 143 | 144 | class Frame(ABC): 145 | 146 | @property 147 | def name(self) -> str: 148 | # opcode/string identifier 149 | 150 | class GenericFrame(Frame): 151 | def __init__(self, name, frequency, phase): 152 | self._name = name 153 | self._frequency = frequency 154 | self._phase = phase 155 | 156 | @property 157 | def name(self) -> str: 158 | return self._name 159 | 160 | @property 161 | def frequency(self) -> float: # The initial frequency of the frame 162 | 163 | @property 164 | def phase(self) -> float: # The initial phase of the frame 165 | 166 | 167 | class QubitFrame(Frame): 168 | def __init__(self, index): 169 | self._index = index 170 | 171 | @property 172 | def index(self) -> int 173 | # qubit index 174 | 175 | @property 176 | def name(self) -> str: 177 | return f"QFrame{self.index}" 178 | 179 | class MeasurementFrame(Frame): 180 | def __init__(self, index): 181 | self._index = index 182 | 183 | @property 184 | def index(self) -> int 185 | # qubit index 186 | 187 | @property 188 | def name(self) -> str: 189 | return f"MFrame{self.index}" 190 | 191 | class MixedFrame(): 192 | def __init__(self, logical_element: LogicalElement, frame: Frame): 193 | self._logical_element = logical_element 194 | self._frame = frame 195 | 196 | @property 197 | def logical_element(self) -> LogicalElement 198 | return self._logical_element 199 | 200 | @property 201 | def frame(self) -> Frame 202 | return self._frame 203 | ``` 204 | 205 | ### Pulse IR 206 | The Pulse IR will provide the framework for the compiler to work on and perform the necessary compilation steps. The main components of the IR will be: 207 | 208 | - IR Block - A block of instructions (or nested blocks) with an alignment context. This structure is similar to the structure of `ScheduleBlock` and is needed to support one of the main tasks of the compiler - scheduling. 209 | - IR Instruction - A pulse program instruction. Typically, it will be initialized without concrete timing, and will be scheduled during the compiler operation. 210 | 211 | Two instructions types are used: 212 | - `GenericInstruction` - for play, delay, set\shift frequency\phase. Assignment of `LogicalElement` will be optional for set\shift frequency\phase and will determine whether or not the instruction will be 213 | broadcaseted to all mixed frames associated with the frame or not. 214 | - `AcquireInstruction` - for acquire instructions (due to the different elements involved). 215 | 216 | ```python 217 | class PulseIR: 218 | def __init__(self): 219 | self.instructions # List of instructions or nested PulseIR objects 220 | self.alignment 221 | 222 | class GenericInstruction: 223 | def __init__( 224 | self, 225 | instruction_type: str, 226 | duration: int, 227 | logical_element: Optional[LogicalElement] = None, 228 | frame: Optional[Frame] = None, 229 | **operands, 230 | ): 231 | self.t0 = None 232 | self.instruction = instruction_type # opcode 233 | self.duration = duration 234 | self.logical_element = logical_element 235 | self.frame = frame 236 | self.operands = operands 237 | ``` 238 | 239 | ### Compiler 240 | The compiler will be built with a shared design of Qiskit's pass manager (based on PR #10474), and will thus be easily extendable to other tasks. The pass based approach allows for simple modification of the lowering process for vendors or Qiskit team. 241 | A typical compiler call will look like: 242 | ```python 243 | payload = compile(my_pulse_prog, backend, target="pulse_qobj") 244 | ``` 245 | where the backend is provided to accomodate the compiled program to the backend constraints and mappings. An optional argument will be a mapping between virtual and physical qubits, as under the new model all indices will be assumed virtual. If no mapping is provided, the trivial one will be used. The mapping will be done before all other operations, during the initialization of the IR. 246 | 247 | The first step of every compiler run will be to initialize the IR of the pulse program. The IR will be initialized with no concrete timing, and the scheduling will be carried out next. 248 | 249 | Next we highlight some of the tasks handled by the compiler. 250 | 251 | #### Scheduling 252 | - Canonicalization (transform pass) - If legacy `Channel`s were used, they will be mapped to `MixedFrame`s using the backend mapping. This is the only scenario where backend mapping will be needed for this stage. 253 | - Collect frames and mixed frames (analysis pass) - Shift\set frequency\phase instructions on a `Frame` will need to be broadcasted to every `MixedFrame` associated with that `Frame`. Therefore, we need collect every `MixedFrame`, `Frame` and the relations between them. 254 | - Schedule each block - 255 | - Starting from the lowest blocks, each block will be scheduled on its own. 256 | - Set\shift frequency\phase instructions will be broadcasted when necessary, and the additional mixed frames will be added to the block. 257 | - According to the alignment, the instructions will be scheduled within the block. 258 | - Nested blocks will be shifted according to the alignment, but their internal timing will not be altered by parent block alignment. 259 | - Apply backend scheduling constraints. 260 | - Validate timing and constraints. 261 | 262 | #### Mapping to backend aware "channels" 263 | For a target format consumed by a backend, the `Frame`s and `MixedFrame`s will have to be converted to backend aware "channels" (for a lack of a better generic term). 264 | It remains to be seen if this conversion will be done on the frontend or the backend, but a scheme for frontend mapping could look like this. 265 | 266 | - Consume the backend accepted channels (For example, "D0" is the driving mixed frame of qubit 0 while "CR12" is the cross resonance mixed frame of qubit 1 in the frame of qubit 2.). 267 | - First, map `MixedFrame`s which natively map to the backend. For example, a `MixedFrame` associated with `Qubit(1)` and `QubitFrame(1)` is natively mapped to the backend's "D1" "channel" in the example above. 268 | Similarly MixedFrame associate with `Qubit(1)` and `QubitFrame(2)` is natively mapped to the backend's "CR12" "channel". 269 | - Next, map remaining `MixedFrames` into unused "channels". 270 | - Lastly, provide the backend with `MixedFrame`s which couldn't have been mapped by the frontend, in hope that the backend could support them. (This will obviously require dedicated backend support). 271 | 272 | #### Conversion to output format 273 | There is still ongoing discussion about desired output formats, but every choice of output format could be supported at the cost of creating a conversion mechanism from IR to that format. 274 | One can imagine various tasks associated with this step: 275 | - Conversion of `SymbolicPulse` to `Waveform` for non-backend-supported pulses. 276 | - Creation of pulse dictionary to reduce payload memory foot print. 277 | 278 | #### Optimizations 279 | While pulse level programs are low level, one might consider optimization passes, like dynamical decoupling addition. The pass based compiler will allow such optimization passes to be created and applied. 280 | 281 | ## Alternative Approaches 282 | This proposal combines two seemingly separate issues - the channel model rework and the introduction of Pulse IR and Compiler. It would be possible to do one without the other, but it seems like this is 283 | a good opportunity to do both. 284 | 285 | ## Questions 286 | - Naming - Names were not finalized. While not in the same namespace, some names here clash with other Qiskit modules (most notably `Qubit`), and it might be better to modify the names. 287 | - IR instructions - The existing `Instruction` class provides similar functionality. Should we use it instead of introducing new IR Instruction classes? 288 | 289 | ## Future Extensions 290 | - Frontend & backend coordination to support custom frames and mixed frames. This has the potential to better utilize HW control options (as discussed above). 291 | - Introuction of new optimizations at the pulse level programing. 292 | -------------------------------------------------------------------------------- /0010-simple-classical-representations.md: -------------------------------------------------------------------------------- 1 | # Preliminary representation of rvalue classical expression in Qiskit 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 10 | 6 | | **Authors** | Jake Lishman (jake.lishman@ibm.com) | 7 | | **Deprecates** | None | 8 | | **Submitted** | 2023-03-15 | 9 | | **Updated** | 2023-03-22 | 10 | 11 | 12 | ## Summary 13 | 14 | This proposes an experimental representation for operations on classical bits solely within conditions. 15 | This is not required to be the final design for classical handling in Terra, it is meant to be something simple that doesn't entangle existing Terra objects too closely, so can be deprecated in favour of a more complete system in the future. 16 | 17 | 18 | ## Motivation 19 | 20 | - Current hardware is gaining support for runtime operations and subsequent conditions on classical bits 21 | - IBM dynamic-circuits hardware can do bit-level calculations, but there is no way to represent this in Qiskit to pass it on 22 | - In Terra, we need more of a feel for what will actually help us represent more complex classical constructs 23 | 24 | 25 | ## User Benefit 26 | 27 | - Users of IBM dynamic circuits will be able to take advantage of the classical-processing capabilities of those systems from within Qiskit 28 | - This support is not limited to IBM so may extend further, but we are not aware of other dynamic-circuits hardware accessible through Qiskit 29 | - For Terra development: this is a "build one to throw away"-type system, so we can see in actual usage what works and doesn't for us before we commit to further classical processing. 30 | 31 | 32 | ## Design Proposal 33 | 34 | The intent of this RFC is to define an exploratory representation for a simple subset of classical bit-level operations, which expand the current state of Terra's `IfElseOp.condition`. 35 | This representation is not required to be the base for future expansion; it will be permissible to introduce a completely different classical-value type system if that is more appropriate, and deprecate this one. 36 | To that end, this proposal will not include adding any additional public methods to any existing Terra classes that might conflict with an alternative implementation. 37 | In particular, this proposal will not consider adding ease-of-use arithmetic methods to `Clbit` or `ClassicalRegister`, nor will it add expressions that can be used as the parameters to gates. 38 | 39 | Notes: 40 | 41 | - We want to keep a level of interoperability with the OpenQASM 3 description of hybrid quantum–classical programs, to have better cross-ecosystem compatibility. 42 | When in doubt, we probably want to run towards the design choices made there. 43 | - There is no _requirement_ to throw this representation away again. 44 | If it works, we can build on it and keep it. 45 | 46 | ### Representation 47 | 48 | `IfElseOp.condition` and `WhileLoopOp.condition` will expand their allowed values to be an "expression" that evaluates to Boolean. 49 | The allowed expressions will be the following: 50 | 51 | - Object: 52 | - literal `bool` (`True` or `False`); 53 | - literal `uint[_]` (non-negative Python `int`); 54 | - runtime `bool` (`Clbit`); 55 | - runtime `uint[n]` (`ClassicalRegister(size=n)`). 56 | - Unary: 57 | - `uint[n] -> uint[n]`: bitwise negation 58 | - `bool -> bool`: Boolean negation 59 | - Binary: 60 | - `uint[n] * uint[n] -> uint[n]` and `bool * bool -> bool`: `&`, `|`, `^`; 61 | - `bool * bool -> bool`: `&&`, `||`; 62 | - `uint[n] * uint[n] -> bool`: `==`, `!=`, `<`, `<=`, `>`, `>=`. 63 | 64 | For typing in this initial draft, we will make an exact bijection: 65 | 66 | - `ClassicalRegister(size=n)` <=> `uint[n]` 67 | - `Clbit` <=> `bool` 68 | 69 | Python Booleans (`True` and `False`) will be used as the `bool` literal values, as they currently are in `Instruction.condition`. 70 | Non-negative Python ints will be used as the `uint` literal values. 71 | These do not have an inherent width. 72 | The width of a literal `uint[_]` will be inferred and fixed to make a containing binary expression validly typed, and mixed-width operations will be forbidden. 73 | A binary expression in this representation _must_ contain at least one type of fixed width; it will be an error to attempt to use the runtime logic on two literals (this simplifies the implementation, and we won't do constant folding). 74 | 75 | This is not intended to be a complete set of classical expressions, for simplicity in this initial implementation. 76 | Notably, this MVP will _not_ include: 77 | 78 | 1. arithmetic on `uint[n]` (`+`, `*`, etc); 79 | 2. indexing the bits resulting from one of these rvalue expresions; 80 | 3. slicing a `uint[n]` to retrieve a subset of its bits; 81 | 4. any method of assigning one of these expressions for reuse elsewhere in the circuit. 82 | 83 | Points 1 through 3 are rejected in this initial proposal for the sake of keeping the number of expression-tree nodes and type-system entries small. 84 | Point 4 is rejected because it would require the definition of additional `Operation` objects and potentially modifications to the `QuantumCircuit` class that we are not yet prepared to make. 85 | All of these points are eligible to be included in future work, just not the MVP. 86 | 87 | 88 | ### Construction 89 | 90 | #### Stage 1 91 | 92 | This is an experimental representation, so it is a non-goal to produce the best possible UX for constructing these objects. 93 | In the initial representation phase, users will be required to build the expression-tree representations themselves. 94 | This will look _something_ like (names up for discussion): 95 | 96 | ```python 97 | from qiskit.circuit import Clbit, ClassicalRegister 98 | from qiskit.circuit.classical import expr 99 | 100 | loose = [Clbit() for _ in [None]*3] 101 | cr1 = ClassicalRegister(2) 102 | cr2 = ClassicalRegister(2) 103 | 104 | # Equivalent to the current condition `(cr, 2)`: 105 | equal_reg = expr.Equal(expr.Value(cr1), expr.Value(2)) 106 | 107 | # Equivalent to the current condition `(loose[0], False)` 108 | equal_bit = expr.Equal(expr.Value(loose[0]), expr.Value(False)) 109 | 110 | # The above example, but using a Bool-valued unary expression: 111 | not_bit = expr.Not(expr.Value(loose[0])) 112 | 113 | # The comparison 0 < cr1 <= cr2 114 | bounded_reg = expr.And( 115 | expr.Less(expr.Value(0), expr.Value(cr1), 116 | expr.LessEqual(expr.Value(cr1), expr.Value(cr2), 117 | ) 118 | ``` 119 | 120 | These expressions will then be given directly to `IfElseOp` or `WhileLoopOp` in their `condition` fields. 121 | These expressions will not be valid in the general `Instruction.condition` field; we do not want to expand any support for something we are already moving to remove. 122 | 123 | For example, a complete condition construction might look like (eliding `expr.Value` calls that could be inferred): 124 | ```python 125 | from qiskit.circuit import QuantumCircuit, ClassicalRegister, QuantumRegister 126 | from qiskit.circuit.classical import expr 127 | 128 | cregs = [ClassicalRegister(3), ClassicalRegister(3)] 129 | qc = QuantumCircuit(QuantumRegister(3), *cregs) 130 | 131 | qc.h(0) 132 | qc.cx(0, 1) 133 | qc.cx(1, 2) 134 | qc.measure([0, 1, 2], cregs[0]) 135 | qc.measure([0, 1, 2], cregs[1]) 136 | with qc.if_test(expr.And(expr.Less(0, cregs[0]), expr.LessEqual(cregs[0], cregs[1]))): 137 | # This is the same as the `bounded_reg` comparison above. 138 | pass 139 | ``` 140 | 141 | 142 | #### Stage 2 143 | 144 | Looking beyond the initial phase, it will be convenient to define a less verbose way for users to create these expressions. 145 | Since this document is intended to define a representation that can be removed and deprecated from Terra easily if it needs to evolve, we will _not_ consider overloading the Python magic-methods `__and__` etc on `Clbit` and `ClassicalRegister` in general Terra usage. 146 | However, we can do so in a limited scope, which will temporarily change the semantics. 147 | This will look like (continued from above code block, and the same examples in the same order): 148 | 149 | ```python 150 | with expr.build(): 151 | equal_reg = cr1 == 2 152 | equal_bit = loose[0] == False 153 | not_bit = ~loose[0] 154 | bounded_reg = (0 < cr1) & (cr1 <= cr2) 155 | ``` 156 | 157 | It is not possible to overload the behaviour of the Python Boolean operators (`not`, `and` and `or`) for classes, which is why the bitwise operations `~` and `&` are used instead (with the corresponding precedence frustrations). 158 | Within the `expr.build()` context, the magic methods of `ClassicalRegister` and `Clbit` will be temporarily overridden to be an eager builder interface for the syntax tree given above. 159 | This means that `expr.build()` context can just contain the entire circuit construction without any changes to `QuantumCircuit`; nothing magic happens on exit of the builder context except for tidying up the monkey-patched methods. 160 | For example, it will be valid to do 161 | 162 | ```python 163 | qc = QuantumCircuit([Qubit()], loose) 164 | with expr.build(): 165 | with qc.if_test(~loose[0]): 166 | qc.h(0) 167 | ``` 168 | 169 | The reason to require entering the builder context to make the magic methods available is for potential future ease of change/removal/deprecation. 170 | The mutation of global state required to do this makes the builder interface non-thread-safe, but this is not judged to be a problem; it is uncommon to attempt to multithread during manual circuit construction, and the advantages of easy removal/representation change completely outweigh the potential concern. 171 | 172 | 173 | ## Detailed Design 174 | 175 | The new functionality will live in `qiskit.circuit.classical`. 176 | The expression-builder objects will all be exposed from `qiskit.circuit.classical.expr`, to allow people to bring the desired values into scope either with a namespace prefix `expr` or by a star-import of limited scope. 177 | 178 | > From this point on, I will omit the prefix `qiskit.circuit.classical.`. 179 | 180 | The class `expr.Expr` will be an abstract base class with one read-only field: 181 | ```python 182 | # file: qiskit/circuit/classical/expr.py 183 | 184 | class Expr(ABC): 185 | type: qiskit.circuit.classical.Type 186 | ``` 187 | 188 | The `type` field is a resolved type of the contained expression. 189 | In this initial release, the only time that `type` will not be a fully qualified type will be when representing a `expr.Value` of a `uint` literal. 190 | Type errors will raise immediately on attempted construction. 191 | In the future, we may consider relaxing this restriction and having a type-evaluation pass that runs on the complete `QuantumCircuit` AST representation, but that is for later work. 192 | 193 | The expressions in the above examples will be final (uninheritable) subclasses of `Expr`: 194 | ```python 195 | class Value(Expr): 196 | value: Any 197 | 198 | class Less(Expr): 199 | left: Expr 200 | right: Expr 201 | 202 | ... 203 | ``` 204 | 205 | We will supply a base class `ExprVisitor` that can be subclassed to easily handle the double-dynamic dispatch needed to visit the children of an `Expr`. 206 | For an example implementation of a tree visitor, see the Python built-in `ast.NodeVisitor`. 207 | 208 | 209 | Similarly, the type system will be represented by values of the type `types.Type`: 210 | ```python 211 | # file: qiskit/circuit/classical/types.py 212 | 213 | class Type(ABC): 214 | pass 215 | 216 | @typing.final 217 | class Bool(Type): 218 | pass 219 | 220 | UNKNOWN = object() 221 | 222 | @typing.final 223 | class Uint(Type): 224 | size: int | Literal[UNKNOWN] 225 | ``` 226 | 227 | In this simple type system, there is likely no need for a `TypeVisitor` class yet, but if the type system expands to include compound types (functions, for example), we can supply one. 228 | 229 | 230 | ### Potential deprecation 231 | 232 | If this is needed to be replaced, the module `qiskit.circuit.classical` can just be deprecated, and the replacement can be given a new name. 233 | Since none of this proposal involves new user-facing methods on any existing classes, there will be no trouble with replacing those with new behaviour. 234 | For example, since the magic method `Clbit.__add__` would only be defined when the `expr.build()` context is active, we can simply deprecate `expr.build` to remove the usage of the magic methods. 235 | A new implementation would _immediately_ be able to define new magic methods if desired, instead of needing to go through a full deprecate-and-remove cycle, because `Clbit.__add__` would only be monkey-patched on using the deprecated `expr.build`. 236 | 237 | 238 | ## Implementation plan 239 | 240 | PR 1: 241 | - write representation of `Expr` and `Type` 242 | - test that these objects can be constructed and handle type checking correctly 243 | 244 | PR 2 (depends on 1): 245 | - add support to `Expr` of evaluated type `Bool` to `IfElseOp.condition` and `WhileLoopOp.condition` 246 | 247 | PR 3 (depends on 2): 248 | - add support for exporting these `Expr` conditions to OpenQASM 3 249 | 250 | PR 4 (depends on 2): 251 | - add support for these `Expr` conditions into the `DAGCircuit` <-> `QuantumCircuit` conversions (i.e. enable the transpiler to work with them) 252 | 253 | PR 5 (depends on 1): 254 | - add the `expr.build()` context manager 255 | 256 | Pull requests 1 through 4 are required for minimal support in a Terra version. 257 | PRs 2 and 3 are semi-parallelisable; the export support can be made prospectively assuming that the `condition` field might be an `Expr`, but the final tests will need PR 2 merged first. 258 | Pull request 5 can be permitted to follow in a subsequent Terra release, if necessary, despite being parallelisable with all PRs following 1. 259 | 260 | 261 | ## Alternative Approaches 262 | 263 | ### Reuse of `ParameterExpression` 264 | 265 | We have talked about using the existing `ParameterExpression` before, for this. 266 | This poses several problems, because overloading it from its current use as a _compile-time_ stand-in for unknown values to involve arbitrary _run-time_ expressions opens the door for many errors where those two domains don't fully align. 267 | `ParameterExpression` is also build on `sympy`/`symengine`, which don't have any sort of rigorous type system for us to use. 268 | We would have to hack one on top of them, which would make a lot more of the manipulation interfaces around these types far more complex to use. 269 | These also perform (by default) aggressive simplifications based on arithmetic operations on the reals; this does not translate cleanly to storing operations on mixed types, or having casts from one type to another, and so on. 270 | 271 | ### Reuse of `classicalfunction.BooleanExpression` 272 | 273 | This type is somewhat more similar to the immediate goals of this PR, but it: 274 | 275 | - has hard requirements on being a Python AST walker, which hurts ergonomics for construction of simple conditions (see next comment, and the "call" syntax to apply to given objects would need to implemented still); 276 | - relies on `tweedledum`, which is unmaintained (which is why `qiskit.circuit.classicalfunction` is pending complete removal from Terra); 277 | - cannot easily allow dynamic construction of conditions, since it relies on being a static analyser. 278 | 279 | It is also currently only defined for bit types, not the integer types we need for `ClassicalRegister` (despite the existence of `Int2`). 280 | This possibly could be extended, but the other points above are enough reason to dismiss this. 281 | 282 | 283 | ### AST-visitor builder interface 284 | 285 | The stage-2 builder interface for the expression syntax given above had a problem that Python does not allow classes to override the behaviour of binary Boolean operations. 286 | This could be avoided instead if we had the builder interface be something like 287 | ```python 288 | @expr.build 289 | def _equal_reg(cr: ClassicalRegister): 290 | return cr == 2 291 | 292 | @expr.build 293 | def _bounded_reg(cr1: ClassicalRegister, cr2: ClassicalRegister): 294 | return 0 < cr1 <= cr2 295 | 296 | equal_reg = _equal_reg(cr) 297 | bounded_reg = _bounded_reg(cr1, cr2) 298 | ``` 299 | 300 | This is possible with function decorators because the decorator can access the Python AST of the contained code and rewrite it. 301 | `with` statements still execute, we can just control the context within that happens. 302 | 303 | This function-decorator method is not chosen because: 304 | 305 | - in practice, since it only applies to expressions and is not part of a larger circuit builder interface, it ends up being much more verbose due to the need to first define, then call; 306 | - it is harder to write and maintain a Python AST visitor, which makes it less ideal for a preliminary implementation 307 | - it has to do type checking twice; once during the AST visit, and once during the subsequent object call. 308 | 309 | In the context of a larger circuit-builder interface, where the entirety of the `QuantumCircuit` is built up using such functions, many of the negatives of this form are reduced. 310 | 311 | 312 | ## Future Extensions 313 | 314 | - An entire classical system including casting between different types, and the ability to assign runtime expressions to variables that are managed by `QuantumCircuit`. 315 | - An extension of the type system to include values that can be used as the operands of gate objects. 316 | -------------------------------------------------------------------------------- /0020-release_cycle.md: -------------------------------------------------------------------------------- 1 | # Qiskit release cycle and versioning 2 | 3 | | **Status** | **Accepted** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0020 | 6 | | **Authors** | [Luciano Bello](https://github.com/1ucian0/) and the Qiskit development team | 7 | | **Submitted** | 2023-11-21 | 8 | 9 | ## Summary 10 | 11 | Balancing stable backward compatibility with the rapid pace of technology is a crucial consideration for Qiskit. This RFC is a public discussion that aims to find a harmonious solution that offers users a clear and transparent support contract while minimizing the burden on developers and users. Ideally, we are in the search for an approach that also maximizes flexibility to accommodate new hardware and services, which often necessitate the development of new features. 12 | 13 | 14 | ## Motivation 15 | 16 | Qiskit is known for its dynamic nature and frequent deprecation of features. However, the [deprecation policy](https://qiskit.org/documentation/deprecation_policy.html) places a strong emphasis on stability and guarantees a relatively lengthy transition period (usually longer than six months from the first notification point on) when removing a feature. For the past several years Qiskit has also had planned releases on a regular schedule for mitigating the impact of coming changes, as well as pre-releases to enable testing prior to a final release. 17 | 18 | However, there is a demand for a more transparent release cycle with longer periods of backwards compatibility support. In order to get ready for a "beyond Qiskit 0.x", a discussion on how that cycle would like is key to understand the trade-offs among: 19 | 20 | * developer effort: Supporting several stable versions requires significant development resources. At the same time, rolling releases tend to create technical debt and fewer chances to enable re-architecting features or interfaces for better maintainability or changing needs. 21 | * user support: users tend to demand longer support periods to avoid regular updates in their code and software. 22 | * new feature support for coming technology: the quantum computing field and hardware is constantly changing and scaling up. This can require changes in Qiskit, which are not always compatible with previous approaches. 23 | 24 | The outcome of the RFC is an agreement for release cycle and a versioning schema that would provide users with the tools for planning and stability while reduce the impact in the development workflow. 25 | 26 | ## User Benefit 27 | 28 | The RFC aims to benefit users and Qiskit ecosystem developers, because they will have guaranties that their software will run for a defined period of time and they could plan the transition period. 29 | 30 | ## Design Proposal 31 | 32 | The current `0.*`-release cycle increases the minor version in approximate periods of 3 months on a scheduled basis and, with the exception of the pre-release period (from one to two weeks) does not support more than one stable version at the time, i.e. the support of `0.X` finishes with the release of `0.X+1`. 33 | 34 | ```mermaid 35 | gantt 36 | dateFormat YYYY-MM-DD 37 | tickInterval 3month 38 | todayMarker off 39 | axisFormat %b-%Y 40 | 0.17 :r017, 2021-04-01, 2021-07-12 41 | 0.18 :r018, after r017, 2021-12-06 42 | 0.19 :r019, after r018, 2022-03-31 43 | 0.20 :r020, after r019, 2022-06-30 44 | 0.21rc :r021rc, 2022-06-23, 2022-06-30 45 | 0.21 :r021, after r020, 2022-10-13 46 | 0.22rc :r022rc, 2022-10-07, 2022-10-13 47 | 0.22 :r022, after r021, 2023-01-26 48 | 0.23rc :r023rc, 2023-01-16, 2023-01-26 49 | 0.23 :r024, after r022, 2023-05-04 50 | 0.24rc :r024rc, 2023-04-20, 2023-05-04 51 | 0.24 :milestone, 2023-05-04 52 | ``` 53 | 54 | The `0.*`-release branch scheme is like this: 55 | 56 | ```mermaid 57 | gitGraph 58 | commit id:"feature/0" 59 | commit id: "ready_for_release" type:HIGHLIGHT 60 | branch stable/0.X 61 | commit id: "tag_0.X.0rc1" tag: "v0.X.0rc1" 62 | checkout main 63 | commit id:"bugfix/1" 64 | checkout stable/0.X 65 | cherry-pick id:"bugfix/1" 66 | commit id: "tag_0.X.0" tag: "v0.X.0" 67 | checkout main 68 | commit id:"feature/1" 69 | commit id:"feature/2" 70 | commit id:"bugfix/2" 71 | checkout stable/0.X 72 | cherry-pick id:"bugfix/2" 73 | checkout main 74 | commit id:"feature/3" 75 | commit id:"bugfix/3" 76 | checkout stable/0.X 77 | cherry-pick id:"bugfix/3" 78 | checkout main 79 | commit id:"feature/4" 80 | checkout stable/0.X 81 | commit id: "tag_0.X.1" tag: "v0.X.1" 82 | ``` 83 | 84 | The main branch is a single development branch from which some bugfixes are backported to the stable branch, from which releases are done. 85 | 86 | 87 | The new release cycle will include: 88 | 89 | * [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) 90 | * Critical bugfix support for at least one year 91 | * 6-month transition period for updating to a new major while having support. 92 | * Non-breaking new features releases in a 3-month cycle (as currently) 93 | 94 | 95 | ```mermaid 96 | gantt 97 | dateFormat YYYY-MM-DD 98 | tickInterval 3month 99 | todayMarker off 100 | axisFormat %b 101 | section X.* 102 | X.0 :rX0Y0, 2024-01-31, 91d 103 | X.1 :rX0Y1, after rX0Y0, 91d 104 | X.2 :rX0Y2, after rX0Y1, 91d 105 | X.3 :rX0Y3, after rX0Y2, 91d 106 | X.4, :done, rX0Y4, after rX0Y3, 183d 107 | section X+1.* 108 | X+1.0 :rX1Y0, 2025-01-31, 91d 109 | X+1.1 :rX1Y1, after rX1Y0, 91d 110 | X+1.2 :rX1Y2, after rX1Y1, 91d 111 | X+1.3 :rX1Y3, after rX1Y2, 91d 112 | X+1.4, :done, rX1Y4, after rX1Y3, 183d 113 | section X+2.* 114 | X+2.0 :rX2Y0, 2026-01-31, 91d 115 | X+2.1 :rX2Y1, after rX2Y0, 91d 116 | X+2.2 :rX2Y2, after rX2Y1, 91d 117 | X+2.3 :rX2Y3s, after rX2Y2, 91d 118 | X+2.4, :done, rX2Y4, after rX2Y3s, 183d 119 | ``` 120 | 121 | ```mermaid 122 | %%{init: {'theme': 'default', 'gitGraph': {'mainBranchOrder': 1}} }%% 123 | gitGraph 124 | commit id:"feature/0" 125 | commit id: "ready_for_X" type:HIGHLIGHT 126 | branch "next/X+1" order: 0 127 | 128 | commit id:"breaking/0" 129 | checkout main 130 | 131 | branch stable/X.0 order: 2 132 | commit id: "tag_X.0.0" tag: "vX.0.0" 133 | checkout main 134 | commit id:"bugfix/1" 135 | checkout stable/X.0 136 | cherry-pick id:"bugfix/1" 137 | 138 | checkout "next/X+1" 139 | commit id:"breaking/2" 140 | commit id:"breaking/3" 141 | 142 | checkout main 143 | commit id:"feature/1" 144 | checkout stable/X.0 145 | commit id: "tag_X.0.1" tag: "vX.0.1" 146 | 147 | checkout main 148 | commit id: "ready_for_1" type:HIGHLIGHT 149 | 150 | checkout "next/X+1" 151 | merge "main" 152 | checkout main 153 | 154 | branch "stable/X.1" order: 2 155 | commit id: "tag_X.1" tag: "vX.1" 156 | checkout main 157 | commit id: "ready_for_2" type:HIGHLIGHT 158 | 159 | checkout "next/X+1" 160 | merge "main" 161 | checkout main 162 | 163 | branch "stable/X.2" order: 2 164 | commit id: "tag_X.2" tag: "vX.2" 165 | checkout main 166 | commit id: "ready_for_3" type:HIGHLIGHT 167 | 168 | checkout "next/X+1" 169 | merge "main" 170 | checkout main 171 | 172 | branch "stable/X.3" order: 2 173 | commit id: "tag_X.3.0" tag: "vX.3.0" 174 | checkout main 175 | commit id:"feature/2" 176 | commit id:"bugfix/2" 177 | checkout "stable/X.3" 178 | cherry-pick id:"bugfix/2" 179 | checkout main 180 | commit id:"breaking/1" 181 | 182 | checkout stable/X.3 183 | commit id: "tag_X.3.1" tag: "vX.3.1" 184 | 185 | checkout "next/X+1" 186 | commit id:"breaking/4" 187 | commit id:"breaking/5" 188 | 189 | checkout main 190 | merge "next/X+1" 191 | 192 | commit id: "ready_for_X+1" type:HIGHLIGHT 193 | branch "stable/X+1.0" order: 2 194 | commit id: "tag_X+1.0.0" tag: "vX+1.0.0" 195 | 196 | checkout main 197 | commit id:"bugfix/3" 198 | checkout "stable/X.3" 199 | cherry-pick id:"bugfix/3" 200 | checkout "stable/X+1.0" 201 | cherry-pick id:"bugfix/3" 202 | checkout "stable/X.3" 203 | commit id: "tag_X.3.2" tag: "vX.3.2" 204 | checkout "stable/X+1.0" 205 | commit id: "tag_X+1.0.1" tag: "vX+1.0.1" 206 | ``` 207 | 208 | Similarly to the current branching model, non-breaking features (`feature/*`) and bug fixes (`bugfix/*`) can be merged into `main` at any point. Non-breaking features (`feature/*`) are released in minor releases, when branched out of `main` for `tag_X.*`. Bug fixes are cherry-picked from main into the respective `stable/X.*` branch. 209 | 210 | The main difference with the `0.*`-release schema is that breaking changes cannot be introduced at any point, but only between major releases (for example, from `X.Y.Z` to `X+1.0.0`. 211 | 212 | ## Detailed Design 213 | 214 | All the stability guarantees on this RFC are on *public APIs*. Users and developers are encourage to only use public API and do not hook on internal interfaces. 215 | 216 | ### Definition of *public API* 217 | 218 | The Qiskit public API is considered any documented module, class, function, or method that is not marked as private (with a `_` prefix). 219 | 220 | **Exceptions**: 221 | 222 | - Experimental interfaces: If module, class, function, or method is documented as experimental that is not marked as private (with a `_` prefix). Experimental interfaces have to raise a user visible [Warning](https://docs.python.org/3/library/warnings.html) (exact Warning type to be define). 223 | - Abstract interface definitions: These APIs are created to define an interface to be implemented by a subclass. Methods and properties defined as private in these Abstract classes are part of the public API. 224 | - Low-level methods for advanced usage: There are private methods that have stable interfaces but are not considered safe to use 225 | as the burden is on the user to uphold the class/safety invariants themselves 226 | (the canonical example of this is the `QuantumCircuit._append` method). 227 | 228 | 229 | ### Versioning Model 230 | 231 | The proposed versioning model for Qiskit aligns with [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html), providing a clear and standardized approach to version numbering. This model aims to communicate the nature of changes on the public API in each release, helping users and developers understand the impact of an update at a glance. 232 | 233 | Semantic Versioning consists of three version components: *Major*, *Minor*, and *Patch* versions, represented as `X.Y.Z`. Each component has a specific meaning in the context of Qiskit: 234 | 235 | **Major Version (X):** Increments for backward-incompatible changes, indicating potential breaking changes that may require modifications in user code using the public API. 236 | 237 | - A major version `X` release has a minimum of 18 month period for support with critical bug fixes. 238 | - New major release `X` can introduce breaking changes with respect to previous major release `X-1`. 239 | - During the `X` release series, there might include non-breaking new features during that period. 240 | - After the release of a major release `X`, `X+1` can be released after, at least, 12 months. 241 | - After the release of `X+1`, `X` wont have new features and only critical bugfixes are provided for, at least, 6 months. 242 | - The features deprecated during the period of support with `X` will be removed in `X+1` 243 | 244 | **Minor Version (Y):** Increases for backward-compatible features or enhancements a new `X.Y` release: 245 | 246 | - Minor releases are planned for every 3 months, on a best effort basis. 247 | - Users can expect new functionalities without breaking existing code (with the exception of Experimental APIs. 248 | - Significant refactorings of internals without changes in the public API are possible in minor releases. 249 | - Bugfixing without changes in the public API are possible in minor releases. 250 | - Deprecation of previous functionality might be introduced (with a `DeprecationWarning` and documentation), pointing to the new prefer way or alternative, if there is one. 251 | - The support of `X.Y` finishes with the release of `X.Y+1` in most of the cases (exception might apply) 252 | - The minor release before the next major (aka, *final minor release*) has support for 6 months after the next major. That is, if `X.Y` is the last feature release before `X+1.0`, then `X.Y+1` is the final minor release. 253 | - The final minor release `X.Y+1` should not have new features but might include `DeprecationWarning`s that will be removed in the next major, `X+1.0`. 254 | 255 | **Patch Version (Z):** Bumps for backward-compatible bug fixes. 256 | 257 | - New `Z` releases have no scheduled and they are done on a *need-base* considering: 258 | - The *backportability* of the patch 259 | - The severity of the bug to fix 260 | - The criticality of the affected use-case 261 | - Cannot be introduced in patch releases: 262 | - new deprecation warnings 263 | - new features of any kind 264 | - raise minimum requirements for using or building Qiskit (including adding new dependencies) 265 | - any kind of changes in any kind of public API (including Experimental APIs), including its removal or expansion. 266 | - It may include: 267 | - expansive support for new versions of Python, Rust, or run/build environment 268 | - support for new versions of other existing dependencies 269 | - The support of `X.Y.Z` finishes with the release of `X.Y.Z+1` (or `X.Y+1.0`) in most of the cases (exception might apply) 270 | - After the release of `X+1`, bugfixing is provided via `X.Y.Z+N` in undetermined regularity for 6 months. 271 | 272 | ### Git branching model 273 | 274 | Before the release of a major `X.0`, the last minor `X-1.Y` should be tagged in the `stable/X-1.Y`. Two weeks before the release `X.0` the branch `next/X` should be merged into `main` (probably not necessary the first time). Then `stable/X.0` is branched from `main`, as well as `next/X+1`. In `stable/X.0`, `X.0.0rc1` is tagged and release. Two week later, at stable release time, `X.0.0` is tagged on `stable/X.0` and released. 275 | 276 | Similarly, two week before the release of `Y` minor, a `stable/X.Y` branch from `main` is created, from where `X.Y.0rc1` is tagged. When stable `X.Y.0` will be released (two weeks later), the label is on `stable/X.Y`. 277 | 278 | All changes, including bug fixes, with backward compatibility are PRed with `main` as base. Bugfix PRs that are possible to port to stable should be tagged as `stable-backport-potential` and a bot ports them to `stable/X.Y` (where `Y` is the last minor). 279 | At undefined time, a new patch release `X.Y.Z` is tagged on `stable/X.Y` and released. 280 | 281 | Non-backward compatible changes, including removal of deprecated code, can be PRed at any point against `next/X+1` branch. 282 | 283 | Regularly, `main` should be merge into `next/X+1` to keep it up-to-date. The suggestion is for every minor release, at least. 284 | 285 | ### QPY support 286 | 287 | The QPY serialization format is backwards compatible so that a new Qiskit can release can always load a QPY 288 | file generated with an earlier release of Qiskit. However, the format isn't forward compatible, so it's not possible 289 | to load QPY files generated with newer version of Qiskit using an older release. To support compatibility across major version releases, the `qiskit.qpy.dump()` function has an optional argument `version` that lets a user specify a back version of the QPY format emitted by the `dump()` function. There are two constants exposed by 290 | the `qpy` module, `qiskit.qpy.QPY_VERSION` which documents the default format version emitted by `dump()` and 291 | also the maximum version that `load()` supports, and `qiskit.qpy.QPY_COMPATIBILITY_VERSION` which documents the minimum version that `dump()` can emit (while `load()` can load any version <= `QPY_VERSION`). 292 | 293 | To facilitate user migration across major version releases the `qiskit.qpy.dump()` function will always support at least one overlapping version between the `X.0.0` and the `X-1.Y.0` release (where Y is the last minor version of 294 | that series). This will enable saving QPY format files that can be loaded by both major versions from the newer 295 | release. For example, in Qiskit 1.0.0 the `QPY_VERSION` was `11`, and in Qiskit 0.46.0 the `QPY_VERSION` constant was `10`. For qiskit 1.0.0 the minimum version supported by `dump()`'s `version` argument, and exposed by 296 | `qiskit.qpy.QPY_COMPATIBILITY_VERSION` was 10. This enabled Qiskit 1.0.0 to generate qpy payloads that could 297 | be loaded by Qiskit 0.46.0. 298 | 299 | ### Pre-releases 300 | 301 | The pre-release model from the `0.*`-release cycle will continue in the same way. Two weeks before the release of a minor `X.Y`, a release candidate `X.Yrc0` will be released as a pre-release. The final minor release might be except for that release candidate release, as it does not include new features. 302 | 303 | ### Feature, deprecation, and removal proposal deadline 304 | 305 | Two weeks before the pre-release or a minor release, what ever is before, there will be a feature, deprecation, and removal proposal deadline. That means that any PR with addition, removal, or modification on the public API needs to be ready for review in the Qiskit repository before that date. Exceptions might apply at consideration of the Qiskit core team. 306 | 307 | 308 | ### Suggested upgrade path 309 | 310 | Users should upgrade minors and patch versions as soon as the next stable release happens in every case, except when there is a new major release. 311 | Major releases allow for 6 months to transition from `X` to `X+1`. 312 | Users and downstreamers should depend on `=X.Y, int: 132 | ... 133 | 134 | @property 135 | @abstractmethod 136 | def name(self) -> str: 137 | ... 138 | 139 | def __call__(self, channel: PulseChannel) -> Play: 140 | return Play(self, channel) 141 | ``` 142 | 143 | #### Instruction 144 | ```python 145 | class Instruction(ABC): 146 | def __init__(self, *operands) -> Instruction: 147 | ... 148 | 149 | @property 150 | @abstractmethod 151 | def duration(self) -> int: 152 | ... 153 | 154 | @property 155 | def operands(self) -> Tuple[Any, ...]: 156 | return operands 157 | 158 | @property 159 | @abstractmethod 160 | def channels -> Tuple[Channel, ...]: 161 | ... 162 | ``` 163 | 164 | #### SamplePulse 165 | ```python 166 | class SamplePulse(Pulse): 167 | # otherwise unchanged 168 | ... 169 | ``` 170 | 171 | #### `ParametricPulse` 172 | ```python 173 | class ParametricPulse(Pulse): 174 | # otherwise unchanged 175 | ... 176 | ``` 177 | 178 | #### Play 179 | ```python 180 | class Play(Instruction): 181 | def __init__(self, pulse: Pulse, channel: PulseChannel) -> Play: 182 | super().__init__(pulse, channel) 183 | 184 | @property 185 | def duration(self) -> int: 186 | return pulse.duration 187 | 188 | @property 189 | def channels: 190 | return (channel,) 191 | 192 | @property 193 | def pulse(self) -> Pulse: 194 | return pulse 195 | 196 | @property 197 | def pulse_name(self) -> str: 198 | return pulse.name 199 | ``` 200 | 201 | #### ShiftPhase 202 | ```python 203 | class ShiftPhase(Instruction): 204 | def __init__(self, phase: float, channel: PulseChannel) -> ShiftPhase: 205 | super().__init__(phase, channel) 206 | 207 | @property 208 | def duration(self) -> int: 209 | return 0 210 | 211 | @property 212 | def channels: 213 | return (channel,) 214 | 215 | @property 216 | def phase(self) -> float: 217 | return phase 218 | ``` 219 | 220 | #### SetPhase 221 | ```python 222 | class SetPhase(Instruction): 223 | def __init__(self, phase: float, channel: PulseChannel) -> SetPhase: 224 | super().__init__(phase, channel) 225 | 226 | @property 227 | def duration(self) -> int: 228 | return 0 229 | 230 | @property 231 | def channels: 232 | return (channel,) 233 | 234 | @property 235 | def phase(self) -> float: 236 | return phase 237 | ``` 238 | 239 | #### SetFrequency 240 | ```python 241 | class SetFrequency(Instruction): 242 | def __init__(self, frequency: float, channel: PulseChannel) -> SetFrequency: 243 | super().__init__(frequency, channel) 244 | 245 | @property 246 | def duration(self) -> int: 247 | return 0 248 | 249 | @property 250 | def channels: 251 | return (channel,) 252 | 253 | @property 254 | def frequency(self) -> float: 255 | return frequency 256 | ``` 257 | 258 | #### ShiftFrequency 259 | ```python 260 | class ShiftFrequency(Instruction): 261 | def __init__(self, frequency: float, channel: PulseChannel) -> ShiftFrequency: 262 | super().__init__(frequency, channel) 263 | 264 | @property 265 | def duration(self) -> int: 266 | return 0 267 | 268 | @property 269 | def channels: 270 | return (channel,) 271 | 272 | @property 273 | def frequency(self) -> float: 274 | return frequency 275 | ``` 276 | 277 | #### Acquire 278 | ```python 279 | class Acquire(Instruction): 280 | def __init__(self, duration: int, channel: AcquireChannel, 281 | register: Union[MemorySlot, RegisterSlot], 282 | kernel: Optional[Kernel], discriminator: Optional[Discriminator]) -> Acquire: 283 | super().__init__(duration, channel, register, 284 | kernel, discriminator) 285 | 286 | @property 287 | def duration(self) -> int: 288 | return duration 289 | 290 | @property 291 | def channels(self): 292 | return (channel, register) 293 | 294 | @property 295 | def kernel(self) -> Kernel: 296 | return kernel 297 | 298 | @property 299 | def discriminator(self) -> Discriminator: 300 | return discriminator 301 | ``` 302 | 303 | #### Snapshot 304 | ```python 305 | class Snapshot(Instruction): 306 | def __init__(self, label: str, snapshot_type: str) -> Snapshot: 307 | super().__init__(label, snapshot_type) 308 | 309 | @property 310 | def label(self): 311 | return label 312 | 313 | @property 314 | def snapshot_type(self): 315 | return snapshot_type 316 | 317 | @property 318 | def duration(self): 319 | return 0 320 | 321 | @property 322 | def channels: 323 | return (SnapshotChannel(0),) 324 | ``` 325 | ## Alternative Approaches 326 | At this time the alternative approach is to leave the API as is and continue to have both `Command`s and `Instruction`s. This would allow some useful features such as being able to define reusable fixed `FrameChange`s but this comes at the cost of a cumbersome user interface. 327 | 328 | ## Questions 329 | - Have all possible breaking changes for the current interface been covered? If so do graceful deprecation paths exist? 330 | 331 | ## Future Extensions 332 | - Defining an accompanying textual representation (language) for the instruction set defined within this RFC should be explored. This will enable a convenient interface for textual interface pulse programming and also provide an on-disk storage format. 333 | - Explore the possibility of creating a builder interface with Python within a Python context that generates the underlying schedule data structure. This could make pulse programming much easier and would like a Python DSL for pulse programming rather than building up a data structure as pulse programming is currently done. 334 | -------------------------------------------------------------------------------- /0006-rfc-generalized-unroller-and-equivalence-library.md: -------------------------------------------------------------------------------- 1 | # Generalized Unroller and Equivalence Library 2 | 3 | | **Status** | **Implemented** | 4 | |:------------------|:---------------------------------------------| 5 | | **RFC #** | 0006 | 6 | | **Authors** | Kevin Krsulich (kevin.krsulich@ibm.com), | 7 | | | Luciano Bello (Luciano.Bello@ibm.com), | 8 | | | Ali Javadi (Ali.Javadi@ibm.com), | 9 | | **Submitted** | 2020-05-21 | 10 | | **Updated** | 2023-05-10 | 11 | 12 | 13 | # Summary 14 | 15 | We propose a generalization of the Qiskit transpiler's unroller and gate definition infrastructure to enable circuit translation across a variety of bases. 16 | We define an interface for an equivalence library which will be used to expose a repository of valid circuit translations, initially defined over the standard library and automatically integrating decompositions of user-defined gates. 17 | Implementation of this library within the transpiler pipeline will support natively targeting a broader array of architectures without requiring re-synthesis, and enable basis-dependent logical optimizations. 18 | 19 | 20 | # Motivation 21 | 22 | Cross-architecture compatibility is a key architectural goal of the Qiskit transpiler. 23 | To date, practical opportunities to pursue this goal have been few as available targets have been predominantly superconducting circuit devices and simulators. 24 | As a result, the transpiler has, in several places, developed implicit assumptions on or preferences for superconducting backends. 25 | As the number of deployed devices of varied architecture rapidly increases, ensuring that the Qiskit transpiler is able to achieve state-of-the-art optimizations while targeting diverse backends is a pressing practical goal. 26 | 27 | Immediate objectives are to ensure that the majority of the transpiler pipeline is target-architecture agnostic and that the tooling provided is equally useful across architectures. 28 | Logical optimization passes should be applicable regardless of target architecture, and device-level optimization passes should be applicable for any backend which reports the necessary quantities. 29 | High level optimizations should be applied broadly, and architecture-specific optimization passes employing the strengths of a particular architecture should be easy to develop and utilize. 30 | The limitation that `Instruction` s are allowed only a single decomposition, which must ultimately be reducible to `U3` and `CX` gates, will be lifted. 31 | For devices which report an overcomplete basis, users will be able to control how instructions will be decomposed, or to provide specific decompositions of single instruction. 32 | 33 | At a high level, current transpiler levels 0 and 1 are roughly summarized as follows: 34 | 35 | ┌───────────────┐ 36 | │ Current Terra │░ 37 | │ Transpiler │░ 38 | └───────────────┘░ 39 | ░░░░░░░░░░░░░░░░░ 40 | ┌──────────────┐ ┌────────────────┐ ┌────────────────┐ 41 | │ User Circuit │ │Embedded Circuit│ │ Device Circuit │ 42 | ├──────────────┤ ├────────────────┤ ├────────────────┤ 43 | │custom │ │custom │ │device gates* │ 44 | Input │built-in │ Embedding │built-in │ Unrolling │ │ 45 | ●──────│unitary gates │────────────────────▶│unitary gates │───────────────▶│ │ 46 | │ │ LayoutSelection │ │ UnrollU3CX │ │ 47 | ├──────────────┤ AncillaAllocation ├────────────────┤ Unitary Synth ├────────────────┤ 48 | │virtual qubits│ │ device qubits │ │ device qubits │ 49 | └──────────────┘ └────────────────┘ └────────────────┘ 50 | │ 51 | │ 52 | │ 53 | ┌─────────────────┐ ┌────────────────┐ │ 54 | │Optimized Circuit│ │Runnable Circuit│ │ 55 | ├─────────────────┤ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ├────────────────┤ │ 56 | Device │device gates │ Optimization │device gates │ │ Mapping 57 | Output Re-synthesis │ │ │ Loop │ │ │ │ 58 | ●───────────────────│ │◀─────────────────────│ │◀──────┘ 59 | │ │ │ Optimize1QGates │ │ │ 60 | ├─────────────────┤ CXCancellation ├────────────────┤ 61 | │ device qubits │ │ConsolidateBlocks│ │ device qubits │ 62 | └─────────────────┘ ... └────────────────┘ 63 | └ ─ ─ ─ ─ ─ ─ ─ ─ ┘ 64 | 65 | Levels 2 and 3 are similar, with expanded passes in the optimization loop and the order of embedding and unrolling reversed. 66 | 67 | A transpiler architecture of the following form is envisioned: 68 | 69 | ┌───────────────┐ 70 | │ Envisioned │░ 71 | │ Terra │░ High-Level Logical 72 | └───────────────┘░ Optimization Loop 73 | ░░░░░░░░░░░░░░░░░ 74 | ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 75 | ┌──────────────┐ ┌────────────────┐ ┌────────────────┐ Unroll to │ 76 | │ User Circuit │ │ │ │ │ optimization 77 | ├──────────────┤ ├────────────────┤ ├────────────────┤ basis │ 78 | │custom │ Unroll Custom │built-in │ Synthesize │built-in gates ├─────────────■ 79 | Input │built-in │ Gates │unitary gates │ Unitaries │ │ │ Apply │ 80 | ●──────│unitary gates │──────────────▶│ │───────────▶│ │ │optimization 81 | │ │ UnrollUser │ │ │ ◀─────────────■ │ 82 | ├──────────────┤ ├────────────────┤ ├────────────────┤ LLL Opt. 83 | │virtual qubits│ │ virtual qubits │ │ virtual qubits │ Loop │ 84 | └──────────────┘ └────────────────┘ └────────────────┤ 85 | │ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ Template matching 86 | Embedding└───────────┐ Peephole optimization 87 | ▼ Clifford resynthesis 88 | ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ Block consolidation 89 | │ Device Circuit │ │ Device Circuit │ │ Device Circuit │ FinalToffoliToRelativePhase 90 | ├────────────────┤ ├────────────────┤ ├────────────────┤ ... 91 | │device gates │ Device │device gates │ │device gates* │ 92 | Output │ │ Optimizations │ │ Mapping │ │ 93 | ●──────────────│ │◀─────────────────│ │◀──────────│ │ 94 | │ │ Device Unroller │ │ │ │ 95 | ├────────────────┤ Approx Synthesis├────────────────┤ ├────────────────┤ 96 | │ device qubits │ │ device qubits │ │ device qubits │ 97 | ├───┬──────▲─────┘─ ─ ─ ─ ─ ─ ─ └────────────────┘ └────────────────┘ 98 | │ │ Optimize1QGates │ 99 | Low-Level Logical │ │ │ CXCancellation 100 | Optimization Loop │ │ ... │ 101 | │ ■──────■ 102 | │ 103 | └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ 104 | 105 | Low-level logical optimizations will in general be more restricted than high-level optimizations. 106 | For example, they must be executable without a basis change on any circuit defined over any complete basis from the standard gates. 107 | 108 | This approach allows the high-level logical optimizations which are expected to bring the most substantial performance improvements to be utilized broadly and made distinct from the architecture-specific optimization passes intended to optimize to a given architecture's strengths. 109 | 110 | 111 | # Guide-level explanation 112 | 113 | Before being executed on a device, a `QuantumCircuit` will be transformed through several representations, including the gate set over which the circuit is expressed. 114 | Each backend supports a fixed gate set, so instructions will need to be translated into an equivalent form in the device's native gate set. 115 | Similarly, some transpiler optimizations may only operate on certain gate sets. 116 | Terra provides the necessary tooling to automatically apply these translations, as well as ways to inspect and update the set of valid translations. 117 | 118 | Even when comparing between complete bases, not all gate sets are equivalent in terms of expressiveness. 119 | Applying a given translation will in general yield a circuit with a different gate count and depth. 120 | Practically, within the context of the transpiler, these translations will be followed by optimization passes which will reduce any incurred overhead. 121 | 122 | 123 | ## `qiskit.circuit.EquivalenceLibrary` 124 | 125 | The `EquivalenceLibrary` interface allows for recording and retrieval of interchangeable sets of instructions. 126 | It is used by transpiler developers to store and retrieve identities, or equivalent replacements. 127 | Equivalent here means unitarily equivalent, *not* equivalence up to a global phase or up to a permutation (which could be introduced later). 128 | 129 | Users can easily access the decompositions for a given gate via the `.decompositions` property. 130 | Previously, gates stored only a single definition in their `.definition` property, which has been deprecated. 131 | 132 | 133 | ## Examples 134 | 135 | 136 | ### Setting and fetching gate decompositions via properties 137 | 138 | from qiskit.extensions.standard import CnotGate 139 | 140 | cx = CnotGate() 141 | print(cx.definition) 142 | 143 | None 144 | 145 | for entry in cx.decompositions: 146 | print(entry) 147 | 148 | 149 | q_0: |0>──────■────── 150 | ┌───┐ │ ┌───┐ 151 | q_1: |0>┤ H ├─■─┤ H ├ 152 | └───┘ └───┘ 153 | 154 | from qiskit.extensions.standard import CzGate 155 | cz = CzGate() 156 | for gate, qargs, cargs in cz.definition: 157 | print(gate.name, qargs, cargs) 158 | 159 | h [Qubit(QuantumRegister(2, 'q'), 1)] [] 160 | cx [Qubit(QuantumRegister(2, 'q'), 0), Qubit(QuantumRegister(2, 'q'), 1)] [] 161 | h [Qubit(QuantumRegister(2, 'q'), 1)] [] 162 | 163 | for entry in cz.decompositions: 164 | print(entry) 165 | 166 | 167 | q_0: |0>───────■─────── 168 | ┌───┐┌─┴─┐┌───┐ 169 | q_1: |0>┤ H ├┤ X ├┤ H ├ 170 | └───┘└───┘└───┘ 171 | 172 | 173 | ### Adding user-definition to standard gate 174 | 175 | from qiskit.extensions.standard import HGate 176 | 177 | for entry in HGate().decompositions: 178 | print(entry) 179 | 180 | ┌──────────┐ 181 | q_0: |0>┤ U2(0,pi) ├ 182 | └──────────┘ 183 | 184 | from qiskit.circuit import Gate, QuantumCircuit 185 | from qiskit.extensions.standard import HGate 186 | 187 | my_gate = Gate('special_h', 1, []) 188 | qc = QuantumCircuit(1) 189 | qc.append(my_gate, [0]) 190 | 191 | HGate().decompositions += [qc] 192 | 193 | for entry in HGate().decompositions: 194 | print(entry) 195 | 196 | ┌──────────┐ 197 | q_0: |0>┤ U2(0,pi) ├ 198 | └──────────┘ 199 | ┌───────────┐ 200 | q_0: |0>┤ Special_h ├ 201 | └───────────┘ 202 | 203 | 204 | ### Decomposing Toffoli/GHZ cross-architecture 205 | 206 | ### Expanding device basis sets with cover h,rx,p 207 | 208 | ### Tree traversal, CX->CZ->iSWAP 209 | 210 | 211 | # Detailed Design 212 | 213 | 214 | This proposal introduces two new concepts, that of the `EquivalenceLibrary` and the `BasisTranslator`. 215 | 216 | ## `qiskit.circuit.EquivalenceLibrary` 217 | 218 | print(pydoc.render_doc(qk.circuit.EquivalenceLibrary, renderer=pydoc.plaintext)) 219 | 220 | Python Library Documentation: class EquivalenceLibrary in module qiskit.circuit.equivalence 221 | 222 | class EquivalenceLibrary(builtins.object) 223 | | A library storing equivalence translation rules. 224 | | 225 | | Methods defined here: 226 | | 227 | | __init__(self, *, base=None) 228 | | Create a new equivalence library. 229 | | 230 | | Args: 231 | | base - Optional[CircuitEquivalenceLibrary]: Base equivalence library 232 | | which will be referenced if an entry is not found in this library. 233 | | 234 | | add_entry(self, gate, equivalent_circuit) 235 | | Add one new equivalence definition to the library. 236 | | 237 | | Will be added to all existing equalilities (including base). 238 | | 239 | | Args: 240 | | gate - Gate: \ldots 241 | | equivalent_circuit - QuantumCircuit: \ldots 242 | | 243 | | draw_basis_graph(self) 244 | | 245 | | get_entry(self, gate) 246 | | Get 247 | | 248 | | Args: 249 | | gate - Gate: \ldots 250 | | 251 | | Returns: List[qc], if empty list, library contains no known decompositions 252 | | 253 | | set_entry(self, gate, entry) 254 | | Set 255 | | 256 | | Will override existing definitions. 257 | | 258 | | Args: 259 | | gate - Gate: \ldots 260 | | entry - List[QuantumCircuit]: \ldots 261 | | 262 | | ---------------------------------------------------------------------- 263 | | Data descriptors defined here: 264 | | 265 | | __dict__ 266 | | dictionary for instance variables (if defined) 267 | | 268 | | __weakref__ 269 | | list of weak references to the object (if defined) 270 | 271 | The `EquivalenceLibrary` defines an interface for declaring equivalence between an `Instruction` and one or more `QuantumCircuit`s. 272 | No specific equivalence measure is defined nor enforced by the library, though the transpiler will expect that any defined equivalence can be used as a substitution without impacting the correctness of the circuit. 273 | 274 | Two `EquivalenceLibrary` instances will be automatically instantiated during each Qiskit session: 275 | 276 | - the `StandardEquivalenceLibrary` will be pre-constructed for the gates in the standard library, 277 | - and a `SessionEquivalenceLibrary` will be constructed and will be the source and target of definitions for user-defined gates. 278 | 279 | `EquivalenceLibrary`s can be singly nested, so derived libraries layer modifications on top of an existing library without affecting the original. 280 | 281 | The set of circuits returned in an equivalence entry by the library does not have a defined order, the library consumer should inspect the set to find a desired circuit,. 282 | 283 | If an input gate is parameterized by a set of `qiskit.circuit.Parameters`, the returned circuit will be parameterized by the same `Parameter` set. 284 | 285 | A consequence of this approach is that setting custom definitions on individual `Instruction` instances will no longer be supported. 286 | In the future, this can be replaced by incorporating `EquivalenceLibrary` entries to be tied to an `Instruction` label or instance. 287 | 288 | 289 | ## Example: Fetching standard definition 290 | 291 | from qiskit.extensions.standard import CzGate, CnotGate, ToffoliGate 292 | from qiskit.extensions.standard import StandardEquivalenceLibrary as sel 293 | 294 | cz_entry = sel.get_entry(CzGate()) 295 | cz_entry[0].draw() 296 | 297 | sel.get_entry(ToffoliGate())[0].draw(output='mpl') 298 | 299 | ## `qiskit.transpiler.passes.BasisTranslator` 300 | 301 | As a replacement for the current `Unroller` pass, we introduce a `BasisTranslator` pass which utilizes a provided `EquivalenceLibrary` to find a set of translations to map from a source basis to a target basis via a bramble-search algorithm, as compared to a tree-descent search in the existing `Unroller`. 302 | 303 | # Alternative Approaches 304 | 305 | # Unresolved questions 306 | 307 | Gates which are defined over a variable number of qubits, such as the Mølmer–Sørensen gate, may require additional handling in the `EquivalenceLibrary` interface. 308 | Entries could be defined as callables rather than circuits, either generally or specifically for variadic gates, though this may hinder the ability of transpiler passes to inspect available decompositions and intelligently choose among them. 309 | Storing one circuit entry per gate width in the library is another option, growing the library size proportional to the number of variadic gates and their maximum widths. 310 | 311 | The `Decompose` transpile pass and corresponding `QuantumCircuit.decompose` method depend on a single unique path through `Instruction.definition`. 312 | These methods could be deprecated and removed, maintained via a decomposition search targeting `U3` and `CX`, or maintained via additional library entry labeling to support identification of one entry as the legacy `definition`. 313 | 314 | An efficient means of serializing and reconstructing an `EquivalenceLibrary` will be necessary, both for initially distributing and constructing the `StandardEquivalenceLibrary`, and for users to store, transmit and re-use custom definitions. 315 | 316 | 317 | # Future posibilities 318 | 319 | Following the implementation of this proposal, possible future steps include expanding user control over the scope of decomposition application to a specific `Instruction` label or instance. 320 | Additionally, the `EquivalenceLibrary`'s matching procedures can be enhanced to support fixed parameter simplifications (e.g. `U3(pi/2, 0, pi)` to `H`) and circuit to circuit equivalence. 321 | Envisioned future transpiler passes include noise-aware unrolling, and ancilla-aware unrolling with active ancilla management 322 | --------------------------------------------------------------------------------