diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4013b007a..f716fc416 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,8 +55,16 @@ jobs: run: | python -m pip install --upgrade pip pip install -U tox + pip install nbqa docutils sudo apt install -y graphviz pandoc pip install -e . + + wget https://github.com/errata-ai/vale/releases/download/v2.23.0/vale_2.23.0_Linux_64-bit.tar.gz + mkdir $HOME/bin && tar -xf vale_2.23.0_Linux_64-bit.tar.gz -C $HOME/bin + echo "$HOME/bin" >> $GITHUB_PATH + - name: Lint documentation + run: | + make docs-test - name: Build documentation run: tox -edocs - name: Upload documentation @@ -144,4 +152,4 @@ jobs: uses: coverallsapp/github-action@1.1.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} - parallel-finished: true \ No newline at end of file + parallel-finished: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9616d514..75b711fe4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -270,6 +270,19 @@ out$> make style out$> make mypy ``` +If you edit any documentation, refer to [IBM Quantum's writing style +guide](https://github.com/IBM/ibm-quantum-style-guide). You can use +[Vale](https://vale.sh) to automatically check some of these rules for you. +With Vale installed, run the following command + +```sh +make docs-test +``` + +This test also runs on CI and will fail if Vale encounters any spelling +mistakes. To add a word to the dictionary, add it to +`test/docs/dictionary.txt`. + ### Development Cycle The development cycle for qiskit-ibm is all handled in the open using diff --git a/Makefile b/Makefile index 1d9099ef5..3cd601802 100644 --- a/Makefile +++ b/Makefile @@ -32,6 +32,9 @@ integration-test: e2e-test: python -m unittest discover --verbose --top-level-directory . --start-directory test/e2e +docs-test: + ./test/docs/vale.sh + unit-test-coverage: coverage run -m unittest discover --verbose --top-level-directory . --start-directory test/unit coverage lcov diff --git a/docs/.vale.ini b/docs/.vale.ini new file mode 100644 index 000000000..13557c9fc --- /dev/null +++ b/docs/.vale.ini @@ -0,0 +1,12 @@ +StylesPath = ../test/docs +MinAlertLevel = suggestion + +[[!_]**.{md,rst}] +BasedOnStyles = IBMQuantum + +[apidocs/ibm-runtime.rst] +IBMQuantum.Headings = NO + +# skip './stubs' +[stubs/**] +BasedOnStyles = '' diff --git a/docs/apidocs/ibm-runtime.rst b/docs/apidocs/ibm-runtime.rst index 158972388..29b06f462 100644 --- a/docs/apidocs/ibm-runtime.rst +++ b/docs/apidocs/ibm-runtime.rst @@ -1,5 +1,7 @@ +.. vale off + ***************************************** -qiskit-ibm-runtime API Reference +qiskit-ibm-runtime API reference ***************************************** .. toctree:: diff --git a/docs/cloud/architecture-workload-isolation.rst b/docs/cloud/architecture-workload-isolation.rst index 6f49be53d..2b64de908 100644 --- a/docs/cloud/architecture-workload-isolation.rst +++ b/docs/cloud/architecture-workload-isolation.rst @@ -5,7 +5,7 @@ Learning about Qiskit Runtime architecture and workload isolation Qiskit Runtime jobs run in individual containers in an internal Kubernetes cluster to isolate jobs from any other activities of other users. Jobs are not shared or visible between service instances. However, all users that can access a service instance can see that instance’s jobs, or submit jobs the account owner might be charged for. -Restricting Access to service instances +Restricting access to service instances --------------------------------------- With Qiskit Runtime, you can create service instances that are IAM-managed resources. Accordingly, IAM-based access control can be used for these service instances. diff --git a/docs/cloud/cloud-provider-org.rst b/docs/cloud/cloud-provider-org.rst index f9a79e205..58a5601f5 100644 --- a/docs/cloud/cloud-provider-org.rst +++ b/docs/cloud/cloud-provider-org.rst @@ -1,7 +1,7 @@ Manage users ====================== -You can manage IBM Cloud users or ID provider users. Follow the instructions in the relevant section, depending on your setup. +You can manage IBM Cloud users or ID provider (IDP) users. Follow the instructions in the relevant section, depending on your setup. * :ref:`cloud-users` * :ref:`provider-cloud` @@ -42,7 +42,7 @@ Optional: Modify users’ project assignments 2. Add access groups with **Assign group** or remove the user from an access group by clicking the three dot menu and choosing **Remove user**. -User Flow +User flow ~~~~~~~~~~~~~ 1. After they accept an invitation, users can log in through the `IBM Cloud portal `__. @@ -135,7 +135,7 @@ Integrate the App ID instance as the ID provider for the administrator’s accou 4. The default IdP URL is shown. Share this URL with users when they need to log in. -Add Users +Add users ~~~~~~~~~~ When you use App ID as ID provider with the Cloud directory, you can create users in the IBM Cloud user interface. @@ -314,7 +314,7 @@ User flow .. note:: The administrator can always go to `Manage → Access (IAM) → Identity providers `__ to look up the ID provider URL. -2. To work with Qiskit Runtime serive instances, users must create an API key by going to `Manage → Access (IAM) → API keys `__. +2. To work with Qiskit Runtime service instances, users must create an API key by going to `Manage → Access (IAM) → API keys `__. 3. For further information, users can review `Getting started, Step 2 `__. diff --git a/docs/cloud/cost.rst b/docs/cloud/cost.rst index a17116401..5aa9399be 100644 --- a/docs/cloud/cost.rst +++ b/docs/cloud/cost.rst @@ -13,7 +13,7 @@ Additionally, the system limit on the job execution time is 3 hours for a job th How to limit your cost *********************** -The time your job takes (and therefore, its cost) depends on how many iterations you make in a session and how many shots are run in each iteration. Thus, you can manage your cost by running only as many iterations and shots as you need. +The time your job takes (and therefore, its cost) depends on how many iterations you make in a session and how many shots are run in each iteration. Therefore, you can manage your cost by running only as many iterations and shots as you need. Additionally, an instance administrator can limit how much is spent. To set cost limits, navigate to the `IBM Cloud Instances page `__, then click the instance and set the **Cost limit**. The cost limit refers to the total cost of all jobs run with this instance since it was created, and it will always be greater than or equal to the Total cost. After the instance reaches the specified number of total seconds, no further jobs can be run and no more cost is incurred. @@ -71,7 +71,7 @@ Set up spending notifications You can set up spending notifications to get notified when your account or a particular service reaches a specific spending threshold that you set. For information, see the `IBM Cloud account Type description `__. IBM Cloud spending notifications must be used with other methods of cost management for several reasons: - The notifications trigger only *after* cost surpasses the specified limit. -- Cost is submitted to the billing system hourly. Thus, a long delay might occur between the job submission and the spending notification being sent. +- Cost is submitted to the billing system hourly. Therefore, a long delay might occur between the job submission and the spending notification being sent. - The billing system can take multiple days to get information to the invoicing system, which might cause further delay in notifications. For more information about how the IBM Cloud billing system works, see `Setting spending notifications `__. Next steps diff --git a/docs/cloud/plans.rst b/docs/cloud/plans.rst index 4fafc2288..9d89447fc 100644 --- a/docs/cloud/plans.rst +++ b/docs/cloud/plans.rst @@ -11,27 +11,27 @@ Lite plan A free plan that gives you access to quantum simulators to help you get started with Qiskit Runtime. It does not include access to IBM Quantum systems. The following simulators are included in this plan: -- **ibmq_qasm_simulator**: A general-purpose simulator for simulating quantum circuits both ideally and subject to noise modeling. The simulation method is automatically selected based on the input circuits and parameters. +- ``ibmq_qasm_simulator``: A general-purpose simulator for simulating quantum circuits both ideally and subject to noise modeling. The simulation method is automatically selected based on the input circuits and parameters. - **Type**: General, context-aware - **Simulatable Qubits**: 32 -- **simulator_statevector**: Simulates a quantum circuit by computing the wave function of the qubit’s state vector as gates and instructions are applied. Supports general noise modeling. +- ``simulator_statevector``: Simulates a quantum circuit by computing the wave function of the qubit’s state vector as gates and instructions are applied. Supports general noise modeling. - **Type**: Schrödinger wave function - **Simulated Qubits**: 32 -- **simulator_mps**: A tensor-network simulator that uses a Matrix Product State (MPS) representation for the state that is often more efficient for states with weak entanglement. +- ``simulator_mps``: A tensor-network simulator that uses a Matrix Product State (MPS) representation for the state that is often more efficient for states with weak entanglement. - **Type**: Matrix Product State - **Simulated Qubits**: 100 -- **simulator_stabilizer**: An efficient simulator of Clifford circuits. Can simulate noisy evolution if the noise operators are also Clifford gates. +- ``simulator_stabilizer``: An efficient simulator of Clifford circuits. Can simulate noisy evolution if the noise operators are also Clifford gates. - **Type**: Clifford - **Simulated Qubits**: 5000 -- **simulator_extended_stabilizer**: Approximates the action of a quantum circuit by using a ranked-stabilizer decomposition. The number of non-Clifford gates determines the number of stabilizer terms. +- ``simulator_extended_stabilizer``: Approximates the action of a quantum circuit by using a ranked-stabilizer decomposition. The number of non-Clifford gates determines the number of stabilizer terms. - **Type**: Extended Clifford (for example, Clifford+T) - **Simulated Qubits**: 63 diff --git a/docs/cloud/quickstart-org.rst b/docs/cloud/quickstart-org.rst index 6e61fe0d7..9d51362b8 100644 --- a/docs/cloud/quickstart-org.rst +++ b/docs/cloud/quickstart-org.rst @@ -10,7 +10,7 @@ Overview IBM Cloud provides various ways to implement these mechanisms described in this tutorial. There are several ways to achieve these objectives. Additionally, most of the steps in this tutorial are generic to IBM Cloud and not specific to Qiskit Runtime, except the custom role details. -Involved Personas +Involved personas ~~~~~~~~~~~~~~~~~ The are several main personas that are mentioned in this tutorial: diff --git a/docs/cloud/quickstart.rst b/docs/cloud/quickstart.rst index e28617323..772fb084a 100644 --- a/docs/cloud/quickstart.rst +++ b/docs/cloud/quickstart.rst @@ -20,7 +20,7 @@ If you already created a Qiskit Runtime service instance or were invited to one 1. From the `Qiskit Runtime Provisioning page `__, choose the appropriate service plan, depending on what you need access to. For more information about these plans, see the `Qiskit Runtime plans `__ topic. - **Lite**: Free simulators-only plan to help you get started with Qiskit Runtime. Learn to use Qiskit Runtime by following our examples and tutorials for one of the pre-built programs available for running circuits efficiently. - - **Standard**: A pay-as-you-go model for accessing IBM Quantum systems and simulators. Build your own programs and leverage all the benefits of Qiskit Runtime by running on real quantum hardware. + - **Standard**: A pay-as-you-go model for accessing IBM Quantum systems and simulators. Build your own programs and use all the benefits of Qiskit Runtime by running on real quantum hardware. Because this is not a free plan, it is important to understand how to best manage your costs. See `Manage the cost `__ for tips to limit your cost, how to set up spending notifications, and more. diff --git a/docs/cloud/setup-terraform.rst b/docs/cloud/setup-terraform.rst index 1355341ae..6aeb5a8e0 100644 --- a/docs/cloud/setup-terraform.rst +++ b/docs/cloud/setup-terraform.rst @@ -1,12 +1,12 @@ Set up Terraform for Qiskit Runtime =================================== -If you use Terraform to manage your infrastructure, the `IBM Cloud provider for Terraform `__ supports provisioning Qiskit Runtime service instances. The generic "ibm_resource_instance" resource is used for that. The following parameters have to be specified: +If you use Terraform to manage your infrastructure, the `IBM Cloud provider for Terraform `__ supports provisioning Qiskit Runtime service instances. The generic ``ibm_resource_instance`` resource is used for that. The following parameters have to be specified: Provisioning with Terraform --------------------------- -If you use Terraform to manage your infrastructure, the `IBM Cloud provider for Terraform `__ supports provisioning Qiskit Runtime service instances. The generic "ibm_resource_instance" resource is used for that. The following parameters have to be specified: +If you use Terraform to manage your infrastructure, the `IBM Cloud provider for Terraform `__ supports provisioning Qiskit Runtime service instances. The generic ``ibm_resource_instance`` resource is used for that. The following parameters have to be specified: - ``name`` – The name of your service instance. - ``service`` – Specify ``quantum-computing`` to provision Qiskit Runtime instances. @@ -18,7 +18,7 @@ Optional parameters include: - ``resource_group_id`` – Creates the service instance in the specified resource group. - ``tags`` – Add tags to the resource. -Example: Creating a Service Instance of Qiskit Runtime +Example: Creating a service instance of Qiskit Runtime ------------------------------------------------------ After the job completes, you can view the results. diff --git a/docs/compare.rst b/docs/compare.rst index 35e608eae..f34e131a5 100644 --- a/docs/compare.rst +++ b/docs/compare.rst @@ -24,7 +24,7 @@ Qiskit Runtime offers advantages in workload performance. Variational algorithms can run on classical compute resources that are colocated with the QPUs through the Estimator primitive program. This allows users to run iterative algorithm circuits back to back. In addition, sessions -can drive a sequence of jobs without having to requeue each job, +can drive a sequence of jobs without having to re-queue each job, avoiding latencies of queue wait times after the session is actively running. As a result, Qiskit Runtime is much more efficient than its predecessors. diff --git a/docs/faqs.rst b/docs/faqs.rst index 3530431a4..f30adcbe1 100644 --- a/docs/faqs.rst +++ b/docs/faqs.rst @@ -1,7 +1,7 @@ .. _faqs: ######################################### -Frequently Asked Questions +Frequently asked questions ######################################### .. toctree:: diff --git a/docs/faqs/max_execution_time.rst b/docs/faqs/max_execution_time.rst index 34271a5fb..edfa09736 100644 --- a/docs/faqs/max_execution_time.rst +++ b/docs/faqs/max_execution_time.rst @@ -8,7 +8,7 @@ To ensure fairness, there is a maximum execution time for each Qiskit Runtime jo a job exceeds this time limit, it is forcibly cancelled. This is represented in the job status as `Cancelled - Ran too long`. The maximum execution time is the smaller of 1) the system limit and 2) the ``max_execution_time`` defined by the program. -The system limit is defined below: +The system limit is defined as follows: Qiskit Runtime on IBM Cloud --------------------------- @@ -34,7 +34,7 @@ The system limit on the job execution time is Note that a *premium user* here means a user who has access to backends in providers other than ibm-q/open/main. -Other Limitations +Other limitations ----------------- - Programs cannot exceed 750KB in size. diff --git a/docs/faqs/open_source_vs_ibm_cloud_primitives.rst b/docs/faqs/open_source_vs_ibm_cloud_primitives.rst index 4ce2f6862..f7cc9d05f 100644 --- a/docs/faqs/open_source_vs_ibm_cloud_primitives.rst +++ b/docs/faqs/open_source_vs_ibm_cloud_primitives.rst @@ -1,8 +1,8 @@ .. _faqs/open_source_vs_ibm_cloud_primitives: -================================================================================================= -What is the difference between the open source primitives and primitives available via IBM Cloud? -================================================================================================= +===================================================================================================== +What is the difference between the open source primitives and primitives available through IBM Cloud? +===================================================================================================== The open source primitive contains the base classes (to define interfaces) and a reference implementation. The Qiskit Runtime primitive is planned to provide more sophisticated implementation (such as with error diff --git a/docs/getting_started.rst b/docs/getting_started.rst index d4824666a..d04b92bf4 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -6,7 +6,7 @@ Install Qiskit packages ======================== Install these packages. They let you create circuits and work with primitive programs -via Qiskit Runtime. +through Qiskit Runtime. .. code-block:: bash @@ -64,7 +64,7 @@ Run the Hello World program to ensure that your environment is set up properly: print(result) -Getting started with Primitives +Getting started with primitives ================================= .. nbgallery:: diff --git a/docs/how_to/account-management.rst b/docs/how_to/account-management.rst index f435b0ffa..9555dce1e 100644 --- a/docs/how_to/account-management.rst +++ b/docs/how_to/account-management.rst @@ -54,7 +54,7 @@ Alternatively, if you specified a name for your account when saving it, you can service = QiskitRuntimeService(name="prod") -If you want to use your credentials for just the session instead of saving it, you can pass the credentials in when initializing the ``QiskitRuntimeService`` instance: +If you want to use your credentials for just the session rather than saving it, you can pass the credentials in when initializing the ``QiskitRuntimeService`` instance: .. code-block:: python diff --git a/docs/how_to/backends.rst b/docs/how_to/backends.rst index 6abd07e00..cb8bb24a3 100644 --- a/docs/how_to/backends.rst +++ b/docs/how_to/backends.rst @@ -1,24 +1,24 @@ Run on quantum backends ================================= -A **backend** represents either a simulator or a real quantum computer and are responsible for running quantum circuits and/or pulse schedules and returning results. +A **backend** represents either a simulator or a real quantum computer and are responsible for running quantum circuits, running pulse schedules, and returning results. In qiskit-ibm-runtime, a backend is represented by an instance of the ``IBMBackend`` class. Attributes of this class provides information about this backend. For example: -* name: Name of the backend. -* instructions: A list of instructions the backend supports. -* operation_names: A list of instruction names the backend supported. -* num_qubits: The number of qubits the backend has. -* coupling_map: Coupling map of the backend. -* dt: System time resolution of input signals. -* dtm: System time resolution of output signals. +* ``name``: Name of the backend. +* ``instructions``: A list of instructions the backend supports. +* ``operation_names``: A list of instruction names the backend supported. +* ``num_qubits``: The number of qubits the backend has. +* ``coupling_map``: Coupling map of the backend. +* ``dt``: System time resolution of input signals. +* ``dtm``: System time resolution of output signals. Refer to the `API reference `__ for a complete list of attributes and methods. Initialize the service ------------------------ -Before calling ``IBMBackend``, inialize the service: +Before calling ``IBMBackend``, initialize the service: .. code-block:: python @@ -110,8 +110,11 @@ As mentioned previously, the ``IBMBackend`` class attributes provide information backend.simulator #returns True or False, depending on whether it is a simulator backend.num_qubits #returns the number of qubits the backend has +.. vale IBMQuantum.Spelling = NO + See the `IBMBackend class documentation `__ for the full list of backend attributes. +.. vale IBMQuantum.Spelling = YES Find backend information from other channels -------------------------------------------------- diff --git a/docs/how_to/error-mitigation.rst b/docs/how_to/error-mitigation.rst index 0bc4622ff..6ef017546 100644 --- a/docs/how_to/error-mitigation.rst +++ b/docs/how_to/error-mitigation.rst @@ -1,9 +1,11 @@ Configure error mitigation ============================= +.. vale IBMQuantum.Definitions = NO + Error mitigation techniques allow users to mitigate circuit errors by modeling the device noise at the time of execution. This typically results in quantum pre-processing overhead related to model training and classical post-processing overhead to mitigate errors in the raw results by using the generated model. -The error mitigation techniques built in to primitives are advanced resilience options. To specify these options, use the `resilience_level` option when submitting your job. +The error mitigation techniques built in to primitives are advanced resilience options. To specify these options, use the ``resilience_level`` option when submitting your job. The resilience level specifies how much resilience to build against errors. Higher levels generate more accurate results, at the expense of longer processing times. Resilience levels can be used to configure the cost/accuracy trade-off when applying error mitigation to your primitive query. Error mitigation reduces errors (bias) in results by processing the outputs from a collection, or ensemble, of related circuits. The degree of error reduction depends on the method applied. The resilience level abstracts the detailed choice of error mitigation method to allow users to reason about the cost/accuracy trade that is appropriate to their application. @@ -51,7 +53,7 @@ No error mitigation is applied to the user program. .. _TREX: -Level 1 applies error mitigation methods that particularly address readout errors. In the Estimator, we apply a model-free technique known as Twirled Readout Error eXtinction (TREX). It reduces measurement error by diagonalizing the noise channel associated with measurement by randomly flipping qubits via X gates immediately prior to measurement, and flipping the corresponding measured bit if an X gate was applied. A rescaling term from the diagonal noise channel is learned by benchmarking random circuits initialized in the zero state. This allows the service to remove bias from expectation values that result from readout noise. This approach is described further in `Model-free readout-error mitigation for quantum expectation values `__. +Level 1 applies error mitigation methods that particularly address readout errors. In the Estimator, we apply a model-free technique known as Twirled Readout Error eXtinction (TREX). It reduces measurement error by diagonalizing the noise channel associated with measurement by randomly flipping qubits through X gates immediately before measurement, and flipping the corresponding measured bit if an X gate was applied. A rescaling term from the diagonal noise channel is learned by benchmarking random circuits initialized in the zero state. This allows the service to remove bias from expectation values that result from readout noise. This approach is described further in `Model-free readout-error mitigation for quantum expectation values `__. .. raw:: html @@ -64,7 +66,7 @@ Level 1 applies error mitigation methods that particularly address readout error .. _ZNE: -Level 2 leverages Zero Noise Extrapolation method (ZNE) which computes an expectation value of the observable for different noise factors (amplification stage) and then uses the measured expectation values to infer the ideal expectation value at the zero-noise limit (extrapolation stage). This approach tends to reduce errors in expectation values, but is not guaranteed to produce an unbiased result. +Level 2 uses the Zero Noise Extrapolation method (ZNE) which computes an expectation value of the observable for different noise factors (amplification stage) and then uses the measured expectation values to infer the ideal expectation value at the zero-noise limit (extrapolation stage). This approach tends to reduce errors in expectation values, but is not guaranteed to produce an unbiased result. .. figure:: ../images/resiliance-2.png :alt: This image shows a graph that compares the noise amplification factor to expectation values. @@ -107,14 +109,14 @@ The sampling overhead scales exponentially with a parameter that characterizes t When the Estimator completes the model-learning phase of the primitive query, it will return metadata about the total sampling overhead for circuit. -Depending on the precision required by your application, you will need to scale the number of samples accordingly. The plot below illustrates the relationship between estimator error and number of circuit samples for different total sampling overheads. +Depending on the precision required by your application, you will need to scale the number of samples accordingly. The following plot illustrates the relationship between estimator error and number of circuit samples for different total sampling overheads. .. figure:: ../images/sampling-overhead.png - :alt: This image shows that samping overhead goes down as the number of samples increases. + :alt: This image shows that sampling overhead goes down as the number of samples increases. Note that the number of samples required to deliver a desired accuracy is not known before the primitive query because the mitigation scaling factor is discovered during the learning phase of PEC. -We recommend starting with short depth circuits to get a feel for the scaling of the sampling overhead of PEC prior to attempting larger problems. +We suggest starting with short depth circuits to get a feel for the scaling of the sampling overhead of PEC before attempting larger problems. .. raw:: html @@ -123,7 +125,7 @@ We recommend starting with short depth circuits to get a feel for the scaling of Example ^^^^^^^ -The Estimator interface lets users seamlessly work with the variety of error mitigation methods to reduce error in expectation values of observables. Below is an example of leveraging Zero Noise Extrapolation by simply setting ``resilience_level 2``. +The Estimator interface lets users seamlessly work with the variety of error mitigation methods to reduce error in expectation values of observables. The following code uses Zero Noise Extrapolation by simply setting ``resilience_level 2``. .. code-block:: python @@ -142,7 +144,7 @@ The Estimator interface lets users seamlessly work with the variety of error mit session.close() .. note:: - As you increase the resilience level, you will be able to leverage additional methods to improve the accuracy of your result. However, because the methods become more advanced with each level, they require additional sampling overhead (time) to generate more accurate expectation values. + As you increase the resilience level, you will be able to use additional methods to improve the accuracy of your result. However, because the methods become more advanced with each level, they require additional sampling overhead (time) to generate more accurate expectation values. Configure Sampler with resilience levels ----------------------------------------- @@ -155,7 +157,7 @@ The Sampler default resilience setting (level 1) enables readout error mitigatio
Resilience Level 1 -Level 1 leverages matrix-free measurement mitigation (M3) routine to mitigate readout error. M3 works in a reduced subspace defined by the noisy input bitstrings that are to be corrected. Because the number of unique bitstrings can be much smaller than the dimensionality of the full multi-qubit Hilbert space, the resulting linear system of equations is nominally much easier to solve. +Level 1 uses matrix-free measurement mitigation (M3) routine to mitigate readout error. M3 works in a reduced subspace defined by the noisy input bit strings that are to be corrected. Because the number of unique bit strings can be much smaller than the dimensionality of the full multi-qubit Hilbert space, the resulting linear system of equations is nominally much easier to solve. .. figure:: ../images/m3.png :alt: This image illustrates the M3 routine. @@ -183,7 +185,7 @@ Advanced resilience options You can tune advanced options to configure your resilience strategy further. These methods can be used alongside resilience levels where you change the specific options of interest and let your previously set resilience level manage the rest. -As a part of the beta release of the resilience options, users will be able configure ZNE by using the following advanced options below. We will soon add options to tune other resilience levels that include PEC. +As a part of the beta release of the resilience options, users will be able configure ZNE by using the following advanced options. We will soon add options to tune other resilience levels that include PEC. +---------------------------------------------------------------+----------------------------------+--------------------------------------------------------+ | Options | Inputs | Description | diff --git a/docs/how_to/error-suppression.rst b/docs/how_to/error-suppression.rst index 1b507cbe5..db91e3aa0 100644 --- a/docs/how_to/error-suppression.rst +++ b/docs/how_to/error-suppression.rst @@ -10,7 +10,7 @@ Primitives let you employ error suppression techniques by setting the optimizati Setting the optimization level ------------------------------ -The optimization_levels setting specifies how much optimization to perform on the circuits. Higher levels generate more optimized circuits, at the expense of longer transpilation times. +The ``optimization_level`` setting specifies how much optimization to perform on the circuits. Higher levels generate more optimized circuits, at the expense of longer transpilation times. +--------------------+---------------------------------------------------------------------------------------------------+ | Optimization Level | Estimator & Sampler | diff --git a/docs/how_to/noisy_simulators.rst b/docs/how_to/noisy_simulators.rst index da5483956..b4c4af8e1 100644 --- a/docs/how_to/noisy_simulators.rst +++ b/docs/how_to/noisy_simulators.rst @@ -1,17 +1,17 @@ -Noisy Simulators in Qiskit Runtime +Noisy simulators in Qiskit Runtime ================================== -This notebook shows how to setup ``ibmq_qasm_simulator`` and map a basic -noise model for an IBM Quantum hardware device in **Qiskit Runtime**, and -use this noise model to do noisy simulations of ``QuantumCircuits`` on -``Sampler`` and ``Estimator`` to study the effects of errors which occur -on real devices. +This notebook shows how to set up ``ibmq_qasm_simulator`` and map a basic noise +model for an IBM Quantum hardware device in **Qiskit Runtime**, and use this +noise model to perform noisy simulations of ``QuantumCircuits`` using +``Sampler`` and ``Estimator`` to study the effects of errors which occur on +real devices. Set up your local development environment ----------------------------------------- This tutorial requires a Qiskit Runtime service instance to be setup. If -you haven’t done so already, please follow `these +you haven’t done so already, follow `these steps `__ to set one up. @@ -30,7 +30,7 @@ routine. One of the major benefits of using primitives is simplification of binding multiple parameters in parameterized circuits. To check this, here is an example circuit with a controlled `P-gate `__ -as implemented right below. Here, we parametrise the ``P-gate`` with a +as implemented in the following code. Here, we parametrise the ``P-gate`` with a rotation parameter ``theta``. To learn how to create circuits and bind parameters to them by using Qiskit, see the `Circuit Basics `__ @@ -61,12 +61,11 @@ in Qiskit documentation. -The circuit shown above is parameterized with the eigenvalue being -kicked back into qubit 0 to be measured. The amount of kickback will be -determined by the parameter theta. Now in the cell below, we shall -define our parameters for our above circuit as a list. The parameters -here will be from :math:`0` to :math:`2\pi` divided over 50 evenly -spaced points. +The circuit shown by the previous cell is parameterized with the eigenvalue +being kicked back into qubit 0 to be measured. The amount of kickback will be +determined by the parameter theta. Now in the following cell, we shall define +our parameters for our circuit as a list. The parameters here will be from +:math:`0` to :math:`2\pi` divided over 50 evenly spaced points. .. code-block:: python @@ -85,8 +84,8 @@ Set the backend and options to use First we shall demonstrate a run using an ideal case without any ``noise_model``, ``optimization_level`` or ``resilience_level`` for both -Sampler and Estimator. We shall proceed to setup the options as shown -below: +Sampler and Estimator. We shall proceed to setup the options in the following +code: .. code-block:: python @@ -104,8 +103,8 @@ Run the circuits on Sampler ~~~~~~~~~~~~~~~~~~~~~~~~~~~ We shall now sample the circuit to get the result probability -distribution. We shall be utilizing the `Sampler -primitive `__ +distribution using the `Sampler primitive +`__ to do the same. To learn how to use the ``Sampler`` primitive and how to get started using Qiskit Runtime Sessions, you can check this tutorial: `Get started with the Sampler @@ -154,7 +153,7 @@ To learn how to start a session for Estimator, you may check this tutorial: `Get started with the Estimator primitive `__. -The Estimator will bind single-qubit rotations to get hamiltonians +The Estimator will bind single-qubit rotations to get Hamiltonians before it returns expectation values of quantum operators. Therefore, the circuit doesn’t require any measurements. Currently the circuit ``qc`` has measurements so we will remove these with @@ -186,13 +185,13 @@ the circuit doesn’t require any measurements. Currently the circuit With this observable, the expectation value is calculated by the -equation below. +following equation. .. math:: \langle ZZ\rangle =\langle \psi | ZZ | \psi\rangle=\langle \psi|(|0\rangle\langle 0| -|1\rangle\langle 1|)\otimes(|0\rangle\langle 0| - |1\rangle\langle 1|) |\psi\rangle =|\langle 00|\psi\rangle|^2 - |\langle 01 | \psi\rangle|^2 - |\langle 10 | \psi\rangle|^2 + |\langle 11|\psi\rangle|^2 -The next cell will implement the above as shown. +The next cell will implement this as shown. .. code-block:: python @@ -234,7 +233,7 @@ Running a noisy simulation Now we’ll setup our simulator to run a noisy simulation rather than the ideal one. We can pass a custom ``noise_model`` to the simulator on Runtime by specifying it in the ``Options`` parameter. Here we will try -to mimic a real backend and map on the noise_model from a +to mimic a real backend and map on the ``noise_model`` from a ``FakeBackend`` class. The noise model can be extracted from the ``FakeBackend`` and passed as a ``simulator`` parameter in options. If you want to know more about ``fake_provider``, check `Fake @@ -271,16 +270,15 @@ that the backend supports to have a more realistic noisy simulation. The ``ibmq_qasm_simulator`` allows for the activation of the ``resilience_levels`` offered by the Qiskit Runtime Service, and use of these levels on simulators is best demonstrated using the noisy -simulation as we have described above. +simulation as we have described previously. -To see the comparision, we shall define two set of ``Options``. The ibmq -qasm simulator allows for the activation of the resilience levels -offered by Qiskit Runtime, and the use of these levels on simulators is -best demonstrated using the noisy simulation that we have built. Here, -``options`` is set to\ ``resilience level`` = ``0`` to represent a -normal run without error mitigation, and ``options with em`` is set to -``resilience level`` = ``1`` to represent a run with error mitigation -enabled. +To see the comparison, we shall define two set of ``Options``. The +``ibmq_qasm_simulator`` allows for the activation of the resilience levels +offered by Qiskit Runtime, and the use of these levels on simulators is best +demonstrated using the noisy simulation that we have built. Here, ``options`` +is set to\ ``resilience level`` = ``0`` to represent a normal run without error +mitigation, and ``options with em`` is set to ``resilience level`` = ``1`` to +represent a run with error mitigation enabled. .. code-block:: python @@ -392,14 +390,16 @@ All available resilience level configurations can be found .. image:: ../images/noisy-sim-estimator-noisy.png +.. vale IBMQuantum.Definitions = NO + Resilience levels are currently in beta so sampling overhead and solution quality will vary from circuit to circuit. New features, advanced options and management tools will be released on a rolling -basis. You can also play around wtih higher levels of resilience and -explore additional options offered by them. If you wish to learn more +basis. You can also play around with higher levels of resilience and +explore additional options offered by them. If you want to learn more about activating features like *Digital-ZNE*, *PEC* in addition to *M3* -and *T-REx* as shown in the examples above, check out this tutorial: -`Error supression and error mitigation with Qiskit +and *T-REx* as shown in the previous examples, check out this tutorial: +`Error suppression and error mitigation with Qiskit Runtime `__. .. code-block:: python diff --git a/docs/how_to/run_session.rst b/docs/how_to/run_session.rst index eb907431f..d11bc0856 100644 --- a/docs/how_to/run_session.rst +++ b/docs/how_to/run_session.rst @@ -1,8 +1,8 @@ Run a primitive in a session ================================= -A Qiskit Runtime session allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. As long as the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead. -As a result, sessions allow you to more efficiently run programs that require iterative calls between classical and quantum resources while giving you the flexibility to deploy your programs remotely on cloud or on-premise classical resources (including your laptop). +A Qiskit Runtime session allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. Provided that the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead. +As a result, sessions allow you to more efficiently run programs that require iterative calls between classical and quantum resources while giving you the flexibility to deploy your programs remotely on cloud or on-premises classical resources (including your laptop). Before you begin ---------------- @@ -92,7 +92,7 @@ After this time limit is reached, the session is permanently closed and any queu Additionally, there is an *interactive* timeout value. If there are no session jobs queued within that window, the session is temporarily deactivated and normal job selection resumes. After a session is deactivated, a subsequent job could start an additional session. Jobs for the new session would then take priority until the new session deactivates or is closed. After the new session becomes inactive, if the job scheduler gets a job from the original session and its maximum timeout value has not been reached, the session is reactivated until its maximum timeout value is reached. -When you are done submitting jobs, you are encouraged to use ``session.close()`` to close the session. This allows the scheduler to run the next job without waiting for the session timeout. Keep in mind, however, that you cannot submit more jobs to a closed session. +When you are done submitting jobs, you are encouraged to use ``session.close()`` to close the session. This allows the scheduler to run the next job without waiting for the session timeout. Remember, however, that you cannot submit more jobs to a closed session. Retrieve previous job results ----------------------------------- @@ -113,5 +113,5 @@ Jobs are also listed on the Jobs page for your quantum service instance. How session jobs fit into the job queue ------------------------------------------ -For each backend, the first job in the session waits its turn in the queue normally, but while the session is active, subsequent jobs within the same session take priority over any other queued jobs. If there are no jobs that are part of a session, the next job from the regular fair-share queue is run. Jobs still run one at a time. Thus, jobs that belong to a session still queue up if you already have one running, but you do not have to wait for them to complete before submitting more jobs. +For each backend, the first job in the session waits its turn in the queue normally, but while the session is active, subsequent jobs within the same session take priority over any other queued jobs. If there are no jobs that are part of a session, the next job from the regular fair-share queue is run. Jobs still run one at a time. Therefore, jobs that belong to a session still queue up if you already have one running, but you do not have to wait for them to complete before submitting more jobs. diff --git a/docs/index.rst b/docs/index.rst index 2a1e1a887..ea9a077a3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,7 +13,7 @@ programs. .. figure:: images/runtime-architecture.png :align: center -Key Concepts +Key concepts ============== **Primitives** @@ -37,7 +37,7 @@ multiple relevant data points in the context of destructive interference. -Next Steps +Next steps ================================= `Getting started `_ diff --git a/docs/migrate_from_ibmq.rst b/docs/migrate_from_ibmq.rst index 858bd5008..e0367cd8b 100644 --- a/docs/migrate_from_ibmq.rst +++ b/docs/migrate_from_ibmq.rst @@ -10,7 +10,7 @@ The classes related to Qiskit Runtime that used to be included in ``qiskit-ibmq- Changes in Class name and location ================================== -The module from which the classes are imported has changed. Below is a table of example access patterns in ``qiskit.providers.ibmq.runtime`` and their new form in ``qiskit_ibm_runtime``: +The module from which the classes are imported has changed. The following table contains example access patterns in ``qiskit.providers.ibmq.runtime`` and their new form in ``qiskit_ibm_runtime``: .. list-table:: Migrate from ``qiskit.providers.ibmq.runtime`` in ``qiskit-ibmq-provider`` to ``qiskit-ibm-runtime`` :header-rows: 1 diff --git a/docs/primitives.rst b/docs/primitives.rst index 1e4dc4c93..3d5032ae3 100644 --- a/docs/primitives.rst +++ b/docs/primitives.rst @@ -7,9 +7,9 @@ The existing Qiskit interface to backends (`backend.run()`) was originally desig For example, an algorithm researcher and developer cares about information beyond counts; they are more focused on efficiently calculating quasiprobabilities and expectation values of observables. -Our primitives provide methods that make it easier to build modular algorithms and other higher-order programs. Instead of simply returning counts, they return more immediately meaningful information. Additionally, they provide a seamless way to access the latest optimizations in IBM Quantum hardware and software. +Our primitives provide methods that make it easier to build modular algorithms and other higher-order programs. Rather than simply returning counts, they return more immediately meaningful information. Additionally, they provide a seamless way to access the latest optimizations in IBM Quantum hardware and software. -The basic operations that one can do with a probability distribution is to sample from it or to estimate quantities on it. Therefore, these operations form the fundamental building blocks of quantum algorithm development. Our first two Qiskit Runtime primitives (Sampler and Estimator) use these sampling and estimating operations as core interfaces to our quantum systems. +The basic operations that one can perform with a probability distribution is to sample from it or to estimate quantities on it. Therefore, these operations form the fundamental building blocks of quantum algorithm development. Our first two Qiskit Runtime primitives (Sampler and Estimator) use these sampling and estimating operations as core interfaces to our quantum systems. Available primitives -------------------- diff --git a/docs/tutorials/Error-Suppression-and-Error-Mitigation.ipynb b/docs/tutorials/Error-Suppression-and-Error-Mitigation.ipynb index 0cd9e804e..3dbe05f7a 100644 --- a/docs/tutorials/Error-Suppression-and-Error-Mitigation.ipynb +++ b/docs/tutorials/Error-Suppression-and-Error-Mitigation.ipynb @@ -9,7 +9,7 @@ } }, "source": [ - "# Error supression and error mitigation with Qiskit Runtime\n", + "# Error suppression and error mitigation with Qiskit Runtime\n", "\n", "**Pedro Rivero** \n", "Quantum Developer @ IBM Quantum \n", @@ -17,7 +17,9 @@ "\n", "**Mariana Bernagozzi** \n", "Software Engineer @ IBM Quantum \n", - "[mariana.bernagozzi@ibm.com](mariana.bernagozzi@ibm.com)\n" + "[mariana.bernagozzi@ibm.com](mariana.bernagozzi@ibm.com)\n", + "\n", + "" ] }, { @@ -35,8 +37,9 @@ "import numpy as np\n", "import matplotlib as mpl\n", "import matplotlib.pyplot as plt\n", + "\n", "plt.rcParams.update({\"text.usetex\": True})\n", - "plt.rcParams[\"figure.figsize\"] = (6,4)\n", + "plt.rcParams[\"figure.figsize\"] = (6, 4)\n", "mpl.rcParams[\"figure.dpi\"] = 200\n", "\n", "from qiskit_ibm_runtime import Estimator, Session, QiskitRuntimeService, Options\n", @@ -56,7 +59,7 @@ "## Introduction\n", "To illustrate the need for error suppression and mitigation, we will start by taking a look at some results without error suppression or error mitigation. First, we are going to use a noiseless simulator to get an idea of what ideal results look like. Next, we are going to run the same experiment in a real backend without using error suppression or error mitigation. \n", "\n", - "For the experiments, we are going to use a list of Trotter circuits defined below.\n", + "The following code cell defines a list of Trotter circuits for use in the experiments.\n", "\n", "### Create a Trotter circuit" ] @@ -316,17 +319,19 @@ "source": [ "options = Options()\n", "options.execution.shots = 1000\n", - "options.optimization_level = 0 # No optimization\n", - "options.resilience_level = 0 # No mitigation\n", + "options.optimization_level = 0 # No optimization\n", + "options.resilience_level = 0 # No mitigation\n", "\n", "with Session(service=service, backend=backend_simulator) as session:\n", " estimator_sim = Estimator(session=session, options=options)\n", " job_sim = estimator_sim.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_sim.job_id)\n", + " print(\"job id:\", job_sim.job_id)\n", " print(job_sim.result())\n", "\n", "expvals_ideal = job_sim.result().values\n", - "expvals_ideal_variance = [metadata['variance']/metadata['shots'] for metadata in job_sim.result().metadata]\n", + "expvals_ideal_variance = [\n", + " metadata[\"variance\"] / metadata[\"shots\"] for metadata in job_sim.result().metadata\n", + "]\n", "std_error_ideal = np.sqrt(expvals_ideal_variance)" ] }, @@ -365,17 +370,19 @@ "source": [ "options = Options()\n", "options.execution.shots = 1000\n", - "options.optimization_level = 0 # No optimization\n", - "options.resilience_level = 0 # No error mitigation\n", + "options.optimization_level = 0 # No optimization\n", + "options.resilience_level = 0 # No error mitigation\n", "\n", "with Session(service=service, backend=backend) as session:\n", " estimator = Estimator(session=session, options=options)\n", " job = estimator.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job.job_id)\n", + " print(\"job id:\", job.job_id)\n", " print(job.result())\n", "\n", "expvals_unmit = job.result().values\n", - "expvals_unmit_variance = [metadata['variance']/metadata['shots'] for metadata in job.result().metadata]\n", + "expvals_unmit_variance = [\n", + " metadata[\"variance\"] / metadata[\"shots\"] for metadata in job.result().metadata\n", + "]\n", "std_error_unmit = np.sqrt(expvals_unmit_variance)" ] }, @@ -430,7 +437,7 @@ "\n", "There are several ways to handle these errors. The terminology can get confusing, as there is disagreement even within the field. We will break it into three core pieces:\n", "\n", - "1. Supression\n", + "1. Suppression\n", "2. Mitigation\n", "3. Correction\n", "\n", @@ -486,7 +493,7 @@ "id": "9fc2531a-e7e0-421c-a45b-76d7e3195f9d", "metadata": {}, "source": [ - "\\* The data in the above table is based on simulations for surface codes with certain conditions. The code distance was chosen so that none of the T-gates, or 100 logical qubits at the end of runtime, had error greater than $1\\text{E}-2$. The number of T-gates is $n \\times d$ and each parity check cycle takes $1 \\mu s$.\n", + "\\* The data in the previous table is based on simulations for surface codes with certain conditions. The code distance was chosen so that none of the T-gates, or 100 logical qubits at the end of runtime, had error greater than $1\\text{E}-2$. The number of T-gates is $n \\times d$ and each parity check cycle takes $1 \\mu s$.\n", "\n", "__Reference__: Daniel Litinski, _A Game of Surface Codes: Large-Scale Quantum Computing with Lattice Surgery_, [arXiv:1808.02892](https://arxiv.org/abs/1808.02892)\n" ] @@ -502,13 +509,13 @@ }, "source": [ "## Error suppression\n", - "Error suppression is the most basic level of error handling. It often refers to a set of techniques performed close to hardware, such as altering control signals (i.e. Qiskit Pulse level). To make it simpler, we define these techniques as introducing _classical overhead_, usually within the transpilation/compilation process.\n", + "Error suppression is the most basic level of error handling. It often refers to a set of techniques performed close to hardware, such as altering control signals (that is, at Qiskit Pulse level). To make it simpler, we define these techniques as introducing _classical overhead_, usually within the transpilation/compilation process.\n", "\n", "These techniques are very old and were first developed outside of the field at the same time as some of the first controllable quantum systems such as magnetic resonance imaging devices.\n", "\n", "\n", "### Dynamical decoupling (DD)\n", - "Quantum computers have adopted some of these techniques like spin echos (a sequence of pulses that can help refocus the state of a qubit). As a matter of fact, spin echos play a big role in a class of techniques known as _Dynamical Decoupling_ (DD), which sends pulses to idle qubits in order to reset their value to their original states, undoing the potentially harmful effects of nearby qubits that are being used for the calculation.\n", + "Quantum computers have adopted some of these techniques like spin echos (a sequence of pulses that can help refocus the state of a qubit). As a matter of fact, spin echos play a big role in a class of techniques known as _Dynamical Decoupling_ (DD), which sends pulses to idle qubits to reset their value to their original states, undoing the potentially harmful effects of nearby qubits that are being used for the calculation.\n", "\n", "__Reference__: Lorenza Viola, and Seth Lloyd , _Dynamical suppression of decoherence in two-state quantum systems_, [arXiv:quant-ph/9803057](https://arxiv.org/abs/quant-ph/9803057)" ] @@ -535,17 +542,19 @@ "source": [ "options = Options()\n", "options.execution.shots = 1000\n", - "options.optimization_level = 3 # Dynamical decoupling\n", - "options.resilience_level = 0 # No error mitigation\n", + "options.optimization_level = 3 # Dynamical decoupling\n", + "options.resilience_level = 0 # No error mitigation\n", "\n", "with Session(service=service, backend=backend) as session:\n", " estimator = Estimator(session=session, options=options)\n", " job_dd = estimator.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_dd.job_id)\n", + " print(\"job id:\", job_dd.job_id)\n", " print(job_dd.result())\n", "\n", "expvals_unmit_dd = job_dd.result().values\n", - "expvals_unmit_dd_variance = [metadata['variance']/metadata['shots'] for metadata in job_dd.result().metadata]\n", + "expvals_unmit_dd_variance = [\n", + " metadata[\"variance\"] / metadata[\"shots\"] for metadata in job_dd.result().metadata\n", + "]\n", "std_error_dd = np.sqrt(expvals_unmit_dd_variance)" ] }, @@ -576,13 +585,40 @@ } ], "source": [ - "plt.title('Trotter circuits expectation value')\n", - "plt.errorbar(range(1, num_steps), expvals_ideal, std_error_ideal, fmt = 'o', linestyle = '--', capsize=4, c='red', label='Ideal')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit, std_error_unmit, fmt = 'o', linestyle = '-', capsize=4, c='green', label='No mitigation')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit_dd, std_error_dd, fmt = 'o', linestyle = '-', capsize=4, c='blue', label='Dynamical decoupling')\n", + "plt.title(\"Trotter circuits expectation value\")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_ideal,\n", + " std_error_ideal,\n", + " fmt=\"o\",\n", + " linestyle=\"--\",\n", + " capsize=4,\n", + " c=\"red\",\n", + " label=\"Ideal\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit,\n", + " std_error_unmit,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"green\",\n", + " label=\"No mitigation\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit_dd,\n", + " std_error_dd,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"blue\",\n", + " label=\"Dynamical decoupling\",\n", + ")\n", "\n", "plt.ylabel(f\"$\\langle ZZZZ \\\\rangle$\")\n", - "plt.xlabel('No. Trotter Steps')\n", + "plt.xlabel(\"No. Trotter Steps\")\n", "plt.xticks([1, 2, 3, 4, 5])\n", "plt.legend()\n", "plt.show()" @@ -601,7 +637,7 @@ "## Error mitigation\n", "Error mitigation introduces _quantum overhead_ to our calculations.\n", "\n", - "Typically, error correction uses the outputs of multiple ensembles of noisy calculations to reduce or eliminate the noise in estimating quantities like expectation values — commonly by using classical post-processing. In this regard, error mitigation is different from error correction. Instead of fixing errors in every circuit run, errors are allowed to occur, then better results are inferred from several of these noisy calculations. " + "Typically, error correction uses the outputs of multiple ensembles of noisy calculations to reduce or eliminate the noise in estimating quantities like expectation values — commonly by using classical post-processing. In this regard, error mitigation is different from error correction. Rather than fixing errors in every circuit run, errors are allowed to occur, then better results are inferred from several of these noisy calculations. " ] }, { @@ -613,7 +649,7 @@ } }, "source": [ - "Since there is no threshold that one must surpass before QEM becomes practical, we see error mitigation as the key to realizing useful quantum computers in the near term.\n", + "Since there is no threshold that one must surpass before quantum error mitigation becomes practical, we see error mitigation as the key to realizing useful quantum computers in the near term.\n", "\n", "We are developing a portfolio of different error mitigation techniques, looking for three main things:\n", "\n", @@ -750,8 +786,8 @@ "Twirled readout error extinction (T-REx) uses a technique known as Pauli twirling to reduce the noise introduced during the process of quantum measurement. This technique assumes no specific form of noise, which makes it very general and effective.\n", "\n", "#### Overall workflow\n", - "1. Acquire data for the zero state with randomized bit flips (i.e. Pauli X before measurement)\n", - "2. Acquire data for the desired (noisy) state with randomized bit flips (i.e. Pauli X before measurement)\n", + "1. Acquire data for the zero state with randomized bit flips (Pauli X before measurement)\n", + "2. Acquire data for the desired (noisy) state with randomized bit flips (Pauli X before measurement)\n", "3. Compute the special function for each data set, and divide.\n", "\n", "
\n", @@ -783,18 +819,20 @@ ], "source": [ "options = Options()\n", - "options.resilience_level = 1 # T-REx\n", - "options.optimization_level = 0 # No optimization\n", + "options.resilience_level = 1 # T-REx\n", + "options.optimization_level = 0 # No optimization\n", "options.execution.shots = 1000\n", "\n", "with Session(service=service, backend=backend) as session:\n", " estimator = Estimator(session=session, options=options)\n", " job_trex = estimator.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_trex.job_id)\n", + " print(\"job id:\", job_trex.job_id)\n", " print(job_trex.result())\n", "\n", "expvals_unmit_trex = job_trex.result().values\n", - "expvals_unmit_trex_variance = [metadata['variance']/metadata['shots'] for metadata in job_trex.result().metadata]\n", + "expvals_unmit_trex_variance = [\n", + " metadata[\"variance\"] / metadata[\"shots\"] for metadata in job_trex.result().metadata\n", + "]\n", "std_error_trex = np.sqrt(expvals_unmit_trex_variance)" ] }, @@ -825,13 +863,40 @@ } ], "source": [ - "plt.title('Trotter circuits expectation value')\n", - "plt.errorbar(range(1, num_steps), expvals_ideal, std_error_ideal, fmt = 'o', linestyle = '--', capsize=4, c='red', label='Ideal')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit, std_error_unmit, fmt = 'o', linestyle = '-', capsize=4, c='green', label='No mitigation')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit_trex, std_error_trex, fmt = 'o', linestyle = '-', capsize=4, c='violet', label='T-REx')\n", + "plt.title(\"Trotter circuits expectation value\")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_ideal,\n", + " std_error_ideal,\n", + " fmt=\"o\",\n", + " linestyle=\"--\",\n", + " capsize=4,\n", + " c=\"red\",\n", + " label=\"Ideal\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit,\n", + " std_error_unmit,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"green\",\n", + " label=\"No mitigation\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit_trex,\n", + " std_error_trex,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"violet\",\n", + " label=\"T-REx\",\n", + ")\n", "\n", "plt.ylabel(f\"$\\langle ZZZZ \\\\rangle$\")\n", - "plt.xlabel('No. Trotter Steps')\n", + "plt.xlabel(\"No. Trotter Steps\")\n", "plt.xticks([1, 2, 3, 4, 5])\n", "plt.legend()\n", "plt.show()" @@ -882,17 +947,17 @@ "source": [ "options = Options()\n", "options.execution.shots = 1000\n", - "options.optimization_level = 0 # No optimization\n", - "options.resilience_level = 2 # ZNE\n", + "options.optimization_level = 0 # No optimization\n", + "options.resilience_level = 2 # ZNE\n", "\n", "with Session(service=service, backend=backend) as session:\n", " estimator = Estimator(session=session, options=options)\n", " job_zne = estimator.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_zne.job_id)\n", + " print(\"job id:\", job_zne.job_id)\n", " print(job_zne.result())\n", "\n", "expvals_unmit_zne = job_zne.result().values\n", - "# Standard error: coming soon!\n" + "# Standard error: coming soon!" ] }, { @@ -922,12 +987,39 @@ } ], "source": [ - "plt.title('Trotter circuits expectation value')\n", - "plt.errorbar(range(1, num_steps), expvals_ideal, std_error_ideal, fmt = 'o', linestyle = '--', capsize=4, c='red', label='Ideal')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit, std_error_unmit, fmt = 'o', linestyle = '-', capsize=4, c='green', label='No mitigation')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit_zne, [0]*(num_steps-1), fmt = 'o', linestyle = '-', capsize=4, c='cyan', label='ZNE')\n", - "\n", - "plt.xlabel('No. Trotter Steps')\n", + "plt.title(\"Trotter circuits expectation value\")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_ideal,\n", + " std_error_ideal,\n", + " fmt=\"o\",\n", + " linestyle=\"--\",\n", + " capsize=4,\n", + " c=\"red\",\n", + " label=\"Ideal\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit,\n", + " std_error_unmit,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"green\",\n", + " label=\"No mitigation\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit_zne,\n", + " [0] * (num_steps - 1),\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"cyan\",\n", + " label=\"ZNE\",\n", + ")\n", + "\n", + "plt.xlabel(\"No. Trotter Steps\")\n", "plt.ylabel(f\"$\\langle ZZZZ \\\\rangle$\")\n", "plt.xticks([1, 2, 3, 4, 5])\n", "plt.legend()\n", @@ -944,7 +1036,7 @@ }, "source": [ "### Probabilistic error cancellation\n", - "Probabilistic error cancellation (PEC) samples for a collection of circuits that, on average mimics a noise inverting channel to cancel out the noise in the desired computation. This process is a bit like how noise-cancelling headphones work, and produces great results, however it is not as general as other methods, and the sampling overhead is exponential.\n", + "Probabilistic error cancellation (PEC) samples for a collection of circuits that, on average mimics a noise inverting channel to cancel out the noise in the desired computation. This process is a bit like how noise-cancelling headphones work, and produces great results; however, it is not as general as other methods, and the sampling overhead is exponential.\n", "\n", "__Reference__: E. van den Berg, Z. Minev, A. Kandala, and K. Temme, _Probabilistic error cancellation with sparse Pauli-Lindblad models on noisy quantum processors_ [arXiv:2201.09866](https://arxiv.org/abs/2201.09866)\n", "\n", @@ -1035,19 +1127,20 @@ " now = datetime.datetime.now()\n", " print(now, \"*** Callback ***\", result, \"\\n\")\n", "\n", + "\n", "options = Options()\n", - "options.optimization_level = 0 # No optimization\n", + "options.optimization_level = 0 # No optimization\n", "options.execution.shots = 100\n", - "options.resilience_level = 3 # PEC\n", + "options.resilience_level = 3 # PEC\n", "options.environment.callback = interim_results_callback\n", "\n", "with Session(service=service, backend=backend) as session:\n", " estimator_pec = Estimator(session=session, options=options)\n", " job_pec = estimator_pec.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_pec.job_id)\n", + " print(\"job id:\", job_pec.job_id)\n", "\n", "expvals_pec = job_pec.result().values\n", - "std_error_pec = [metadata['standard_error'] for metadata in job_pec.result().metadata]\n" + "std_error_pec = [metadata[\"standard_error\"] for metadata in job_pec.result().metadata]" ] }, { @@ -1077,13 +1170,40 @@ } ], "source": [ - "plt.title('Trotter circuits expectation value')\n", - "plt.errorbar(range(1, num_steps), expvals_ideal, std_error_ideal, fmt = 'o', linestyle = '--', capsize=4, c='red', label='Ideal')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit, std_error_unmit, fmt = 'o', linestyle = '-', capsize=4, c='green', label='No mitigation')\n", - "plt.errorbar(range(1, num_steps), expvals_pec, std_error_pec, fmt = 'd', linestyle = '-', capsize=4, c='orange', label='PEC')\n", + "plt.title(\"Trotter circuits expectation value\")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_ideal,\n", + " std_error_ideal,\n", + " fmt=\"o\",\n", + " linestyle=\"--\",\n", + " capsize=4,\n", + " c=\"red\",\n", + " label=\"Ideal\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit,\n", + " std_error_unmit,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"green\",\n", + " label=\"No mitigation\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_pec,\n", + " std_error_pec,\n", + " fmt=\"d\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"orange\",\n", + " label=\"PEC\",\n", + ")\n", "\n", "plt.ylabel(f\"$\\langle ZZZZ \\\\rangle$\")\n", - "plt.xlabel('No. Trotter Steps')\n", + "plt.xlabel(\"No. Trotter Steps\")\n", "plt.xticks([1, 2, 3, 4, 5])\n", "plt.legend()\n", "plt.show()" @@ -1325,10 +1445,24 @@ "twin2.spines.right.set_position((\"axes\", 1.2))\n", "twin3.spines.right.set_position((\"axes\", 1.4))\n", "\n", - "p1, = ax.plot(range(1, num_steps), [m[\"total_mitigated_layers\"] for m in pec_metadata] , \"b-\", label=\"Total mitigated layers\")\n", - "p2, = twin1.plot(range(1, num_steps), [m[\"sampling_overhead\"] for m in pec_metadata], \"r-\", label=\"Sampling overhead\")\n", - "p3, = twin2.plot(range(1, num_steps), [m[\"samples\"] for m in pec_metadata], \"g-\", label=\"Samples\")\n", - "p4, = twin3.plot(range(1, num_steps), [m[\"shots\"] for m in pec_metadata], \"c-\", label=\"Shots\")\n", + "(p1,) = ax.plot(\n", + " range(1, num_steps),\n", + " [m[\"total_mitigated_layers\"] for m in pec_metadata],\n", + " \"b-\",\n", + " label=\"Total mitigated layers\",\n", + ")\n", + "(p2,) = twin1.plot(\n", + " range(1, num_steps),\n", + " [m[\"sampling_overhead\"] for m in pec_metadata],\n", + " \"r-\",\n", + " label=\"Sampling overhead\",\n", + ")\n", + "(p3,) = twin2.plot(\n", + " range(1, num_steps), [m[\"samples\"] for m in pec_metadata], \"g-\", label=\"Samples\"\n", + ")\n", + "(p4,) = twin3.plot(\n", + " range(1, num_steps), [m[\"shots\"] for m in pec_metadata], \"c-\", label=\"Shots\"\n", + ")\n", "\n", "ax.set_ylim(0, 20)\n", "twin1.set_ylim(0, 2.8)\n", @@ -1347,15 +1481,15 @@ "twin3.yaxis.label.set_color(p4.get_color())\n", "\n", "tkw = dict(size=4, width=1.5)\n", - "ax.tick_params(axis='y', colors=p1.get_color(), **tkw)\n", - "twin1.tick_params(axis='y', colors=p2.get_color(), **tkw)\n", - "twin2.tick_params(axis='y', colors=p3.get_color(), **tkw)\n", - "twin3.tick_params(axis='y', colors=p4.get_color(), **tkw)\n", + "ax.tick_params(axis=\"y\", colors=p1.get_color(), **tkw)\n", + "twin1.tick_params(axis=\"y\", colors=p2.get_color(), **tkw)\n", + "twin2.tick_params(axis=\"y\", colors=p3.get_color(), **tkw)\n", + "twin3.tick_params(axis=\"y\", colors=p4.get_color(), **tkw)\n", "plt.xticks([1, 2, 3, 4, 5])\n", "\n", "ax.legend(handles=[p1, p2, p3, p4])\n", "\n", - "plt.title('PEC metadata')\n", + "plt.title(\"PEC metadata\")\n", "plt.show()" ] }, @@ -1399,15 +1533,61 @@ ], "source": [ "from matplotlib.pyplot import figure\n", - "plt.errorbar(range(1, num_steps), expvals_ideal, std_error_ideal, fmt = 'o', linestyle = '--', capsize=4, c='red', label='Ideal')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit, std_error_unmit, fmt = 'o', linestyle = '-', capsize=4, c='green', label='No mitigation')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit_trex, std_error_trex, fmt = 'o', linestyle = '-', capsize=4, c='violet', label='T-REx')\n", - "plt.errorbar(range(1, num_steps), expvals_unmit_zne, [0]*(num_steps-1), fmt = 'o', linestyle = '-', capsize=4, c='cyan', label='ZNE')\n", - "plt.errorbar(range(1, num_steps), expvals_pec, std_error_pec, fmt = 'd', linestyle = '-', capsize=4, c='orange', label='PEC')\n", "\n", - "plt.title('Trotter circuits expectation value')\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_ideal,\n", + " std_error_ideal,\n", + " fmt=\"o\",\n", + " linestyle=\"--\",\n", + " capsize=4,\n", + " c=\"red\",\n", + " label=\"Ideal\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit,\n", + " std_error_unmit,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"green\",\n", + " label=\"No mitigation\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit_trex,\n", + " std_error_trex,\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"violet\",\n", + " label=\"T-REx\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_unmit_zne,\n", + " [0] * (num_steps - 1),\n", + " fmt=\"o\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"cyan\",\n", + " label=\"ZNE\",\n", + ")\n", + "plt.errorbar(\n", + " range(1, num_steps),\n", + " expvals_pec,\n", + " std_error_pec,\n", + " fmt=\"d\",\n", + " linestyle=\"-\",\n", + " capsize=4,\n", + " c=\"orange\",\n", + " label=\"PEC\",\n", + ")\n", + "\n", + "plt.title(\"Trotter circuits expectation value\")\n", "plt.ylabel(f\"$\\langle ZZZZ \\\\rangle$\")\n", - "plt.xlabel('No. Trotter Steps')\n", + "plt.xlabel(\"No. Trotter Steps\")\n", "plt.xticks([1, 2, 3, 4, 5])\n", "plt.legend()\n", "plt.show()" @@ -1514,16 +1694,16 @@ "source": [ "options = Options()\n", "options.execution.shots = 1000\n", - "options.optimization_level = 0 # no optimization\n", - "options.resilience_level = 2 # ZNE\n", + "options.optimization_level = 0 # no optimization\n", + "options.resilience_level = 2 # ZNE\n", "options.resilience.noise_factors = [1, 2, 3, 4]\n", "options.resilience.noise_amplifier = \"LocalFoldingAmplifier\"\n", "options.resilience.extrapolator = \"QuadraticExtrapolator\"\n", "\n", - "with Session(service=service, backend='ibmq_montreal') as session:\n", + "with Session(service=service, backend=\"ibmq_montreal\") as session:\n", " estimator = Estimator(session=session, options=options)\n", " job_zne_options = estimator.run(circuits=trotter_circuit_list, observables=obs_list)\n", - " print('job id:', job_zne_options.job_id)\n", + " print(\"job id:\", job_zne_options.job_id)\n", " print(job_zne_options.result())" ] }, @@ -1758,6 +1938,7 @@ ], "source": [ "from qiskit.tools import jupyter\n", + "\n", "%qiskit_version_table\n", "%qiskit_copyright" ] diff --git a/docs/tutorials/chsh_with_estimator.ipynb b/docs/tutorials/chsh_with_estimator.ipynb index eef92bdbd..c4b44f9ae 100644 --- a/docs/tutorials/chsh_with_estimator.ipynb +++ b/docs/tutorials/chsh_with_estimator.ipynb @@ -5,6 +5,8 @@ "id": "bf7f865a", "metadata": {}, "source": [ + "\n", + "\n", "# Demonstrate the violation of the CHSH inequality with the Estimator primitive" ] }, @@ -33,7 +35,7 @@ "id": "98fa28f0", "metadata": {}, "source": [ - "## Background Information" + "## Background information" ] }, { @@ -41,7 +43,7 @@ "id": "36669708", "metadata": {}, "source": [ - "### CHSH Inequality\n", + "### CHSH inequality\n", "\n", "The CHSH inequality, named after the authors Clauser, Horne, Shimony, and Holt, is used to experimentally prove Bell's theorem. This theorem asserts that local hidden variable theories cannot account for some consequences of entanglement in quantum mechanics. \n", "\n", @@ -65,7 +67,7 @@ "\n", "$$|\\langle S_2 \\rangle| = |\\langle AB \\rangle + \\langle Ab \\rangle - \\langle aB \\rangle + \\langle ab \\rangle| \\leq 2$$\n", "\n", - "If quantum mechanics can be described by local hidden variable theories, the above inequalities must hold true. However, as you are going to demonstrate in this notebook, these inequalities can be violated in a quantum computer. Therefore, quantum mechanics is not compatible with local hidden variable theories.\n", + "If quantum mechanics can be described by local hidden variable theories, the previous inequalities must hold true. However, as you are going to demonstrate in this notebook, these inequalities can be violated in a quantum computer. Therefore, quantum mechanics is not compatible with local hidden variable theories.\n", "\n", "If you want to learn more, you can read the chapter about the CHSH inequality in [the Qiskit textbook](https://qiskit.org/textbook/ch-demos/chsh.html).\n", "\n" @@ -80,14 +82,14 @@ "\n", "You will create an entangled pair between two qubits in a quantum computer by creating the Bell state $|\\Phi^+\\rangle = \\frac{|00\\rangle + |11\\rangle}{\\sqrt{2}}$. Using the Estimator primitive, you can directly obtain the expectation values needed ($\\langle AB \\rangle, \\langle Ab \\rangle, \\langle aB \\rangle$, and $\\langle ab \\rangle$) to calculate the expectation values of the two CHSH quantities $\\langle S_1\\rangle$ and $\\langle S_2\\rangle$. Before the introduction of the Estimator primitive, you would have to construct the expectation values from the measurement outcomes.\n", "\n", - "You will measure the second qubit in the $Z$ and $X$ bases. The first qubit will be measured also in orthogonal bases, but with an angle with respect to the second qubit, which we are going to sweep between $0$ and $2\\pi$. As you will see, the Estimator primitive makes running parameterized circuits very easy. Instead of creating a series of CHSH circuits, you only need to create *one* CHSH circuit with a parameter specifying the measurement angle and a series of phase values for the parameter.\n", + "You will measure the second qubit in the $Z$ and $X$ bases. The first qubit will be measured also in orthogonal bases, but with an angle with respect to the second qubit, which we are going to sweep between $0$ and $2\\pi$. As you will see, the Estimator primitive makes running parameterized circuits very easy. Rather than creating a series of CHSH circuits, you only need to create *one* CHSH circuit with a parameter specifying the measurement angle and a series of phase values for the parameter.\n", "\n", "Finally, you will analyze the results and plot them against the measurement angle. You will see that for certain range of measurement angles, the expectation values of CHSH quantities $|\\langle S_1\\rangle| > 2$ or $|\\langle S_2\\rangle| > 2$, which demonstrates the violation of the CHSH inequality.\n", "\n", "
\n", "Note\n", "\n", - "For experts users out there, we need to confess that there are a number of loopholes that have to be closed when violating the inequality in order to claim that either locality or realism have been disproven. Please read the last paragraph (right above \"Exercise\" section) in the CHSH chapter in [the Qiskit textbook](https://qiskit.org/textbook/ch-demos/chsh.html) for discussions.\n", + "For expert users out there, we should mention there are several loopholes that must be closed when violating the inequality to claim that either locality or realism have been disproven. See the last paragraph (right before the \"Exercise\" section) in the CHSH chapter in [the Qiskit textbook](https://qiskit.org/textbook/ch-demos/chsh.html) for discussions.\n", "\n", "
" ] @@ -132,13 +134,13 @@ "from qiskit.circuit import Parameter\n", "from qiskit import QuantumCircuit\n", "\n", - "theta = Parameter('$\\\\theta$')\n", + "theta = Parameter(\"$\\\\theta$\")\n", "\n", "chsh_circuits_no_meas = QuantumCircuit(2)\n", "chsh_circuits_no_meas.h(0)\n", "chsh_circuits_no_meas.cx(0, 1)\n", "chsh_circuits_no_meas.ry(theta, 0)\n", - "chsh_circuits_no_meas.draw('mpl')" + "chsh_circuits_no_meas.draw(\"mpl\")" ] }, { @@ -148,7 +150,7 @@ "source": [ "### Create a list of phase values to be assigned later\n", "\n", - "After creating the parameterized CHSH circuit, you will create a list of phase values to be assigned to the circuit in the next step. You can use the code below to create a list of 21 phase values range from $0$ to $2 \\pi$ with equal spacing, i.e. $0$, $0.1 \\pi$, $0.2 \\pi$, ..., $1.9 \\pi$, $2 \\pi$." + "After creating the parameterized CHSH circuit, you will create a list of phase values to be assigned to the circuit in the next step. You can use the following code to create a list of 21 phase values range from $0$ to $2 \\pi$ with equal spacing, that is, $0$, $0.1 \\pi$, $0.2 \\pi$, ..., $1.9 \\pi$, $2 \\pi$." ] }, { @@ -161,7 +163,7 @@ "import numpy as np\n", "\n", "number_of_phases = 21\n", - "phases = np.linspace(0, 2*np.pi, number_of_phases)\n", + "phases = np.linspace(0, 2 * np.pi, number_of_phases)\n", "# Phases need to be expressed as list of lists in order to work\n", "individual_phases = [[ph] for ph in phases]" ] @@ -231,9 +233,10 @@ " estimator = Estimator()\n", " for op in ops:\n", " job = estimator.run(\n", - " circuits=[chsh_circuits_no_meas]*len(individual_phases),\n", - " observables=[op]*len(individual_phases),\n", - " parameter_values=individual_phases)\n", + " circuits=[chsh_circuits_no_meas] * len(individual_phases),\n", + " observables=[op] * len(individual_phases),\n", + " parameter_values=individual_phases,\n", + " )\n", " est_result = job.result()\n", " chsh_est_sim.append(est_result)" ] @@ -245,7 +248,7 @@ "source": [ "## Step 3: Analyze the results\n", "\n", - "After running the circuits, we need to build the CHSH witness functions. We first build the quantities $\\langle AB \\rangle$, $\\langle Ab \\rangle$, $\\langle aB \\rangle$, and $\\langle ab \\rangle$, by looking at the parity of the outcomes for the four families of circuits we built (two measurement bases for each of the two qubits). Then we use those quantities to build the witness functions as defined above." + "After running the circuits, we need to build the CHSH witness functions. We first build the quantities $\\langle AB \\rangle$, $\\langle Ab \\rangle$, $\\langle aB \\rangle$, and $\\langle ab \\rangle$, by looking at the parity of the outcomes for the four families of circuits we built (two measurement bases for each of the two qubits). Then we use those quantities to build the witness functions as defined previously." ] }, { @@ -256,10 +259,20 @@ "outputs": [], "source": [ "# = - + + \n", - "chsh1_est_sim = chsh_est_sim[0].values - chsh_est_sim[1].values + chsh_est_sim[2].values + chsh_est_sim[3].values\n", + "chsh1_est_sim = (\n", + " chsh_est_sim[0].values\n", + " - chsh_est_sim[1].values\n", + " + chsh_est_sim[2].values\n", + " + chsh_est_sim[3].values\n", + ")\n", "\n", "# = + - + \n", - "chsh2_est_sim = chsh_est_sim[0].values + chsh_est_sim[1].values - chsh_est_sim[2].values + chsh_est_sim[3].values" + "chsh2_est_sim = (\n", + " chsh_est_sim[0].values\n", + " + chsh_est_sim[1].values\n", + " - chsh_est_sim[2].values\n", + " + chsh_est_sim[3].values\n", + ")" ] }, { @@ -305,21 +318,21 @@ "\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "# results from a simulator\n", - "ax.plot(phases/np.pi, chsh1_est_sim, 'o-', label='CHSH1 Simulation')\n", - "ax.plot(phases/np.pi, chsh2_est_sim, 'o-', label='CHSH2 Simulation')\n", + "ax.plot(phases / np.pi, chsh1_est_sim, \"o-\", label=\"CHSH1 Simulation\")\n", + "ax.plot(phases / np.pi, chsh2_est_sim, \"o-\", label=\"CHSH2 Simulation\")\n", "# classical bound +-2\n", - "ax.axhline(y=2, color='r', linestyle='--')\n", - "ax.axhline(y=-2, color='r', linestyle='--')\n", + "ax.axhline(y=2, color=\"r\", linestyle=\"--\")\n", + "ax.axhline(y=-2, color=\"r\", linestyle=\"--\")\n", "# quantum bound, +-2√2\n", - "ax.axhline(y=np.sqrt(2)*2, color='b', linestyle='-.')\n", - "ax.axhline(y=-np.sqrt(2)*2, color='b', linestyle='-.')\n", + "ax.axhline(y=np.sqrt(2) * 2, color=\"b\", linestyle=\"-.\")\n", + "ax.axhline(y=-np.sqrt(2) * 2, color=\"b\", linestyle=\"-.\")\n", "# set x tick labels to the unit of pi\n", - "ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\\pi$'))\n", + "ax.xaxis.set_major_formatter(tck.FormatStrFormatter(\"%g $\\pi$\"))\n", "ax.xaxis.set_major_locator(tck.MultipleLocator(base=0.5))\n", "# set title, labels, and legend\n", - "plt.title('Violation of CHSH Inequality')\n", - "plt.xlabel('Theta')\n", - "plt.ylabel('CHSH witness')\n", + "plt.title(\"Violation of CHSH Inequality\")\n", + "plt.xlabel(\"Theta\")\n", + "plt.ylabel(\"CHSH witness\")\n", "plt.legend()" ] }, @@ -328,7 +341,7 @@ "id": "63e63853", "metadata": {}, "source": [ - "In the figure above, the red dashed lines delimit the classical bounds ($\\pm 2$) and the dash-dotted blue lines delimit the quantum bounds ($\\pm 2\\sqrt{2}$). You can see that the experimental results resemble the general trend of the simulated results and there are regions where the CHSH witness quantities exceeds the classical bounds. Congratulations! You have successfully demonstrated the violation of CHSH inequality in a real quantum system!" + "In the figure, the red dashed lines delimit the classical bounds ($\\pm 2$) and the dash-dotted blue lines delimit the quantum bounds ($\\pm 2\\sqrt{2}$). You can see that the experimental results resemble the general trend of the simulated results and there are regions where the CHSH witness quantities exceeds the classical bounds. Congratulations! You have successfully demonstrated the violation of CHSH inequality in a real quantum system!" ] }, { @@ -378,6 +391,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, diff --git a/docs/tutorials/grover_with_sampler.ipynb b/docs/tutorials/grover_with_sampler.ipynb index f0dfa9f31..6d509848e 100644 --- a/docs/tutorials/grover_with_sampler.ipynb +++ b/docs/tutorials/grover_with_sampler.ipynb @@ -17,7 +17,7 @@ "source": [ "## Before you begin\n", "\n", - "This tutorial requires a Qiskit Runtime service instance. If you haven't done so already, please follow the [Getting Started Guide](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/getting_started.html) to set one up." + "This tutorial requires a Qiskit Runtime service instance. If you haven't done so already, follow the [Getting started guide](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/getting_started.html) to set one up." ] }, { @@ -29,7 +29,7 @@ "\n", "### Unstructured search problem\n", "\n", - "In the olden days, you looked up a person's phone number in a phone book. That is an easy task if you know the person's name because a phone book is ordered alphabetically by name. However, the opposite task, that is, you are given a phone number and want to find out who it belongs to, is much more difficult. That is because a phone book is not ordered by phone numbers. This is an example of an unstructured search problem. To solve this problem with a classical computer, your best trick is to randomly pick an entry. On average, you will need to look up half of the entries ($N/2$, if $N$ is the total number of entries) to find the owner. If you have a quantum computer, however, you can use Grover's algorithm to find the owner in $\\sqrt N$ tries. That means to identify the owner in a phone book that has 1 million numbers, you only need to do 1000 tries instead of 500,000!\n", + "In the olden days, you looked up a person's phone number in a phone book. That is an easy task if you know the person's name because a phone book is ordered alphabetically by name. However, the opposite task, that is, you are given a phone number and want to find out who it belongs to, is much more difficult. That is because a phone book is not ordered by phone numbers. This is an example of an unstructured search problem. To solve this problem with a classical computer, your best trick is to randomly pick an entry. On average, you will need to look up half of the entries ($N/2$, if $N$ is the total number of entries) to find the owner. If you have a quantum computer, however, you can use Grover's algorithm to find the owner in $\\sqrt N$ tries. That means to identify the owner in a phone book that has 1 million numbers, you only need to access 1000 entries, rather than 500,000!\n", "\n", "### Grover's algorithm\n", "\n", @@ -83,8 +83,8 @@ "import random\n", "from qiskit.quantum_info import Statevector\n", "\n", - "secret = random.randint(0,7) # the owner is randomly picked\n", - "secret_string = format(secret, '03b') # format the owner in 3-bit string\n", + "secret = random.randint(0, 7) # the owner is randomly picked\n", + "secret_string = format(secret, \"03b\") # format the owner in 3-bit string\n", "oracle = Statevector.from_label(secret_string) # let the oracle know the owner" ] }, @@ -146,7 +146,7 @@ "from qiskit.algorithms import Grover\n", "\n", "grover_circuits = []\n", - "for iteration in range(1,3):\n", + "for iteration in range(1, 3):\n", " grover = Grover(iterations=iteration)\n", " circuit = grover.construct_circuit(problem)\n", " circuit.measure_all()\n", @@ -281,7 +281,7 @@ "id": "17d8307f-f3ff-4371-9286-611def049a8b", "metadata": {}, "source": [ - "Grover's algorithm determines the correct answer based on the highest probability of measurement outcomes. The `Sampler` primitive program is perfect for getting probabilities, so you will use that. In the cell below, you create an instance of the `Sampler` program, and start a Runtime session using the context manager (`with ...:`), which automatically opens and closes the session for you. \n", + "Grover's algorithm determines the correct answer based on the highest probability of measurement outcomes. The `Sampler` primitive program is perfect for getting probabilities, so you will use that. In the following cell, you create an instance of the `Sampler` program, and start a Runtime session using the context manager (`with ...:`), which automatically opens and closes the session for you. \n", "\n", "The `Sampler` program allows a batch submission of circuits in a job. Here you are passing a list of two circuits (Grover with 1 iteration and 2 iterations) to the Sampler but only one call is needed to sample the probability of measurement outcomes of both circuits." ] @@ -370,12 +370,13 @@ "# Extract bit string with highest probability from results as the answer\n", "result_dict = result.quasi_dists[1].binary_probabilities()\n", "answer = max(result_dict, key=result_dict.get)\n", - "print(f\"As you can see, the quantum computer returned '{answer}' as the answer with highest probability.\\n\"\n", - " \"And the results with 2 iterations have higher probability than the results with 1 iteration.\"\n", + "print(\n", + " f\"As you can see, the quantum computer returned '{answer}' as the answer with highest probability.\\n\"\n", + " \"And the results with 2 iterations have higher probability than the results with 1 iteration.\"\n", ")\n", "\n", "# Plot the results\n", - "plot_histogram(result.quasi_dists, legend=['1 iteration', '2 iterations'])" + "plot_histogram(result.quasi_dists, legend=[\"1 iteration\", \"2 iterations\"])" ] }, { @@ -415,7 +416,7 @@ "# Print the results and the correct answer.\n", "print(f\"Quantum answer: {answer}\")\n", "print(f\"Correct answer: {secret_string}\")\n", - "print('Success!' if answer == secret_string else 'Failure!')" + "print(\"Success!\" if answer == secret_string else \"Failure!\")" ] }, { @@ -435,7 +436,7 @@ "source": [ "## Summary\n", "\n", - "In this tutorial, you have solved a small database search problem using a quantum computer. You have constructed Grover's circuits by defining a phone book search problem using the `AmplificationProblem` class in Qiskit and then submitted the circuits to run using the Sampler primitive program via Qiskit Runtime service. " + "In this tutorial, you have solved a small database search problem using a quantum computer. You have constructed Grover's circuits by defining a phone book search problem using the `AmplificationProblem` class in Qiskit and then submitted the circuits to run using the Sampler primitive program through Qiskit Runtime service. " ] }, { @@ -484,6 +485,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, diff --git a/docs/tutorials/how-to-getting-started-with-estimator.ipynb b/docs/tutorials/how-to-getting-started-with-estimator.ipynb index 9a11bf7ad..eaa36163b 100644 --- a/docs/tutorials/how-to-getting-started-with-estimator.ipynb +++ b/docs/tutorials/how-to-getting-started-with-estimator.ipynb @@ -47,7 +47,7 @@ "source": [ "Primitives are core functions that make it easier to build modular algorithms and applications. \n", "\n", - "Instead of simply returning counts, they return more immediately meaningful information. \n", + "Rather than simply returning counts, they return more immediately meaningful information. \n", "\n", "Additionally, they provide a seamless way to access the latest advancements in IBM Quantum hardware and software." ] @@ -104,7 +104,7 @@ "Similar to the `Backend` base class, there is an `Estimator` base class defined in Qiskit Terra that standardizes the way users interact with all `Estimator` implementations.\n", "This allows users to easily change their choice of simulator or device for performing expectation value calculations, even if the underlying implementation is different. \n", "\n", - "In this section we will be using the default implementation in Qiskit Terra, which uses a local statevector simulator." + "In this section we will be using the default implementation in Qiskit Terra, which uses a local state vector simulator." ] }, { @@ -180,7 +180,7 @@ } }, "source": [ - "You will also need at least one observable to measure. Observables represent physical properties of a quantum system (e.g. energy, spin), and allow said properties to be measured (e.g. their expectation values) for a given state of our system. For simplicity, you can use the [PauliSumOp class](https://qiskit.org/documentation/stubs/qiskit.opflow.primitive_ops.html#module-qiskit.opflow.primitive_ops) in Qiskit to define them, as illustrated in the example below." + "You will also need at least one observable to measure. Observables represent physical properties of a quantum system (such as energy or spin), and allow said properties to be measured (such as their expectation values) for a given state of our system. For simplicity, you can use the [PauliSumOp class](https://qiskit.org/documentation/stubs/qiskit.opflow.primitive_ops.html#module-qiskit.opflow.primitive_ops) in Qiskit to define them, as illustrated in the following example." ] }, { @@ -229,7 +229,9 @@ } }, "source": [ - "The next step is to create an instance of an `Estimator` class. This can be any `Estimator` class that complies with the `Estimator` primitive specification. For simplicity, we will use Qiskit Terra's `qiskit.primitives.Estimator` class, based on the [Statevector construct](https://qiskit.org/documentation/stubs/qiskit.quantum_info.Statevector.html?highlight=statevector#qiskit.quantum_info.Statevector) (i.e. algebraic simulation)." + "\n", + "The next step is to create an instance of an `Estimator` class. This can be any `Estimator` class that complies with the `Estimator` primitive specification. For simplicity, we will use Qiskit Terra's `qiskit.primitives.Estimator` class, based on the [Statevector construct](https://qiskit.org/documentation/stubs/qiskit.quantum_info.Statevector.html?highlight=statevector#qiskit.quantum_info.Statevector) (algebraic simulation).\n", + "" ] }, { @@ -665,7 +667,7 @@ } }, "source": [ - "Here we are initializing an instance of `qiskit_ibm_runtime.Estimator` instead of `qiskit.primitives.Estimator` to use Qiskit Runtime's implementation of the `Estimator`. \n", + "Here we are initializing an instance of `qiskit_ibm_runtime.Estimator` rather than `qiskit.primitives.Estimator` to use Qiskit Runtime's implementation of the `Estimator`. \n", "\n", "When you initialize the `Estimator`, you'll need to pass in the backend you previously selected as the target device (or simulator), using the `session` parameter. This automatically opens a session for that backend. We will talk more about session in a later section." ] @@ -783,7 +785,7 @@ } }, "source": [ - "Primitives come with a number of options that are grouped into different categories. Commonly used options, such as `resilience_level`, are at the first level.\n", + "Primitives come with several options that are grouped into different categories. Commonly used options, such as `resilience_level`, are at the first level.\n", "\n", "![options](images/options.png)" ] @@ -809,7 +811,7 @@ } }, "source": [ - "In the example below, we create an instance of the `Options` class. `optimization_level` is a first level option and can be passed as an input parameter. Options related to the execution environment are passed using the `environment` parameter." + "In the following example, we create an instance of the `Options` class. `optimization_level` is a first level option and can be passed as an input parameter. Options related to the execution environment are passed using the `environment` parameter." ] }, { @@ -903,9 +905,9 @@ } }, "source": [ - "You can also pass in options via the `run()` method. This will overwrite the options you specified when creating the `Estimator` instance for that particular execution. \n", + "You can also pass options to the `run()` method. This will overwrite the options you specified when creating the `Estimator` instance for that particular execution. \n", "\n", - "Since most users will only overwrite a handful of options at the job level, it is not necessary to specify the category the options are in. The code below, for example, specifies `shots=1024` instead of `execution={\"shots\": 1024}` (which is also valid). " + "Since most users will only overwrite a handful of options at the job level, it is not necessary to specify the category the options are in. The following code, for example, specifies `shots=1024` rather than `execution={\"shots\": 1024}` (which is also valid). " ] }, { @@ -1025,7 +1027,7 @@ } }, "source": [ - "A Qiskit Runtime _session_ allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. As long as the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead." + "A Qiskit Runtime _session_ allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. If the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead." ] }, { @@ -1054,7 +1056,7 @@ "If you don't specify a timeout value, it is set to the initial job's maximum execution time and is the smaller of these values:\n", "\n", "- The system limit which can be found [here](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/faqs/max_execution_time.html).\n", - "- The max_execution_time defined by the program.\n", + "- The `max_execution_time` defined by the program.\n", "\n", "After this time limit is reached, the session is permanently closed." ] @@ -1201,7 +1203,7 @@ } }, "source": [ - "The example below shows how you can create both an instance of the `Sampler` class and one of the `Estimator` class and invoke their `run()` methods within a session. " + "The following example shows how you can create both an instance of the `Sampler` class and one of the `Estimator` class and invoke their `run()` methods within a session. " ] }, { @@ -1277,9 +1279,13 @@ "\n", " sampler_job = sampler.run(sampler_circuit)\n", " estimator_job = estimator.run(circuit, observable)\n", - " \n", - " print(f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\")\n", - " print(f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\")" + "\n", + " print(\n", + " f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\"\n", + " )\n", + " print(\n", + " f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\"\n", + " )" ] }, { @@ -1303,7 +1309,7 @@ } }, "source": [ - "Below is a quick recap of using Qiskit Runtime primitives, options, and session." + "The following code recaps using Qiskit Runtime primitives, options, and session." ] }, { @@ -1326,7 +1332,13 @@ } ], "source": [ - "from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Estimator, Options\n", + "from qiskit_ibm_runtime import (\n", + " QiskitRuntimeService,\n", + " Session,\n", + " Sampler,\n", + " Estimator,\n", + " Options,\n", + ")\n", "\n", "# 1. Initialize account\n", "service = QiskitRuntimeService(channel=\"ibm_quantum\")\n", @@ -1347,10 +1359,14 @@ " # 6. Submit jobs\n", " sampler_job = sampler.run(sampler_circuit)\n", " estimator_job = estimator.run(circuit, observable)\n", - " \n", + "\n", " # 7. Get results\n", - " print(f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\")\n", - " print(f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\")" + " print(\n", + " f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\"\n", + " )\n", + " print(\n", + " f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\"\n", + " )" ] }, { @@ -1390,6 +1406,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, @@ -1461,4 +1478,3 @@ "nbformat": 4, "nbformat_minor": 5 } - diff --git a/docs/tutorials/how-to-getting-started-with-sampler.ipynb b/docs/tutorials/how-to-getting-started-with-sampler.ipynb index 90836ecaf..12816e298 100644 --- a/docs/tutorials/how-to-getting-started-with-sampler.ipynb +++ b/docs/tutorials/how-to-getting-started-with-sampler.ipynb @@ -47,7 +47,7 @@ "source": [ "Primitives are core functions that make it easier to build modular algorithms and applications. \n", "\n", - "Instead of simply returning counts, they return more immediately meaningful information. \n", + "Rather than simply returning counts, they return more immediately meaningful information. \n", "\n", "Additionally, they provide a seamless way to access the latest advancements in IBM Quantum hardware and software." ] @@ -104,7 +104,7 @@ "Similar to the `Backend` base class, there is an `Sampler` base class defined in Qiskit Terra that standardizes the way users interact with all `Sampler` implementations.\n", "This allows users to easily change their choice of simulator or device for performing expectation value calculations, even if the underlying implementation is different. \n", "\n", - "In this section we will be using the default implementation in Qiskit Terra, which uses a local statevector simulator." + "In this section we will be using the default implementation in Qiskit Terra, which uses a local state vector simulator." ] }, { @@ -180,7 +180,7 @@ } }, "source": [ - "The next step is to create an instance of an `Sampler` class. This can be any `Sampler` class that complies with the `Sampler` primitive specification. For simplicity, we will use Qiskit Terra's `qiskit.primitives.Sampler` class, based on the [Statevector construct](https://qiskit.org/documentation/stubs/qiskit.quantum_info.Statevector.html?highlight=statevector#qiskit.quantum_info.Statevector) (i.e. algebraic simulation)." + "The next step is to create an instance of an `Sampler` class. This can be any `Sampler` class that complies with the `Sampler` primitive specification. For simplicity, we will use Qiskit Terra's `qiskit.primitives.Sampler` class, based on the [`Statevector` construct](https://qiskit.org/documentation/stubs/qiskit.quantum_info.Statevector.html?highlight=statevector#qiskit.quantum_info.Statevector) (that is, algebraic simulation)." ] }, { @@ -594,7 +594,7 @@ } }, "source": [ - "Here we are initializing an instance of `qiskit_ibm_runtime.Sampler` instead of `qiskit.primitives.Sampler` to use Qiskit Runtime's implementation of the `Sampler`. \n", + "Here we are initializing an instance of `qiskit_ibm_runtime.Sampler` rather than `qiskit.primitives.Sampler` to use Qiskit Runtime's implementation of the `Sampler`. \n", "\n", "When you initialize the `Sampler`, you'll need to pass in the backend you previously selected as the target device (or simulator), using the `session` parameter. This automatically opens a session for that backend. We will talk more about session in a later section." ] @@ -713,7 +713,7 @@ } }, "source": [ - "Primitives come with a number of options that are grouped into different categories. Commonly used options, such as `resilience_level`, are at the first level.\n", + "Primitives come with several options that are grouped into different categories. Commonly used options, such as `resilience_level`, are at the first level.\n", "\n", "![options](images/options.png)" ] @@ -739,7 +739,7 @@ } }, "source": [ - "In the example below, we create an instance of the `Options` class. `optimization_level` is a first level option and can be passed as an input parameter. Options related to the execution environment are passed using the `environment` parameter." + "In the following example, we create an instance of the `Options` class. `optimization_level` is a first level option and can be passed as an input parameter. Options related to the execution environment are passed using the `environment` parameter." ] }, { @@ -833,9 +833,9 @@ } }, "source": [ - "You can also pass in options via the `run()` method. This will overwrite the options you specified when creating the `Sampler` instance for that particular execution. \n", + "You can also pass in options through the `run()` method. This will overwrite the options you specified when creating the `Sampler` instance for that particular execution. \n", "\n", - "Since most users will only overwrite a handful of options at the job level, it is not necessary to specify the category the options are in. The code below, for example, specifies `shots=1024` instead of `execution={\"shots\": 1024}` (which is also valid). " + "Since most users will only overwrite a handful of options at the job level, it is not necessary to specify the category the options are in. The following code, for example, specifies `shots=1024` rather than `execution={\"shots\": 1024}` (which is also valid). " ] }, { @@ -953,7 +953,7 @@ } }, "source": [ - "A Qiskit Runtime _session_ allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. As long as the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead." + "A Qiskit Runtime _session_ allows you to group a collection of iterative calls to the quantum computer. A session is started when the first job within the session is started. Provided the session is active, subsequent jobs within the session are prioritized by the scheduler to minimize artificial delay within an iterative algorithm. Data used within a session, such as transpiled circuits, is also cached to avoid unnecessary overhead." ] }, { @@ -982,7 +982,7 @@ "If you don't specify a timeout value, it is set to the initial job's maximum execution time and is the smaller of these values:\n", "\n", "- The system limit which can be found [here](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/faqs/max_execution_time.html).\n", - "- The max_execution_time defined by the program.\n", + "- The `max_execution_time` defined by the program.\n", "\n", "After this time limit is reached, the session is permanently closed." ] @@ -1088,7 +1088,7 @@ } }, "source": [ - "First we prepare a circuit and an observale for the `Estimator` primitive." + "First we prepare a circuit and an observable for the `Estimator` primitive." ] }, { @@ -1139,7 +1139,7 @@ } }, "source": [ - "The example below shows how you can create both an instance of the `Sampler` class and one of the `Estimator` class and invoke their `run()` methods within a session. " + "The following example shows how you can create both an instance of the `Sampler` class and one of the `Estimator` class and invoke their `run()` methods within a session. " ] }, { @@ -1215,9 +1215,13 @@ "\n", " sampler_job = sampler.run(circuit)\n", " estimator_job = estimator.run(estimator_circuit, observable)\n", - " \n", - " print(f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\")\n", - " print(f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\")" + "\n", + " print(\n", + " f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\"\n", + " )\n", + " print(\n", + " f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\"\n", + " )" ] }, { @@ -1241,7 +1245,7 @@ } }, "source": [ - "Below is a quick recap of using Qiskit Runtime primitives, options, and session." + "The following code quickly recaps using Qiskit Runtime primitives, options, and sessions." ] }, { @@ -1264,7 +1268,13 @@ } ], "source": [ - "from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Estimator, Options\n", + "from qiskit_ibm_runtime import (\n", + " QiskitRuntimeService,\n", + " Session,\n", + " Sampler,\n", + " Estimator,\n", + " Options,\n", + ")\n", "\n", "# 1. Initialize account\n", "service = QiskitRuntimeService(channel=\"ibm_quantum\")\n", @@ -1285,10 +1295,14 @@ " # 6. Submit jobs\n", " sampler_job = sampler.run(circuit)\n", " estimator_job = estimator.run(estimator_circuit, observable)\n", - " \n", + "\n", " # 7. Get results\n", - " print(f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\")\n", - " print(f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\")" + " print(\n", + " f\">>> Quasi Distribution from the sampler job: {sampler_job.result().quasi_dists[0]}\"\n", + " )\n", + " print(\n", + " f\">>> Expectation value from the estimator job: {estimator_job.result().values[0]}\"\n", + " )" ] }, { @@ -1328,6 +1342,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, diff --git a/docs/tutorials/qpe_with_sampler.ipynb b/docs/tutorials/qpe_with_sampler.ipynb index dc6c946cc..1d95b545b 100644 --- a/docs/tutorials/qpe_with_sampler.ipynb +++ b/docs/tutorials/qpe_with_sampler.ipynb @@ -50,7 +50,7 @@ "source": [ "## Overview\n", "\n", - "As explained above, there are black boxes in the QPE algorithm to prepare the state $|\\psi \\rangle$ and perform the controlled-$U^{2^j}$ operation. In this tutorial, you will prepare a series of QPE circuits containing different black boxes corresponding to different phases. You will then run these circuits using the [Sampler primitive](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.Sampler.html) and analyze the results. As you will see, the Sampler primitive makes running parameterized circuits very easy. Instead of creating a series of QPE circuits, you only need to create *one* QPE circuit with a parameter specifying the phase the black boxes generate and a series of phase values for the parameter.\n", + "As explained earlier, there are black boxes in the QPE algorithm to prepare the state $|\\psi \\rangle$ and perform the controlled-$U^{2^j}$ operation. In this tutorial, you will prepare a series of QPE circuits containing different black boxes corresponding to different phases. You will then run these circuits using the [Sampler primitive](https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.Sampler.html) and analyze the results. As you will see, the Sampler primitive makes running parameterized circuits very easy. Rather than create a series of QPE circuits, you only need to create *one* QPE circuit with a parameter specifying the phase the black boxes generate and a series of phase values for the parameter.\n", "\n", "
\n", "\n", @@ -101,18 +101,27 @@ "from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit\n", "from qiskit.circuit.library import QFT\n", "\n", + "\n", "def create_qpe_circuit(theta, num_qubits):\n", - " '''Creates a QPE circuit given theta and num_qubits.'''\n", - " \n", + " \"\"\"Creates a QPE circuit given theta and num_qubits.\"\"\"\n", + "\n", " # Step 1: Create a circuit with two quantum registers and one classical register.\n", - " first = QuantumRegister(size=num_qubits, name='first') # the first register for phase estimation\n", - " second = QuantumRegister(size=1, name='second') # the second register for storing eigenvector |psi>\n", - " classical = ClassicalRegister(size=num_qubits, name='readout') # classical register for readout\n", + " first = QuantumRegister(\n", + " size=num_qubits, name=\"first\"\n", + " ) # the first register for phase estimation\n", + " second = QuantumRegister(\n", + " size=1, name=\"second\"\n", + " ) # the second register for storing eigenvector |psi>\n", + " classical = ClassicalRegister(\n", + " size=num_qubits, name=\"readout\"\n", + " ) # classical register for readout\n", " qpe_circuit = QuantumCircuit(first, second, classical)\n", "\n", " # Step 2: Initialize the qubits.\n", " # All qubits are initialized in |0> by default, no extra code is needed to initialize the first register.\n", - " qpe_circuit.x(second) # Initialize the second register with state |psi>, which is |1> in this example.\n", + " qpe_circuit.x(\n", + " second\n", + " ) # Initialize the second register with state |psi>, which is |1> in this example.\n", "\n", " # Step 3: Create superposition in the first register.\n", " qpe_circuit.barrier() # Add barriers to separate each step of the algorithm for better visualization.\n", @@ -121,7 +130,9 @@ " # Step 4: Apply a controlled-U^(2^j) black box.\n", " qpe_circuit.barrier()\n", " for j in range(num_qubits):\n", - " qpe_circuit.cp(theta*2*np.pi*(2**j), j, num_qubits) # Theta doesn't contain the 2 pi factor.\n", + " qpe_circuit.cp(\n", + " theta * 2 * np.pi * (2**j), j, num_qubits\n", + " ) # Theta doesn't contain the 2 pi factor.\n", "\n", " # Step 5: Apply an inverse QFT to the first register.\n", " qpe_circuit.barrier()\n", @@ -162,8 +173,10 @@ ], "source": [ "num_qubits = 4\n", - "qpe_circuit_fixed_phase = create_qpe_circuit(1/2, num_qubits) # Create a QPE circuit with fixed theta=1/2.\n", - "qpe_circuit_fixed_phase.draw('mpl')" + "qpe_circuit_fixed_phase = create_qpe_circuit(\n", + " 1 / 2, num_qubits\n", + ") # Create a QPE circuit with fixed theta=1/2.\n", + "qpe_circuit_fixed_phase.draw(\"mpl\")" ] }, { @@ -195,9 +208,11 @@ "source": [ "from qiskit.circuit import Parameter\n", "\n", - "theta = Parameter('theta') # Create a parameter `theta` whose values can be assigned later.\n", + "theta = Parameter(\n", + " \"theta\"\n", + ") # Create a parameter `theta` whose values can be assigned later.\n", "qpe_circuit_parameterized = create_qpe_circuit(theta, num_qubits)\n", - "qpe_circuit_parameterized.draw('mpl')" + "qpe_circuit_parameterized.draw(\"mpl\")" ] }, { @@ -207,7 +222,7 @@ "source": [ "### Create a list of phase values to be assigned later\n", "\n", - "After creating the parameterized QPE circuit, you will create a list of phase values to be assigned to the circuit in the next step. You can use the code below to create a list of 21 phase values that range from `0` to `2` with equal spacing, i.e. `0`, `0.1`, `0.2`, ..., `1.9`, `2.0`." + "After creating the parameterized QPE circuit, you will create a list of phase values to be assigned to the circuit in the next step. You can use the following code to create a list of 21 phase values that range from `0` to `2` with equal spacing, that is, `0`, `0.1`, `0.2`, ..., `1.9`, `2.0`." ] }, { @@ -219,7 +234,9 @@ "source": [ "number_of_phases = 21\n", "phases = np.linspace(0, 2, number_of_phases)\n", - "individual_phases = [[ph] for ph in phases] # Phases need to be expressed as a list of lists." + "individual_phases = [\n", + " [ph] for ph in phases\n", + "] # Phases need to be expressed as a list of lists." ] }, { @@ -275,10 +292,14 @@ "from qiskit_ibm_runtime import Sampler, Session\n", "\n", "with Session(service=service, backend=backend):\n", - " results = Sampler().run(\n", - " [qpe_circuit_parameterized]*len(individual_phases), \n", - " parameter_values=individual_phases\n", - " ).result()" + " results = (\n", + " Sampler()\n", + " .run(\n", + " [qpe_circuit_parameterized] * len(individual_phases),\n", + " parameter_values=individual_phases,\n", + " )\n", + " .result()\n", + " )" ] }, { @@ -296,7 +317,7 @@ "source": [ "### Analyze the results of one circuit\n", "\n", - "After the job has been completed, you can start analyzing the results by looking at the histogram of one of the circuits. The (quasi-)probability distribution of the measurement outcome is stored in `results.quasi_dists` and you can access results from an individual circuit by passing the index of the circuit ($idx=6$ in the example below) you are interested in. " + "After the job has been completed, you can start analyzing the results by looking at the histogram of one of the circuits. The (quasi-)probability distribution of the measurement outcome is stored in `results.quasi_dists` and you can access results from an individual circuit by passing the index of the circuit ($idx=6$ in the following example) you are interested in. " ] }, { @@ -321,7 +342,10 @@ "from qiskit.tools.visualization import plot_histogram\n", "\n", "idx = 6\n", - "plot_histogram(results.quasi_dists[idx].binary_probabilities(), legend=[f'$\\\\theta$={phases[idx]:.3f}'])" + "plot_histogram(\n", + " results.quasi_dists[idx].binary_probabilities(),\n", + " legend=[f\"$\\\\theta$={phases[idx]:.3f}\"],\n", + ")" ] }, { @@ -333,7 +357,7 @@ "\n", "$$\\theta = \\frac{N_1}{2^n} = \\frac{10}{2^4} = 0.625. $$\n", "\n", - "This is close to the expected value of $0.6$, but you can do a better estimate by taking the weighted average of the most likely outcome (`1010` in binary or `10` in decimal) and the second most likely outcome (`1001` in binary or `9` in decimal):\n", + "This is close to the expected value of $0.6$, but you can get a better estimate by taking the weighted average of the most likely outcome (`1010` in binary or `10` in decimal) and the second most likely outcome (`1001` in binary or `9` in decimal):\n", "\n", "$$\\theta = \\frac{P_1 \\times \\frac{N_1}{2^n} + P_2 \\times \\frac{N_2}{2^n}}{P_1 + P_2} = \\frac{0.554 \\times \\frac{10}{2^4} + 0.269 \\times \\frac{9}{2^4}}{0.554 + 0.269} = 0.605,$$\n", "\n", @@ -347,7 +371,7 @@ "source": [ "### Analyze the results of all circuits\n", "\n", - "You can use the helper functions below to find the values for $N_1$, $P_1$, $N_2$, and $P_2$ for a phase and calculate the estimated $\\theta$. Ideally $N_2$ should be a \"neighbor\" of $N_1$ (for example, the neighbors of `1010` are `1001` and `1011`), however due to the presence of noise, the second most likely outcome may not be a neighbor of $N_1$ if the results were obtained from a real quantum system. The helper functions take the $N_2$ value only from $N_1$'s neighbors." + "You can use the following helper functions to find the values for $N_1$, $P_1$, $N_2$, and $P_2$ for a phase and calculate the estimated $\\theta$. Ideally $N_2$ should be a \"neighbor\" of $N_1$ (for example, the neighbors of `1010` are `1001` and `1011`). However, due to the presence of noise, the second most likely outcome may not be a neighbor of $N_1$ if the results were obtained from a real quantum system. The helper functions take the $N_2$ value only from $N_1$'s neighbors." ] }, { @@ -358,30 +382,32 @@ "outputs": [], "source": [ "def most_likely_bitstring(results_dict):\n", - " '''Finds the most likely outcome bit string from a result dictionary.'''\n", + " \"\"\"Finds the most likely outcome bit string from a result dictionary.\"\"\"\n", " return max(results_dict, key=results_dict.get)\n", "\n", + "\n", "def find_neighbors(bitstring):\n", - " '''Finds the neighbors of a bit string.\n", - " \n", - " Example: \n", + " \"\"\"Finds the neighbors of a bit string.\n", + "\n", + " Example:\n", " For bit string '1010', this function returns ('1001', '1011')\n", - " '''\n", - " if bitstring == len(bitstring)*'0':\n", - " neighbor_left = len(bitstring)*'1'\n", + " \"\"\"\n", + " if bitstring == len(bitstring) * \"0\":\n", + " neighbor_left = len(bitstring) * \"1\"\n", " else:\n", - " neighbor_left = format((int(bitstring,2)-1), '0%sb'%len(bitstring))\n", + " neighbor_left = format((int(bitstring, 2) - 1), \"0%sb\" % len(bitstring))\n", "\n", - " if bitstring == len(bitstring)*'1':\n", - " neighbor_right = len(bitstring)*'0'\n", + " if bitstring == len(bitstring) * \"1\":\n", + " neighbor_right = len(bitstring) * \"0\"\n", " else:\n", - " neighbor_right = format((int(bitstring,2)+1), '0%sb'%len(bitstring))\n", + " neighbor_right = format((int(bitstring, 2) + 1), \"0%sb\" % len(bitstring))\n", "\n", " return (neighbor_left, neighbor_right)\n", "\n", + "\n", "def estimate_phase(results_dict):\n", - " '''Estimates the phase from a result dictionary of a QPE circuit.'''\n", - " \n", + " \"\"\"Estimates the phase from a result dictionary of a QPE circuit.\"\"\"\n", + "\n", " # Find the most likely outcome bit string N1 and its neighbors.\n", " num_1_key = most_likely_bitstring(results_dict)\n", " neighbor_left, neighbor_right = find_neighbors(num_1_key)\n", @@ -409,7 +435,7 @@ " elif neighbor_left_prob > neighbor_right_prob:\n", " # Both neighbors exist and neighbor_left has higher probability, so N2 is neighbor_left.\n", " num_2_key = neighbor_left\n", - " num_2_prob = neighbor_left_prob \n", + " num_2_prob = neighbor_left_prob\n", " else:\n", " # Both neighbors exist and neighbor_right has higher probability, so N2 is neighor_right.\n", " num_2_key = neighbor_right\n", @@ -417,11 +443,13 @@ "\n", " # Calculate the estimated phases for N1 and N2.\n", " num_qubits = len(num_1_key)\n", - " num_1_phase = (int(num_1_key, 2) / 2**num_qubits)\n", - " num_2_phase = (int(num_2_key, 2) / 2**num_qubits)\n", + " num_1_phase = int(num_1_key, 2) / 2**num_qubits\n", + " num_2_phase = int(num_2_key, 2) / 2**num_qubits\n", "\n", " # Calculate the weighted average phase from N1 and N2.\n", - " phase_estimated = (num_1_phase * num_1_prob + num_2_phase * num_2_prob) / (num_1_prob + num_2_prob)\n", + " phase_estimated = (num_1_phase * num_1_prob + num_2_phase * num_2_prob) / (\n", + " num_1_prob + num_2_prob\n", + " )\n", "\n", " return phase_estimated" ] @@ -451,7 +479,7 @@ "id": "3ed0fc7d", "metadata": {}, "source": [ - "The ideal solutions for the phases $\\theta$ are periodic with a period of `1` because the eigenvalue $e^{2 \\pi i \\theta}$ is $2 \\pi$ periodic. You can run the cell below to generate the ideal solutions for comparison with the solutions obtained from the QPE algorithm." + "The ideal solutions for the phases $\\theta$ are periodic with a period of `1` because the eigenvalue $e^{2 \\pi i \\theta}$ is $2 \\pi$ periodic. You can run the following cell to generate the ideal solutions for comparison with the solutions obtained from the QPE algorithm." ] }, { @@ -462,10 +490,12 @@ "outputs": [], "source": [ "ideal_solutions = np.append(\n", - " phases[:(number_of_phases-1)//2], # first period\n", - " np.subtract(phases[(number_of_phases-1)//2:-1], 1) # second period\n", + " phases[: (number_of_phases - 1) // 2], # first period\n", + " np.subtract(phases[(number_of_phases - 1) // 2 : -1], 1), # second period\n", ")\n", - "ideal_solutions = np.append(ideal_solutions, np.subtract(phases[-1], 2)) # starting point of the third period" + "ideal_solutions = np.append(\n", + " ideal_solutions, np.subtract(phases[-1], 2)\n", + ") # starting point of the third period" ] }, { @@ -473,7 +503,7 @@ "id": "ac4b970c", "metadata": {}, "source": [ - "You can run the code below to visualize the solutions." + "You can run the following code to visualize the solutions." ] }, { @@ -509,12 +539,12 @@ "import matplotlib.pyplot as plt\n", "\n", "fig = plt.figure(figsize=(10, 6))\n", - "plt.plot(phases, ideal_solutions, '--', label='Ideal solutions')\n", - "plt.plot(phases, qpe_solutions, 'o', label='QPE solutions')\n", + "plt.plot(phases, ideal_solutions, \"--\", label=\"Ideal solutions\")\n", + "plt.plot(phases, qpe_solutions, \"o\", label=\"QPE solutions\")\n", "\n", - "plt.title('Quantum Phase Estimation Algorithm')\n", - "plt.xlabel('Input Phase')\n", - "plt.ylabel('Output Phase')\n", + "plt.title(\"Quantum Phase Estimation Algorithm\")\n", + "plt.xlabel(\"Input Phase\")\n", + "plt.ylabel(\"Output Phase\")\n", "plt.legend()" ] }, @@ -575,6 +605,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, diff --git a/docs/tutorials/sea_with_sampler.ipynb b/docs/tutorials/sea_with_sampler.ipynb index 8942a9ce5..ed80c7dd2 100644 --- a/docs/tutorials/sea_with_sampler.ipynb +++ b/docs/tutorials/sea_with_sampler.ipynb @@ -7,7 +7,7 @@ "source": [ "# Spectroscopic Eigensolver Algorithm with Sampler\n", "\n", - "This tutorial demonstrates the ability to send flexible circuits to the `Sampler` primitive by performing a simple example of the spectroscopic eigensolver algorithm ([arXiv:2202.12910](http://arxiv.org/abs/2202.12910)). The SEA is used for quantum simulation of model Hamiltonians, and works by interacting a \"probe\" auxiliary qubit with a simulation register. The energy of the probe qubit is swept and eigenvalues of the simulation Hamiltonian are observed as peaks or dips in the response, akin to the experimental tool of spectroscopy. Because each point (i.e., energy) is a different quantum circuit, this technique is expensive with respect to the number of circuits required. The `Sampler` provides the flexibility to send just a single circuit with the needed `Parameter`s passed." + "This tutorial demonstrates the ability to send flexible circuits to the `Sampler` primitive by performing a simple example of the Spectroscopic Eigensolver Algorithm (SEA) ([arXiv:2202.12910](http://arxiv.org/abs/2202.12910)). The SEA is used for quantum simulation of model Hamiltonians, and works by interacting a \"probe\" auxiliary qubit with a simulation register. The energy of the probe qubit is swept and eigenvalues of the simulation Hamiltonian are observed as peaks or dips in the response, akin to the experimental tool of spectroscopy. Because each point (energy) is a different quantum circuit, this technique is expensive with respect to the number of circuits required. The `Sampler` provides the flexibility to send just a single circuit with the needed `Parameter`s passed." ] }, { @@ -38,13 +38,13 @@ "id": "ce7228b0", "metadata": {}, "source": [ - "## Simple Hamiltonian Model\n", + "## Simple Hamiltonian model\n", "\n", - "Let's consider a Pauli-X matrix acting on a qubit,\n", + "Let us consider a Pauli-X matrix acting on a qubit,\n", "$$\n", "H_{\\rm Pauli}/\\hbar = \\mu X\n", "$$\n", - "where we can set $\\mu$ later, or even sweep its values as well. The SEA works by taking the model Pauli (i.e., qubit) Hamiltonian and building a larger \"resonance\" Hamiltonian that includes both the simulation register and probe qubit `q0` via\n", + "where we can set $\\mu$ later, or even sweep its values as well. The SEA works by taking the model Pauli (qubit) Hamiltonian and building a larger \"resonance\" Hamiltonian that includes both the simulation register and probe qubit `q0` through\n", "$$\n", "H_{\\rm res} / \\hbar = -\\frac{1}{2} \\omega IZ + c XX + H_{\\rm Pauli}/\\hbar \\otimes I\n", "$$\n", @@ -63,7 +63,7 @@ "from qiskit.circuit import Parameter\n", "from qiskit.opflow import I, X, Z\n", "\n", - "mu = Parameter('$\\\\mu$')\n", + "mu = Parameter(\"$\\\\mu$\")\n", "ham_pauli = mu * X" ] }, @@ -74,10 +74,10 @@ "metadata": {}, "outputs": [], "source": [ - "cc = Parameter('$c$')\n", - "ww = Parameter('$\\\\omega$')\n", + "cc = Parameter(\"$c$\")\n", + "ww = Parameter(\"$\\\\omega$\")\n", "\n", - "ham_res = -(1/2)*ww*(I^Z) + cc*(X^X) + (ham_pauli^I)" + "ham_res = -(1 / 2) * ww * (I ^ Z) + cc * (X ^ X) + (ham_pauli ^ I)" ] }, { @@ -95,8 +95,8 @@ "metadata": {}, "outputs": [], "source": [ - "tt = Parameter('$t$')\n", - "U_ham = (tt*ham_res).exp_i()" + "tt = Parameter(\"$t$\")\n", + "U_ham = (tt * ham_res).exp_i()" ] }, { @@ -132,11 +132,13 @@ "\n", "num_trot_steps = 5\n", "total_time = 10\n", - "cr = ClassicalRegister(1, 'c')\n", + "cr = ClassicalRegister(1, \"c\")\n", "\n", - "spec_op = PauliTrotterEvolution(trotter_mode=Suzuki(order=2, reps=num_trot_steps)).convert(U_ham)\n", + "spec_op = PauliTrotterEvolution(\n", + " trotter_mode=Suzuki(order=2, reps=num_trot_steps)\n", + ").convert(U_ham)\n", "spec_circ = spec_op.to_circuit()\n", - "spec_circ_t = transpile(spec_circ, basis_gates=['sx', 'rz', 'cx'])\n", + "spec_circ_t = transpile(spec_circ, basis_gates=[\"sx\", \"rz\", \"cx\"])\n", "spec_circ_t.add_register(cr)\n", "spec_circ_t.measure(0, cr[0])" ] @@ -162,7 +164,7 @@ } ], "source": [ - "spec_circ_t.draw('mpl')" + "spec_circ_t.draw(\"mpl\")" ] }, { @@ -170,7 +172,7 @@ "id": "95ff35f5", "metadata": {}, "source": [ - "Now let's fix our parameters and sweep over frequency with a number of points `num_pts`. The eigenvalues of our model Hamiltonian $H_{\\rm Pauli}$ are $\\pm \\mu$, so we need to choose a range that includes those numbers.\n", + "Now let's fix our parameters and sweep over the frequency with several points `num_pts`. The eigenvalues of our model Hamiltonian $H_{\\rm Pauli}$ are $\\pm \\mu$, so we need to choose a range that includes those numbers.\n", "\n", "Note that the `Parameter`s' keys and values must be separated and converted into a `List` of `List`s. The keys give us the `Parameter`s inside each circuit. In this case, we only have a single circuit, so the `List` of keys contains a single `List`. For the `Parameter` values, there is a `List` for each value of `ww`. " ] @@ -183,11 +185,7 @@ "outputs": [], "source": [ "# fixed Parameters\n", - "fixed_params = {\n", - " cc: 0.3,\n", - " mu: 0.7,\n", - " tt: total_time\n", - "}\n", + "fixed_params = {cc: 0.3, mu: 0.7, tt: total_time}\n", "# Parameter value for single circuit\n", "param_keys = list(spec_circ_t.parameters)\n", "\n", @@ -220,11 +218,9 @@ "with Session(backend=backend):\n", " sampler = Sampler()\n", " job = sampler.run(\n", - " circuits=[spec_circ_t]*num_pts,\n", - " parameter_values=param_vals,\n", - " shots=1e5\n", + " circuits=[spec_circ_t] * num_pts, parameter_values=param_vals, shots=1e5\n", " )\n", - " result = job.result()\n" + " result = job.result()" ] }, { @@ -245,7 +241,7 @@ "Zexps = []\n", "for dist in result.quasi_dists:\n", " if 1 in dist:\n", - " Zexps.append(1 - 2*dist[1])\n", + " Zexps.append(1 - 2 * dist[1])\n", " else:\n", " Zexps.append(1)" ] @@ -255,7 +251,7 @@ "id": "f66fcbbe", "metadata": {}, "source": [ - "As a sanity check, we'll calculate the exact expectation values with Qiskit Opflow." + "As a quick check, we'll calculate the exact expectation values with Qiskit Opflow." ] }, { @@ -267,14 +263,10 @@ "source": [ "from qiskit.opflow import PauliExpectation, Zero\n", "\n", - "param_bind = {\n", - " cc: 0.3,\n", - " mu: 0.7,\n", - " tt: total_time\n", - "}\n", + "param_bind = {cc: 0.3, mu: 0.7, tt: total_time}\n", "\n", - "init_state = Zero^2\n", - "obsv = I^Z\n", + "init_state = Zero ^ 2\n", + "obsv = I ^ Z\n", "Zexp_exact = (U_ham @ init_state).adjoint() @ obsv @ (U_ham @ init_state)\n", "\n", "diag_meas_op = PauliExpectation().convert(Zexp_exact)\n", @@ -321,15 +313,16 @@ ], "source": [ "import matplotlib.pyplot as plt\n", - "plt.style.use('dark_background')\n", + "\n", + "plt.style.use(\"dark_background\")\n", "\n", "fig, ax = plt.subplots(dpi=100)\n", - "ax.plot([-param_bind[mu], -param_bind[mu]], [0, 1], ls='--', color='purple')\n", - "ax.plot([param_bind[mu], param_bind[mu]], [0, 1], ls='--', color='purple')\n", - "ax.plot(wvals, Zexact_values, label='Exact')\n", + "ax.plot([-param_bind[mu], -param_bind[mu]], [0, 1], ls=\"--\", color=\"purple\")\n", + "ax.plot([param_bind[mu], param_bind[mu]], [0, 1], ls=\"--\", color=\"purple\")\n", + "ax.plot(wvals, Zexact_values, label=\"Exact\")\n", "ax.plot(wvals, Zexps, label=f\"{backend}\")\n", - "ax.set_xlabel(r'$\\omega$ (arb)')\n", - "ax.set_ylabel(r'$\\langle Z \\rangle$ Expectation')\n", + "ax.set_xlabel(r\"$\\omega$ (arb)\")\n", + "ax.set_ylabel(r\"$\\langle Z \\rangle$ Expectation\")\n", "ax.legend()" ] }, @@ -352,6 +345,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, @@ -378,6 +372,7 @@ ], "source": [ "from qiskit.tools.jupyter import *\n", + "\n", "%qiskit_version_table" ] } diff --git a/docs/tutorials/user-transpiled-circuits.ipynb b/docs/tutorials/user-transpiled-circuits.ipynb index cc333750a..cf34dccaf 100644 --- a/docs/tutorials/user-transpiled-circuits.ipynb +++ b/docs/tutorials/user-transpiled-circuits.ipynb @@ -12,7 +12,7 @@ "\n", "## Transpiling circuits for IBM Quantum devices\n", "\n", - "In the code cell below, we create a small circuit that our transpiler will try to optimize. In this example, we create a circuit that carries out Grover's algorithm, with an oracle that marks the state `111`. We then simulate the ideal distribution (what we'd expect to measure if we ran this on a perfect quantum computer, an infinite number of times) for comparison later. " + "In the following code cell, we create a small circuit that our transpiler will try to optimize. In this example, we create a circuit that carries out Grover's algorithm, with an oracle that marks the state `111`. We then simulate the ideal distribution (what we'd expect to measure if we ran this on a perfect quantum computer, an infinite number of times) for comparison later. " ] }, { @@ -1040,16 +1040,19 @@ "# Create circuit to test transpiler on\n", "from qiskit import QuantumCircuit\n", "from qiskit.circuit.library import GroverOperator, Diagonal\n", - "oracle = Diagonal([1]*7 + [-1])\n", + "\n", + "oracle = Diagonal([1] * 7 + [-1])\n", "qc = QuantumCircuit(3)\n", - "qc.h([0,1,2])\n", + "qc.h([0, 1, 2])\n", "qc = qc.compose(GroverOperator(oracle))\n", "\n", "# Use Statevector object to calculate the ideal output\n", "from qiskit.quantum_info import Statevector\n", + "\n", "ideal_distribution = Statevector.from_instruction(qc).probabilities_dict()\n", "\n", "from qiskit.visualization import plot_histogram\n", + "\n", "plot_histogram(ideal_distribution)" ] }, @@ -1057,7 +1060,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next, we need to choose a backend to transpile for. In the cell below, we create a service instance, which we'll use to start a session, and get the backend object, which contains information for the transpiler. Since the transpilation process depends on the device, we'll ask the runtime service for a specific device by name. In this example, we'll use `ibm_algiers`, which is only available through IBM Cloud." + "Next, we need to choose a backend to transpile for. In the following cell, we create a service instance, which we'll use to start a session, and get the backend object, which contains information for the transpiler. Since the transpilation process depends on the device, we'll ask the runtime service for a specific device by name. In this example, we'll use `ibm_algiers`, which is only available through IBM Cloud." ] }, { @@ -1067,17 +1070,18 @@ "outputs": [], "source": [ "from qiskit_ibm_runtime import QiskitRuntimeService\n", + "\n", "service = QiskitRuntimeService()\n", - "backend = service.backend('ibm_algiers')" + "backend = service.backend(\"ibm_algiers\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, we transpile the circuits for our backend. We're going to compare the performance of the transpiler with `optimization_level` set to `0` (lowest) against `3` (highest). The lowest optimization level just does the bare minimum needed to get the circuit running on the device, i.e. map the circuit qubits to the device qubits, and add swaps gates to allow all 2-qubit operations. The highest optimization level is much smarter and uses lots of tricks to reduce the overall gate count. Since multi-qubit gates have high error rates, and qubits decohere over time, the shorter circuits should give better results.\n", + "Next, we transpile the circuits for our backend. We're going to compare the performance of the transpiler with `optimization_level` set to `0` (lowest) against `3` (highest). The lowest optimization level just does the bare minimum needed to get the circuit running on the device; it maps the circuit qubits to the device qubits, and adds swaps gates to allow all 2-qubit operations. The highest optimization level is much smarter and uses lots of tricks to reduce the overall gate count. Since multi-qubit gates have high error rates, and qubits decohere over time, the shorter circuits should give better results.\n", "\n", - "In the cell below, we transpile `qc` for both values of `optimization_level`, print the number of CNOT gates, and add the transpiled circuits to a list. Some of the transpiler's algorithms are randomized, so we set a seed for reproducibility." + "In the following cell, we transpile `qc` for both values of `optimization_level`, print the number of CNOT gates, and add the transpiled circuits to a list. Some of the transpiler's algorithms are randomized, so we set a seed for reproducibility." ] }, { @@ -1099,14 +1103,13 @@ "qc.measure_all()\n", "\n", "from qiskit import transpile\n", + "\n", "circuits = []\n", "for optimization_level in [0, 3]:\n", - " t_qc = transpile(qc,\n", - " backend,\n", - " optimization_level=optimization_level,\n", - " seed_transpiler=0)\n", - " print(f'CNOTs (optimization_level={optimization_level}): ',\n", - " t_qc.count_ops()['cx'])\n", + " t_qc = transpile(\n", + " qc, backend, optimization_level=optimization_level, seed_transpiler=0\n", + " )\n", + " print(f\"CNOTs (optimization_level={optimization_level}): \", t_qc.count_ops()[\"cx\"])\n", " circuits.append(t_qc)" ] }, @@ -1116,7 +1119,7 @@ "source": [ "Since CNOTs usually have a high error rate, the circuit transpiled with `optimization_level=3` should perform much better.\n", "\n", - "Another way we can improve performance is through [dynamic decoupling](https://qiskit.org/documentation/stubs/qiskit.transpiler.passes.DynamicalDecoupling.html), where we apply a sequence of gates to idling qubits. This cancels out some unwanted interactions with the environment. In the cell below, we add dynamic decoupling to the circuit transpiled with `optimization_level=3`, and add it to our list." + "Another way we can improve performance is through [dynamic decoupling](https://qiskit.org/documentation/stubs/qiskit.transpiler.passes.DynamicalDecoupling.html), where we apply a sequence of gates to idling qubits. This cancels out some unwanted interactions with the environment. In the following cell, we add dynamic decoupling to the circuit transpiled with `optimization_level=3`, and add it to our list." ] }, { @@ -1136,9 +1139,7 @@ "dd_sequence = [XGate(), XGate()]\n", "\n", "# Run scheduling and dynamic decoupling passes on circuit\n", - "pm = PassManager([ASAPSchedule(durations),\n", - " DynamicalDecoupling(durations, dd_sequence)]\n", - " )\n", + "pm = PassManager([ASAPSchedule(durations), DynamicalDecoupling(durations, dd_sequence)])\n", "circ_dd = pm.run(circuits[1])\n", "\n", "# Add this new circuit to our list\n", @@ -1153,7 +1154,7 @@ "\n", "## Run user-transpiled circuits using Qiskit Runtime\n", "\n", - "At this point, we have a list of circuits (named `circuits`) transpiled for `ibm_algiers`. In the cell below, we create an instance of the sampler primitive, and start a session using the context manager (`with ...:`), which automatically opens and closes the session for us. This is where we pass the `skip_transpilation=True` argument.\n", + "At this point, we have a list of circuits (named `circuits`) transpiled for `ibm_algiers`. In the following cell, we create an instance of the sampler primitive, and start a session using the context manager (`with ...:`), which automatically opens and closes the session for us. This is where we pass the `skip_transpilation=True` argument.\n", "\n", "Within the context manager, we sample the circuits and store the results to `result`." ] @@ -1170,8 +1171,9 @@ " sampler = Sampler()\n", " job = sampler.run(\n", " circuits=circuits, # sample all three circuits\n", - " skip_transpilation=True, \n", - " shots=8000)\n", + " skip_transpilation=True,\n", + " shots=8000,\n", + " )\n", " result = job.result()" ] }, @@ -2672,13 +2674,18 @@ ], "source": [ "from qiskit.visualization import plot_histogram\n", + "\n", "binary_prob = [quasi_dist.binary_probabilities() for quasi_dist in result.quasi_dists]\n", - "plot_histogram(binary_prob+[ideal_distribution],\n", - " bar_labels=False,\n", - " legend=['optimization_level=0',\n", - " 'optimization_level=3',\n", - " 'optimization_level=3 + dd',\n", - " 'ideal distribution'])" + "plot_histogram(\n", + " binary_prob + [ideal_distribution],\n", + " bar_labels=False,\n", + " legend=[\n", + " \"optimization_level=0\",\n", + " \"optimization_level=3\",\n", + " \"optimization_level=3 + dd\",\n", + " \"ideal distribution\",\n", + " ],\n", + ")" ] }, { @@ -2705,6 +2712,7 @@ ], "source": [ "from qiskit.quantum_info import hellinger_fidelity\n", + "\n", "for counts in result.quasi_dists:\n", " print(\n", " f\"{hellinger_fidelity(counts.binary_probabilities(), ideal_distribution):.3f}\"\n", @@ -2729,6 +2737,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, @@ -2764,6 +2773,7 @@ ], "source": [ "from qiskit.tools.jupyter import *\n", + "\n", "%qiskit_version_table\n", "%qiskit_copyright" ] diff --git a/docs/tutorials/vqe_with_estimator.ipynb b/docs/tutorials/vqe_with_estimator.ipynb index b993bb776..b22c2732d 100644 --- a/docs/tutorials/vqe_with_estimator.ipynb +++ b/docs/tutorials/vqe_with_estimator.ipynb @@ -5,11 +5,11 @@ "id": "0658e7c7", "metadata": {}, "source": [ - "# Variational Quantum Eigensolver with Estimator Primitive\n", + "# Variational Quantum Eigensolver with Estimator primitive\n", "\n", "## Overview\n", "\n", - "The Variational Quantum Eigensolver (VQE) is an optimization routine for finding the ground state energy (the lowest eigenvalue) of a [Hamiltonian](https://en.wikipedia.org/wiki/Hamiltonian_(quantum_mechanics)) and is a considered to be a viable candidate for near-term hardware. In this tutorial, you will learn how to use Qiskit Runtime to submit variational jobs using the estimator primitive. Specifically, you will calculate the ground state energy of the $H_2$ molecule." + "The Variational Quantum Eigensolver (VQE) is an optimization routine for finding the ground state energy (the lowest eigenvalue) of a [Hamiltonian](https://en.wikipedia.org/wiki/Hamiltonian_(quantum_mechanics)) and is a considered to be a viable candidate for near-term hardware. In this tutorial, you will learn how to use Qiskit Runtime to submit variational jobs using the `Estimator` primitive. Specifically, you will calculate the ground state energy of the $H_2$ molecule." ] }, { @@ -29,7 +29,7 @@ "source": [ "## Generate molecular Hamiltonians\n", "\n", - "This tutorial uses Qiskit Nature to generate and handle molecular Hamiltonians. If you haven't already, you can install Qiskit Nature (and the PySCF addon) using the commands shown below. For more information about Qiskit Nature, see the [_Getting started_ guide](https://qiskit.org/documentation/nature/getting_started.html).\n", + "This tutorial uses Qiskit Nature to generate and handle molecular Hamiltonians. If you haven't already, you can install Qiskit Nature (and the PySCF addon) using the following commands. For more information about Qiskit Nature, see the [_Getting started_ guide](https://qiskit.org/documentation/nature/getting_started.html).\n", "\n", "```\n", "pip install qiskit-nature\n", @@ -47,12 +47,14 @@ "outputs": [], "source": [ "from qiskit_nature.second_q.drivers import PySCFDriver\n", + "\n", "driver = PySCFDriver(\n", " atom=\"H 0 0 0; H 0 0 0.72\" # Two Hydrogen atoms, 0.72 Angstrom apart\n", ")\n", "molecule = driver.run()\n", "\n", "from qiskit_nature.second_q.mappers import QubitConverter, ParityMapper\n", + "\n", "qubit_converter = QubitConverter(ParityMapper())\n", "hamiltonian = qubit_converter.convert(molecule.second_q_ops()[0])" ] @@ -64,7 +66,7 @@ "source": [ "## Solve classically\n", "\n", - "Since this problem is very small, we can solve it exactly using classical methods. The code below uses the minimum eigensolver from the `NumPy` package to find the electronic ground state energy (in Hartree units), which we will use to assess the performance of the VQE." + "Since this problem is very small, we can solve it exactly using classical methods. The following code uses the minimum eigensolver from the `NumPy` package to find the electronic ground state energy (in Hartree units), which we will use to assess the performance of the VQE." ] }, { @@ -86,6 +88,7 @@ ], "source": [ "from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver\n", + "\n", "sol = NumPyMinimumEigensolver().compute_minimum_eigenvalue(hamiltonian)\n", "real_solution = molecule.interpret(sol)\n", "\n", @@ -99,7 +102,7 @@ "source": [ "## Solve with VQE\n", "\n", - "Next, we will create our service instance and specify our backend. In this example we will use a simulator to avoid queue times, but you can use the code below to run on a real device by simply changing the backend." + "Next, we will create our service instance and specify our backend. In this example we will use a simulator to avoid queue times, but you can use the following code to run on a real device by simply changing the backend." ] }, { @@ -124,10 +127,10 @@ "The next code cell specifies how we want to run the VQE. This includes\n", "\n", "- the type of circuit (ansatz) used to create our trial state,\n", - "- the classical algorithm that decides how to adjust our trial state to acheive better solutions, and\n", + "- the classical algorithm that decides how to adjust our trial state to achieve better solutions, and\n", "- the starting parameters.\n", "\n", - "We will also create a simple object to log our intermediate resuts for plotting later." + "We will also create a simple object to log our intermediate results for plotting later." ] }, { @@ -141,29 +144,36 @@ "\n", "# Use RealAmplitudes circuit to create trial states\n", "from qiskit.circuit.library import RealAmplitudes\n", + "\n", "ansatz = RealAmplitudes(num_qubits=2, reps=2)\n", "\n", "# Search for better states using SPSA algorithm\n", "from qiskit.algorithms.optimizers import SPSA\n", + "\n", "optimizer = SPSA(150)\n", "\n", "# Set a starting point for reproduceability\n", "import numpy as np\n", + "\n", "np.random.seed(6)\n", "initial_point = np.random.uniform(-np.pi, np.pi, 12)\n", "\n", "# Create an object to store intermediate results\n", "from dataclasses import dataclass\n", + "\n", + "\n", "@dataclass\n", "class VQELog:\n", " values: list\n", " parameters: list\n", + "\n", " def update(self, count, parameters, mean, _metadata):\n", " self.values.append(mean)\n", " self.parameters.append(parameters)\n", " print(f\"Running circuit {count} of ~350\", end=\"\\r\", flush=True)\n", "\n", - "log = VQELog([],[])" + "\n", + "log = VQELog([], [])" ] }, { @@ -195,17 +205,26 @@ " options = Options()\n", " options.optimization_level = 3\n", "\n", - " vqe = VQE(Estimator(session=session, options=options),\n", - " ansatz, optimizer, callback=log.update, initial_point=initial_point)\n", + " vqe = VQE(\n", + " Estimator(session=session, options=options),\n", + " ansatz,\n", + " optimizer,\n", + " callback=log.update,\n", + " initial_point=initial_point,\n", + " )\n", " result = vqe.compute_minimum_eigenvalue(hamiltonian)\n", " print(\"Experiment complete.\".ljust(30))\n", " print(f\"Raw result: {result.optimal_value}\")\n", - " \n", - " if 'simulator' not in backend:\n", + "\n", + " if \"simulator\" not in backend:\n", " # Run once with ZNE error mitigation\n", " options.resilience_level = 2\n", - " vqe = VQE(Estimator(session=session, options=options),\n", - " ansatz, SPSA(1), initial_point=result.optimal_point)\n", + " vqe = VQE(\n", + " Estimator(session=session, options=options),\n", + " ansatz,\n", + " SPSA(1),\n", + " initial_point=result.optimal_point,\n", + " )\n", " result = vqe.compute_minimum_eigenvalue(hamiltonian)\n", " print(f\"Mitigated result: {result.optimal_value}\")" ] @@ -215,7 +234,7 @@ "id": "8199c3e9", "metadata": {}, "source": [ - "Finally, the code cell below plots the intermediate results from the optimization process. The optimization algorithm tweaks the parameters to gradually home in on values that produce lower energies. Provided the algorithm does not get caught in a local minima, this graph will plateau at the electronic ground state energy of the molecule." + "Finally, the following code cell plots the intermediate results from the optimization process. The optimization algorithm tweaks the parameters to gradually home in on values that produce lower energies. Provided the algorithm does not get caught in a local minima, this graph will plateau at the electronic ground state energy of the molecule." ] }, { @@ -1637,6 +1656,7 @@ ], "source": [ "import qiskit_ibm_runtime\n", + "\n", "qiskit_ibm_runtime.version.get_version_info()" ] }, diff --git a/requirements-dev.txt b/requirements-dev.txt index 63322ebcd..6113ed906 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,6 +7,7 @@ sphinx-rtd-theme>=0.4.0 sphinx-tabs>=1.1.11 sphinx-automodapi sphinx-autodoc-typehints<=1.19.2 +nbqa==1.5.3 matplotlib>=2.1 jupyter jupyter-sphinx diff --git a/test/docs/IBMQuantum/Abbreviations.yml b/test/docs/IBMQuantum/Abbreviations.yml new file mode 100644 index 000000000..e7b85f235 --- /dev/null +++ b/test/docs/IBMQuantum/Abbreviations.yml @@ -0,0 +1,7 @@ +extends: existence +message: "Do not use periods in all-uppercase abbreviations such as '%s'." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#N100DC' +level: error +nonword: true +tokens: + - '\b(?:[A-Z]\.){3,5}' diff --git a/test/docs/IBMQuantum/DashSpacing.yml b/test/docs/IBMQuantum/DashSpacing.yml new file mode 100644 index 000000000..ea9a103b7 --- /dev/null +++ b/test/docs/IBMQuantum/DashSpacing.yml @@ -0,0 +1,13 @@ +extends: existence +message: "Add spaces around the dash in '%s'." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#N106BF' +ignorecase: true +nonword: true +level: error +action: + name: edit + params: + - remove + - ' ' +tokens: + - '[^\s][—–][^\s]' diff --git a/test/docs/IBMQuantum/Definitions.yml b/test/docs/IBMQuantum/Definitions.yml new file mode 100644 index 000000000..b60b88851 --- /dev/null +++ b/test/docs/IBMQuantum/Definitions.yml @@ -0,0 +1,69 @@ +extends: conditional +message: "Define acronyms and abbreviations (such as '%s') on first occurrence if they're likely to be unfamiliar." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#N100DC' +level: suggestion +ignorecase: false +# Ensures that the existence of 'first' implies the existence of 'second'. +first: '\b([A-Z]{3,5}s?)\b' +second: '\(([A-Z]{3,5}s?)\)' +# ... with the exception of these: +exceptions: + - API + - ASP + - CLI + - CPU + - CNOT + - CSS + - CSV + - DEBUG + - DOM + - DPI + - FAQ + - GCC + - GDB + - GET + - GPU + - GTK + - GUI + - HTML + - HTTP + - HTTPS + - IBM + - IDE + - JAR + - JSON + - JSX + - LESS + - LLDB + - NBQA + - NET + - NOTE + - NVDA + - OSS + - PATH + - PDF + - PHP + - POST + - QPU + - RAM + - REPL + - RSA + - SCM + - SCSS + - SDK + - SQL + - SSH + - SSL + - SVG + - SWAT + - TBD + - TCP + - TODO + - URI + - URL + - USB + - UTF + - XML + - XSS + - YAML + - ZIP diff --git a/test/docs/IBMQuantum/Headings.yml b/test/docs/IBMQuantum/Headings.yml new file mode 100644 index 000000000..cd0f4f770 --- /dev/null +++ b/test/docs/IBMQuantum/Headings.yml @@ -0,0 +1,28 @@ +extends: capitalization +message: "'%s' should use sentence-style capitalization." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#N1030C' +level: warning +scope: heading +match: $sentence +indicators: + - ':' + - '.' + - ')' +exceptions: + - API + - App ID + - IBM + - IBM Quantum + - Qiskit + - Runtime + - Sampler + - Estimator + - Terraform + - Trotter + - Grover + - Hamiltonian + - Hamiltonians + - Cloud + - Spectroscopic Eigensolver Algorithm + - Variational Quantum Eigensolver + - (\d+)\. diff --git a/test/docs/IBMQuantum/However.yml b/test/docs/IBMQuantum/However.yml new file mode 100644 index 000000000..e1322dc45 --- /dev/null +++ b/test/docs/IBMQuantum/However.yml @@ -0,0 +1,7 @@ +extends: existence +message: Double-check your punctuation around 'however' (see github.com/IBM/ibm-quantum-style-guide/issues/10 for more information). +level: suggestion +code: false +ignorecase: false +raw: + - ([^;,] however|however[^,]) diff --git a/test/docs/IBMQuantum/Latin.yml b/test/docs/IBMQuantum/Latin.yml new file mode 100644 index 000000000..b0d2b2b1c --- /dev/null +++ b/test/docs/IBMQuantum/Latin.yml @@ -0,0 +1,13 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#wordlist' +ignorecase: true +level: error +nonword: true +action: + name: replace +swap: + '\b(?:eg|e\.g\.)[\s,]': for example + '\b(?:ie|i\.e\.)[\s,]': that is + '\betc\.': and so on + '\bvs\.': versus diff --git a/test/docs/IBMQuantum/OxfordComma.yml b/test/docs/IBMQuantum/OxfordComma.yml new file mode 100644 index 000000000..6e7f76c7a --- /dev/null +++ b/test/docs/IBMQuantum/OxfordComma.yml @@ -0,0 +1,6 @@ +extends: existence +message: "Use the Oxford comma in '%s'." +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#N106BF' +level: suggestion +tokens: + - '(?:[^,]+,){1,}\s\w+\sand' diff --git a/test/docs/IBMQuantum/Politeness.yml b/test/docs/IBMQuantum/Politeness.yml new file mode 100644 index 000000000..43bf6975d --- /dev/null +++ b/test/docs/IBMQuantum/Politeness.yml @@ -0,0 +1,9 @@ +extends: existence +message: "Don't use '%s'" +link: 'https://github.com/IBM/ibm-quantum-style-guide/issues/16' +ignorecase: true +level: error +tokens: + - please + - thanks + - thank you diff --git a/test/docs/IBMQuantum/Repetition.yml b/test/docs/IBMQuantum/Repetition.yml new file mode 100644 index 000000000..102ebb3ce --- /dev/null +++ b/test/docs/IBMQuantum/Repetition.yml @@ -0,0 +1,6 @@ +extends: repetition +message: "'%s' is repeated!" +level: error +alpha: true +tokens: + - '[^\s]+' diff --git a/test/docs/IBMQuantum/Spelling.yml b/test/docs/IBMQuantum/Spelling.yml new file mode 100644 index 000000000..1dc1ad07a --- /dev/null +++ b/test/docs/IBMQuantum/Spelling.yml @@ -0,0 +1,5 @@ +extends: spelling +message: "Unknown word '%s'; fix or add to dictionary." +level: error +ignore: + - dictionary.txt diff --git a/test/docs/IBMQuantum/Terms.yml b/test/docs/IBMQuantum/Terms.yml new file mode 100644 index 000000000..77527dfeb --- /dev/null +++ b/test/docs/IBMQuantum/Terms.yml @@ -0,0 +1,184 @@ +extends: substitution +message: Use '%s' rather than '%s' +link: 'https://www.ibm.com/developerworks/library/styleguidelines/index.html#wordlist' +level: warning +ignorecase: true +action: + name: replace +# swap maps tokens in form of bad: good +swap: + '(?:Ctrl|control)-click': press Ctrl and click + 'a lot(?: of)?': many|much + 'backward(?:-)?compatible': compatible with earlier versions + 'down(?:-)?level': earlier|previous|not at the latest level + 'mash(?: )?up': create + 'pop-up (?:blocker|killer)': software to block pop-up ad windows + 're(?:-)?occur': recur + 'sort(?:-|/)?merge': sort|merge + 'do(?: )(?!not|so)': complete|perform + + bottom: end|last + below: following + above: previous + top: start|beginning|first + a number of: several + abort: cancel|stop + administrate: administer + all caps: uppercase + and/or: a or b|a, b, or both + as long as: if|provided that + as per: according to|as|as in + back-level: earlier|previous|not at the latest level + Big Blue: IBM + blink: flash + blue screen of death: stop error + breadcrumbing: breadcrumb trail + canned: preplanned|preconfigured|predefined + case insensitive: not case-sensitive + catastrophic error: unrecoverable error + CBE: Common Base Event + CBTS: CICS BTS|BTS + cold boot: hardware restart + cold start: hardware restart + comes with: includes + componentization: component-based development|component model|component architecture|shared components + componentize: develop components + comprised of: consist of + connect with: connect to + context menu: menu|pop-up menu + contextual help: help|context-sensitive help + crash: fail|lock up|stop|stop responding + CRUD: create retrieve update and delete + customer: client + datum: data + debuggable: debug + deconfigure: unconfigure + deinstall: uninstall + deinstallation: uninstallation + demilitarized zone: DMZ + demo: demonstration + depress: press|type + deregister: unregister + desire: want|required + destroy: delete from the database + dismount: demount|unmount|remove + downgrade: upgrade|fallback|fall back|rollback|roll back + downward compatible: compatible with earlier versions + drag and drop: drag + drill up: navigate + e-fix: fix|interim fix + eFix: fix|interim fix + end user: user + end-user interface: graphical interface|interface + EUI: graphical user interface|interface + expose: display|show|make available + fill in: complete|enter|specify + fixed disk drive: hard disk drive + flavor: version|method + floppy disk: diskette|diskette drive + floppy drive: diskette|diskette drive + floppy: diskette|diskette drive + forward compatible: compatible with later versions + gzip: compress + gzipped: archive|compressed file + hard drive: hard disk|hard disk drive + hard file: hard disk|hard disk drive + hence: therefore + i-fix: interim fix + i-Fix: interim fix + IBM's: IBM's|IBM's AIX + ifix: interim fix + iFix: interim fix + in order to: to + in other words: for example|that is + in spite of: regardless of|despite + in the event: in case|if|when + inactivate: deactivate + information on: information about + information technology: IT + instead of: rather than + insure: ensure + Internet address: IP address|URL|Internet email address|web address + irrecoverable: unrecoverable + jar: compress|archive + keep in mind: remember + launch: start|open + left-hand: left + leverage: use + line cord: power cable|power cord + main directory: root directory + memory stick: USB flash drive + microcomputer: PC + motherboard: system board + mouse over: point to|move the mouse pointer over|Mouse|mouse over + network-centric computing: network computing + non-English: in languages other than English|non-English-language + nonrecoverable: unrecoverable + notion: concept + off-premise: on-premises|off-premises|onsite|offsite + offline storage: auxiliary storage + okay: OK + on ramp: access method + on the fly: dynamically|as needed|in real time|immediately + on the other hand: however|alternatively|conversely + on-premise: on-premises|off-premises|onsite|offsite + on-ramp: access method + pain point: challenge|concern|difficulty|issue + parent task: parent process + patch: fix|test fix|interim fix|fix pack|program temporary fix + perimeter network: DMZ + power down: turn on|turn off + power off: turn on|turn off + power on: turn on|turn off + preload: preinstall|preinstalled + preloaded: preinstall|preinstalled + prepend: add a prefix to + prior to: before + recommend: suggest + retry: retry|try again + right double-click: double right-click + right-hand: right + rule of thumb: rule + sanity check: test|evaluate + secondary storage: auxiliary storage + selection button: left mouse button + serial database: nonpartitioned database environment + shift-click: press Shift and click + ship: include|included + Simple Object Access Protocol: SOAP + single quote mark: single quotation mark + single quote: single quotation mark + SME routine: session management exit routine + start up: start + sunset: withdraw from service|withdraw from marketing|discontinue|no longer support + switch off: power on|turn on|power off|turn off + switch on: power on|turn on|power off|turn off + tar: compress|archive + tarball: tar file + terminate: end|stop + thru: through + thumbstick: USB flash drive + thus: therefore + toggle off: toggle + tooling: tools + touchscreen: touch-sensitive screen + transition: make the transition|move|migrate|change + transparent: indiscernible|not visible + typo: typing error|typographical error + uncheck: clear + uncompress: decompress + undeploy: remove|withdraw + unjar: extract + unselect: clear|deselect + untar: extract + unzip: unzip + upward compatible: compatible with later versions + utilize: use + versus: compared to + via: through + warning notice: attention notice + web-enable: enable for the web + webinar: webinar|webcast|web seminar|web-based event + wish: want + zero out: zero + zip: zip|compress diff --git a/test/docs/dictionary.txt b/test/docs/dictionary.txt new file mode 100644 index 000000000..81c20c11b --- /dev/null +++ b/test/docs/dictionary.txt @@ -0,0 +1,245 @@ +Abelian +Abhinav +Aer +Akira +Amyra +Andersson +Andriyash +Aroosa +Arunachalam +Asfaw +Auditability +Babbush +Barowski +Bello +Bengio +Bergholm +Bernagozzi +Bertels +Bertet +Boeblingen +Boixo +Boulant +Briegel +Broughton +Brukner +Bucher +CNOTs +Carleo +Carrera +Cerezo +Chuang +Cincio +Clauser +Colbeck +Corcoles +Courville +Derks +Deutsch +Deutschle +Dewes +Dunjko +Elies +Esteve +Faehrmann +Farhi +Fock +Francesco +Fredkin +Gacon +Garey +Glick +Goemans +Gogolin +Goodfellow +Greenberger +Griffiths +Gutmann +Hadamard +Haide +Hamiltonian +Hamiltonians +Harkins +Hartmut +Hartree +Havlicek +Hellinger +Hindy +Hiptmair +Hoyer +Hubregtsen +Ijaz +Iten +Izaac +Jakob +Jozsa +Jurcevic +Kandala +Keras +Killoran +Kitaev +Koen +Kohli +Kristan +Kulchytskyy +Kus +Lauro +Leib +Litinski +Liu +Lorenza +Lucchi +Lukasz +Maika +Markus +Masoud +Melko +Mezzacapo +Minev +Mohseni +Mondada +Mosca +Mueggenburg +Neven +Ong +Opflow +Osodo +Ozair +Peruzzo +Petar +Petruccione +Pichlmeier +Plesch +QPUs +Qiskit's +Ravi +Revview +Rivero +Rolfe +Runtime's +Schmitt +Schroeter +Schuld +Schwarz +Shadbolt +Shen +Shende +Shewchuk +Shimony +Shor's +Simulatable +Smelyanskiy +Srinivasan +Stamatopoulos +Steenken +Stephane +Streif +Sukin +Takita +Tanvi +Tapp +Technol +Temme +Toeplitz +Toffoli +Tommaso +Trackerservice +Trotterization +Trotterize +Trotterizing +Vadim +Vedran +Ville +Vion +Vivek +Vojtech +Volkoff +Weedbrook +Wierichs +Woerner +Wootton +Youngseok +Yousef +Yunchao +Yung +Zeilinger +Zeng +Zhou +Zoufal +addon +anharmonic +ansatz +ansatzes +arXiv +autoencoder +autoencoders +backend's +bilinearity +bitstring +bool +colocated +coprime +decohere +disproven +doi +ebit +eigenbasis +eigensolver +eigensolvers +eigenstate +eigenstates +endian +exponentials +expressibility +fanout +fermionic +fidelities +hyperparameter +hyperparameters +ket +kets +minimax +misclassifying +multilinear +namespace +nucleobase +orthogonalization +orthonormality +parameterization +polynomially +preprint +priori +pseudocode +qiskit +quantizing +quasiprobabilities +quasiprobability +qubit +qubit's +qubits +qudit +qutrits +recalibrated +reuploading +satisfiability +simulability +subfield +subfields +subscripting +substring +substrings +sudoku +summand +summands +tooltip +tooltips +transmon +transpilation +transpile +transpiled +transpiler +transpiler's +transpiling +tridiagonal +trits +unitaries diff --git a/test/docs/vale.sh b/test/docs/vale.sh new file mode 100755 index 000000000..f4bd36416 --- /dev/null +++ b/test/docs/vale.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cd ./docs + +vale . + +echo +echo "Linting notebooks using nbQA:" + +notebooks=$(find . -name "*.ipynb" -not -name "*checkpoint*" -not -path "./_**") + +python -m nbqa vale ${notebooks} --nbqa-shell --nbqa-md