diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 934e6e216..88124ce1b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,26 +28,3 @@ jobs: encrypted_rclone_iv: ${{ secrets.encrypted_rclone_iv }} run: | tools/deploy_documentation.sh - deploy-translatable-strings: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.9.12' - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install jupyter sphinx_rtd_theme qiskit-terra[visualization] 'torchvision<0.10.0' tox - sudo apt-get install -y graphviz pandoc - - name: Build and publish - env: - encrypted_deploy_po_branch_key: ${{ secrets.encrypted_deploy_po_branch_key }} - encrypted_deploy_po_branch_iv: ${{ secrets.encrypted_deploy_po_branch_iv }} - QISKIT_PARALLEL: False - QISKIT_DOCS_BUILD_TUTORIALS: 'always' - run: | - tools/deploy_translatable_strings.sh diff --git a/Makefile b/Makefile index 3cd601802..b1a2db46a 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ mypy: mypy --module qiskit_ibm_runtime --package test style: - black --check qiskit_ibm_runtime setup.py test docs/tutorials program_source + black --check qiskit_ibm_runtime setup.py test docs/tutorials unit-test: python -m unittest discover --verbose --top-level-directory . --start-directory test/unit @@ -40,4 +40,4 @@ unit-test-coverage: coverage lcov black: - black qiskit_ibm_runtime setup.py test docs/tutorials program_source \ No newline at end of file + black qiskit_ibm_runtime setup.py test docs/tutorials \ No newline at end of file diff --git a/docs/_templates/theme_variables.jinja b/docs/_templates/theme_variables.jinja deleted file mode 100644 index 0c272af50..000000000 --- a/docs/_templates/theme_variables.jinja +++ /dev/null @@ -1,26 +0,0 @@ -{%- set external_urls = { - 'github': 'https://github.com/Qiskit/qiskit-ibm-runtime', - 'github_issues': 'https://github.com/Qiskit/qiskit-ibm-runtime/issues', - 'contributing': 'https://github.com/Qiskit/qiskit/blob/master/CONTRIBUTING.md', - 'docs': 'https://qiskit.org/documentation/', - 'api': 'https://runtime-us-east.quantum-computing.ibm.com/openapi/', - 'ml': 'https://qiskit.org/documentation/machine-learning/', - 'nature': 'https://qiskit.org/documentation/nature/', - 'finance': 'https://qiskit.org/documentation/finance/', - 'optim': 'https://qiskit.org/documentation/optimization/', - 'experiments': 'https://qiskit.org/documentation/experiments/', - 'partners': 'https://qiskit.org/documentation/partners/', - 'twitter': 'https://twitter.com/qiskit', - 'events': 'https://qiskit.org/events', - 'textbook': 'https://qiskit.org/textbook', - 'slack': 'https://qiskit.slack.com', - 'home': 'https://qiskit.org/', - 'blog': 'https://pytorch.org/blog/', - 'resources': 'https://qiskit.org/learn', - 'support': 'https://pytorch.org/support', - 'youtube': 'https://www.youtube.com/qiskit', - 'iqx': 'https://quantum-computing.ibm.com/', - 'iqx_systems': 'https://quantum-computing.ibm.com/docs/manage/backends/', - 'ibm': 'https://www.ibm.com/quantum-computing/', -} --%} diff --git a/docs/cloud/architecture-workload-isolation.rst b/docs/cloud/architecture-workload-isolation.rst deleted file mode 100644 index 2b64de908..000000000 --- a/docs/cloud/architecture-workload-isolation.rst +++ /dev/null @@ -1,15 +0,0 @@ -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 ---------------------------------------- - -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. -User access to Qiskit Runtime service instances can be configured through different mechanisms: -- Resource groups can be used to group service instances. This lets you manage access permissions based on resource group assignment. -- Access groups can be used to assign access to individual service instances. Service IDs (with their API keys) can be assigned to these access groups. -- IAM tags can be used to categorize service instances and use these tags through access groups. diff --git a/docs/cloud/at-events.rst b/docs/cloud/at-events.rst deleted file mode 100644 index b5839ed0a..000000000 --- a/docs/cloud/at-events.rst +++ /dev/null @@ -1,38 +0,0 @@ -Audit events for Qiskit Runtime -=============================== - -As a security officer, auditor, or manager, you can use the IBM Cloud® Activity Tracker service to track how users and applications interact with the Qiskit Runtime service in IBM Cloud. - -IBM Cloud Activity Tracker records user-initiated activities that change the state of a service in IBM Cloud. You can use this service to investigate abnormal activity and critical actions and to comply with regulatory audit requirements. In addition, you can be alerted about actions as they happen. The events that are collected comply with the Cloud Auditing Data Federation (CADF) standard. For more information, see the `getting started tutorial for IBM Cloud Activity Tracker `__. - -List of data events -------------------- - -The following table lists the Qiskit Runtime actions that generate an event: - -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| Action | Description | -+======================================+=================================================================================================================================================+ -| ``quantum-computing.program.create`` | An event is generated a program is uploaded. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.program.read`` | An event is generated when program information is returned. For example, when you list programs or program details. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.program.delete`` | An event is generated when a program is deleted. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.program.update`` | An event is generated when a program metadata is updated. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.job.create`` | An event is generated when a job is started. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.job.read`` | An event is generated when job information is returned. This includes listing jobs, job details, job results, job interim results, or job logs. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.job.delete`` | An event is generated when a job is deleted. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``quantum-computing.job.cancel`` | An event is generated when a job is cancelled. | -+--------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ - -Viewing events --------------- - -Events that are generated by an instance of the *YourServiceName* service are automatically forwarded to the IBM Cloud Activity Trackerservice instance that is available in the same location. - -IBM Cloud Activity Tracker can have only one instance per location. To view events, you must access the web UI of the IBM Cloud Activity Tracker service in the same location where your service instance is available. For more information, see `Launching the UI `__. \ No newline at end of file diff --git a/docs/cloud/cloud-provider-org.rst b/docs/cloud/cloud-provider-org.rst deleted file mode 100644 index 19668c356..000000000 --- a/docs/cloud/cloud-provider-org.rst +++ /dev/null @@ -1,370 +0,0 @@ -Manage users -====================== - -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` -* :ref:`provider-appid` - -.. _cloud-users: - -Manage IBM Cloud users ----------------------- - -This tutorial shows how to use IBM Cloud to enable users who have IBM Cloud accounts and gives instructions for users to access the environment. - - -Invite users -~~~~~~~~~~~~~ - -1. Ensure that the users that you want to invite have IBM Cloud accounts. - -2. Go to Manage → Access (IAM) and click `Invite users `__. - -3. Enter the email addresses of users to be added. - -4. Select the access group or groups of the projects that the users will be part of. These assignments can be changed later. - -5. Click Add to confirm the access group selection. - -6. Click Invite to send the invitation to the users. - - .. note:: - Users cannot be managed until they accept the invitation and log in at least once. - -Optional: Modify users’ project assignments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Go to `Manage → Access (IAM) → Users `__ and click the user. - - |change1| - -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 -~~~~~~~~~~~~~ - -1. After they accept an invitation, users can log in through the `IBM Cloud portal `__. -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 `__. - -Example scenario -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In our example, we want to create the following setup: - -- We have two projects, ``ml`` and ``finance``. - - - The ``ml`` project should have access to the service instances ``QR-ml`` and ``QR-common``. - - The ``finance`` project should have access to the service instances ``QR-finance`` and ``QR-common``. - -- We have three users: - - - Fatima should have access to the ``ml`` project. - - Ravi should have access to the ``finance`` project. - - Amyra should have access to both projects. - -- We will use access groups without resource groups. -- Users are defined in IBM Cloud and project assignments are done there as well. -- Users should be able to delete jobs. - -The steps to implement this setup are: - -2. The Cloud administrator creates three service instances: ``QR-ml``, ``QR finance``, and ``QR-common``. -3. The Cloud administrator creates a custom rule that includes the ``quantum-computing.job.delete`` action. -4. The Cloud administrator creates two access groups: - - - The ``ml`` access group can access ``QR-ml`` and ``QR-common``. - - The ``finance`` access group can access ``QR-finance`` and ``QR-common``. - -5. The Cloud administrator invites cloud users to the appropriate project. Specifically, they invite and assign users to an access group that includes the project. - - - Fatima is added to the “ml” access group. - - Ravi is added to the “finance” access group. - - Amyra is added to both the “ml” and “finance” access groups. - -6. Users can log in through the IBM Cloud portal, create API keys, and work with their projects’ service instances. - -.. _provider-cloud: - -Manage ID provider users with IBM Cloud -------------------------------------------- - -App ID creates an ID provider so you can add users directly in App ID or connect to other external ID providers. This tutorial describes how to set up your ID provider to work with IBM Cloud users, and gives instructions for users to access the environment. - - -Create an App ID instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. `Open App ID from the IBM Cloud catalog `__ and log in if necessary. Specify the following values: - - - For **Select a location**, it is recommended that you keep it in the same location as the Qiskit Runtime service, which is ``Washington DC (us-east)``. - - **Select a pricing plan**: - - - The **Lite** plan is free of charge and is enough to get started. If needed, you can seamlessly upgrade to the graduated tier later. - - The **Graduated tier** is paid per event and per user beyond the lite tier limits. This tier supports more features such as multi-factor authentication. The Cloud administrator as the owning account of the App ID instance is charged for any fees for the graduated tier instances. - - - Complete the values for **Service name** (the App ID instance name), **Resource group** (if one is being used), and any tags you want. - - |create1| - -2. Read and agree to the terms and click **Create**. - -Configure the ID provider -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We will use the **Cloud Directory** capability to add users to the ID provider. Refer to the `App ID documentation `__ for instructions how to integrate other ID providers into App ID. - -1. Open the `IBM Cloud resource list `__, expand the **Services and software** section, find your App ID instance and click its name to view its details. -2. Click **Manage Authentication** and deselect any login options that you don’t need, such as Facebook and Google. -3. Go to **Manage Authentication** → **Cloud Directory** → **Settings** and choose whether user logins should use email or usernames. -4. Optionally go to **Manage Authentication** → **Cloud Directory** → **Password Policies** to define the password strength. -5. Optionally open **Login Customization** and customize the appearance of the login page. - -Integrate the App ID instance as the ID provider for the administrator’s account -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Go to `Manage → Access (IAM) → Identity Providers `__. For **Type**, choose **IBM Cloud App ID**, then click **Create**. - -2. Specify a name and select the App ID instance from the drop-down list. - -3. Select the checkbox to enable the ID provider. - - |identity1| - -4. The default IdP URL is shown. Share this URL with users when they need to log in. - -Add users -~~~~~~~~~~ - -When you use App ID as ID provider with the Cloud directory, you can create users in the IBM Cloud user interface. - -1. Open the App ID instance page from the `resource list `__ Services and software section. -2. Go to **Manage Authentication** → **Cloud Directory** → **Users**, and click **Create User**. Enter the user details. - -Create or modify users’ project assignments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Go to `Manage → Access (IAM) → Users `__ and click the user. - - |access1| - - .. note:: - If you don’t see the user that you want to manage, verify that they logged in to IBM Cloud at least once. See step 1 in the :ref:`user-org`. - -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-org: - -User flow -~~~~~~~~~~~~ - -1. A user is sent the ID provider URL for the IBM Cloud account. They use this URL and the login information to access the system. The user should change their password after they log on. - - .. 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 and access service instances, users need to create an API key from `Manage → Access (IAM) → API keys `__. - -3. For further information, users can review `Getting started, Step 2 `__. - -Example scenario -~~~~~~~~~~~~~~~~ - -In our example, we want to create the following setup: - -- We have two projects, ``ml`` and ``finance``. - - - The ``ml`` project needs access to the service instances ``QR-ml`` and ``QR-common``. - - The ``finance`` project should have access to the service instances ``QR-finance`` and ``QR-common``. - -- We have three users: - - - Fatima needs access to the ``ml`` project. - - Ravi needs access to the ``finance`` project. - - Amyra needs access to both projects. - -- We will use access groups without resource groups. -- Users are defined in IBM Cloud but project assignments are done in an App ID instance. -- Users should be able to delete jobs. - -The steps to implement this setup are: - -1. The Cloud administrator creates an App ID instance and ensures that it is linked in the Cloud administrator’s account. The administrator notes the ID provider URL to share it with users. -2. The Cloud administrator creates three service instances: ``QR-ml``, ``QR finance``, and ``QR-common``. -3. The Cloud administrator creates a custom rule that includes the ``quantum-computing.job.delete`` action. -4. The Cloud administrator creates two access groups: - - - The ``ml`` access group can access ``QR-ml`` and ``QR-common``. This access group needs a dynamic rule for the App ID IDP that accepts users whose ``project`` attribute contains ``ml``. - - The ``finance`` access group can access ``QR-finance`` and ``QR-common``. This access group nees a dynamic rule for the App ID IDP that accepts users whose ``project`` attribute contains ``finance``. - -5. The ID provider administrator defines the three users in the IBM Cloud user interface. -6. Users log in at least once. -7. The cloud administrator assigns access by adding users to the access groups that give them access to the projects: - - - Fatima is given access to the ``ml`` project. - - Ravi is given access to the ``finance`` project. - - Amyra is given access to the ``ml`` and ``finanace`` projects. - -8. Users can log in through the ID provider URL, create API keys, and work with their projects’ service instances. - -.. _provider-appid: - -Manage ID provider users with the ID provider ------------------------------------------------ - -App ID creates an ID provider so you can add users directly in App ID or connect to other external ID providers. This tutorial describes how to set up your ID provider to work with users that do not have IBM Cloud accounts. - - -Create an App ID instance -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. `Open App ID from the IBM Cloud catalog `__ and log in. Specify the following values: - - - For **Select a location**, it is recommended to keep it in the same location as the Qiskit Runtime service, which is ``Washington DC (us-east)``. - - **Select a pricing plan**: - - - The **Lite** plan is free of charge and is enough to get started. If needed, you can seamlessly upgrade to the graduated tier later. - - The **Graduated tier** is paid per event and per user beyond the Lite tier limits. This tier supports more features such as multi-factor authentication. The Cloud administrator as the owning account of the App ID instance is charged for any costs for the graduated tier instances. - - - Complete the values for **Service name** (the App ID instance name), **Resource group** (if one is being used), and any tags you want. - - |create| - -2. Read and agree to the terms and click **Create**. - -Configure the ID provider -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We will use the **Cloud Directory** capability to add users to the ID provider. Refer to the `App ID documentation `__ for instructions how to integrate other ID providers into App ID. - -1. Open the `IBM Cloud resource list `__, expand the **Services and software** section, find your App ID instance and click its name to view its details. -2. Click **Manage Authentication** and deselect any login options that you don’t need, such as Facebook and Google. -3. Navigate to **Manage Authentication** → **Cloud Directory** → **Settings** and choose whether user logins should use email or usernames. -4. Optional: Open **Manage Authentication** → **Cloud Directory** → **Password Policies** to define the password strength. -5. Optionally open **Login Customization** and customize the appearance of the login page. - -Integrate the App ID instance as the ID provider for the administrator’s account -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Go to `Manage → Access (IAM) → Identity Providers `__. For **Type**, choose **IBM Cloud App ID**, then click **Create**. - -2. Specify a name and select the App ID instance from the drop-down list. - -3. Select the checkbox to enable the ID provider. - - |identity| - -4. The default IdP URL is shown. Share this URL with users when they need to log in. - -Add a dynamic rule to the access group -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The access group needs a dynamic rule to test whether it should be applied to an IDP user when they log in. - -Because the dynamic rules are evaluated during login, any changes are picked up the next time the user logs in. {: note} - -1. Navigate to `Manage → IAM → Access groups `__ and click your access group to open its details page. -2. Click the **Dynamic rules** tab, then click **Add**. - - - Provide a name. - - For the Authentication method, choose **Users federated by IBM Cloud AppID**, then select the IDP from the Identity provider drop-down list. - - |Dynamic| -3. Click **Add a condition**, complete the following values, then click **Add**. - - - In the **Allow users when** field, enter the attribute key that is used by the IDP administrator in the ID provider user attributes, such as ``project`` (this string is a convention that is defined during planning). - - Select **Contains** as the **Qualifier**. - - In **Values**, enter the value, such as ``ml``. This is the same value that the IDP administrator uses in the IDP user profile definition. It is typically the project name. - - You might want to increase the **Session duration** to increase the period before users must log back in. Logged-in users keep their access group membership for that period, and reevaluation takes place on the next login. - - |Condition| - -Add users -~~~~~~~~~~~~~~~ - -When you use App ID as ID provider with the Cloud directory, you can create users in the Cloud user interface. - -1. Open the App ID instance page from the `resource list `__ Services and software section. -2. Go to **Manage Authentication** → **Cloud Directory** → **Users**, and click **Create User**. Enter the user details. - -Create or modify users’ project assignments -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -If the IDP administrator will assign users to projects, you can define project values in the user’s attributes. - -1. Open the App ID instance page from the `resource list `__ Services and software section. - -2. Go to **Manage Authentication** → **Cloud Directory** → **Users**, and click a user to open it. - -3. Scroll down to **Custom Attributes**, and click **Edit**. - -4. Enter a key value pair that can will checked by the dynamic rules of the access groups, then click **Save**. You can add several values in the same string (for example, ``{"project":"ml finance"}``); the **contains** qualifier of the dynamic rule detects a match of a substring. For our example, add ``{"project":"ml"}``. - - The value ``project`` corresponds to the convention defined in the planning section. ``ml`` is the project that the user belongs to. - - This check is done on every login, so changes in the ID provider user attributes will be effective when a user next logs in. - -User flow -~~~~~~~~~~~ - -1. A user is sent the ID provider URL for the IBM Cloud account. - - .. 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 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 `__. - -Example scenario -~~~~~~~~~~~~~~~~ - -In our example, we want to create the following setup: - -- We have two projects, ``ml`` and ``finance``. - - - The ``ml`` project needs access to the service instances ``QR-ml`` and ``QR-common``. - - The ``finance`` project needs access to the service instances ``QR-finance`` and ``QR-common``. - -- We have three users: - - - Fatima needs access to the ``ml`` project. - - Ravi needs access to the ``finance`` project. - - Amyra needs access to both projects. - -- We will use access groups without resource groups. -- Users are defined in an App ID instance and project assignments are also done there. -- Users should be able to delete jobs. - -The steps to implement this setup are: - -1. The Cloud administrator creates an App ID instance and ensures that it is linked in the Cloud administrator’s account. The administrator notes the ID provider URL to share it with users. -2. The Cloud administrator creates three service instances: ``QR-ml``, ``QR finance``, and ``QR-common``. -3. The Cloud administrator creates a custom rule that includes the ``quantum-computing.job.delete`` action. -4. The Cloud administrator creates two access groups: - - - The ``ml`` access group can access ``QR-ml`` and ``QR-common``. This access group needs a dynamic rule for the App ID IDP that accepts users whose ``project`` attribute contains ``ml``. - - The ``finance`` access group can access ``QR-finance`` and ``QR-common``. This access group needs a dynamic rule for the App ID IDP that accepts users whose ``project`` attribute contains ``finance``. - -5. The IDP administrator uses the App ID instance that the Cloud administrator created and defines the three users: - - - For Fatima, the custom attributes contain ``{"project":"ml"}``. - - For Ravi, the custom attributes contain ``{"project":"finance"}``. - - For Amyra, the custom attributes contain ``{"project":"ml finance"}``. - -6. Users can log in through the ID provider URL, create API keys, and work with their projects’ service instances. - - -Next steps ----------- - -.. |create1| image:: ../images/org-guide-create-appid.png -.. |identity1| image:: ../images/org-guide-idp-reference.png -.. |access1| image:: ../images/org-guide-manage-user.png -.. |change1| image:: ../images/org-guide-manage-user.png -.. |create| image:: ../images/org-guide-create-appid.png -.. |identity| image:: ../images/org-guide-idp-reference.png -.. |Dynamic| image:: ../images/org-guide-create-dynamic-rule1.png -.. |Condition| image:: ../images/org-guide-create-dynamic-rule2.png diff --git a/docs/cloud/cost.rst b/docs/cloud/cost.rst deleted file mode 100644 index b313daa53..000000000 --- a/docs/cloud/cost.rst +++ /dev/null @@ -1,80 +0,0 @@ -Manage costs -############ - -The Standard plan is not free, except when running jobs on simulators. Use the information in this topic to help you understand how much you’re paying and how to limit your costs. - -Time limits on programs -*********************** - -The maximum execution time for the Sampler primitive is 10000 seconds (2.78 hours). The maximum execution time for the Estimator primitive is 18000 seconds (5 hours). - -Additionally, the system limit on the system execution time is 3 hours for a job that is running on a simulator and 8 hours for a job running on a physical system. - -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. 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. - -.. note:: - The cost limit is always specified in US dollars (USD), then converted to runtime seconds. However, for monthly billing purposes, you are charged in your local currency, specified on your IBM Cloud account. Because currency exchange rates can fluctuate, the cost for `X` runtime seconds might be different when initially calculated in USD than when you're actually charged in your local currency. As a result, if your local currency is not USD, the total amount charged for the number of seconds specified in this field could vary from the dollar amount you specify. - -How to remove a cost limit -**************************** - -An instance administrator can remove the cost limit. To do so, navigate to the `IBM Cloud Instances page `__, then open the instance and click the edit button by the **Cost limit**. Delete the value and click **Save**. - -What happens when the cost limit is reached -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -When the instance's cost limit is reached, the currently running job is stopped. Its status is set to `Cancelled` with a reason of `Ran too long`. Any available partial results are kept. - -No further jobs can be submitted by using this instance until the cost limit is increased. - - -How to see what you’re being charged -************************************* - -You are sent a monthly invoice that provides details about your resource charges. You can check how much has been spent at any time on the `IBM Cloud Billing and usage page `__. - -Additionally, you can determine cost per instance or per job at any time. - -View instance cost -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To determine how much has been billed to an instance during the current billing cycle, from the `Instances page `__, click the instance to open its details page. - -These are the fields relevant to cost: - -- **Billing cycle usage**: Qiskit Runtime usage by this instance during the current billing cycle. This usage is the time counted by Qiskit Runtime to process a job, and is determined by the use of internal resources. -- **Billing cycle cost**: The total cost of running jobs during the current billing cycle. -- **Total usage**: Qiskit Runtime usage by this instance since it was created. -- **Total cost**: The total cost of running jobs on this instance since it was created (only administrators can set this value). - -You can view your billing cycle on the `Billing and usage page `__. - -View job cost -~~~~~~~~~~~~~~~~ - -To determine how much has been billed to each job associated with an instance, from the `Instances page `__, click the instance to open its details page. Next, on the left side, click Jobs. - -These are the columns relevant to cost: - -- **Usage**: Qiskit Runtime used by this job. This usage is the time counted by Qiskit Runtime to process a job, and is determined by the use of internal resources. -- **Cost**: The total cost of running this job - - -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. 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 -****************** - -See `Qiskit Runtime plans `__ to learn about the plans. diff --git a/docs/cloud/data-security.rst b/docs/cloud/data-security.rst deleted file mode 100644 index 2fa4d5fbe..000000000 --- a/docs/cloud/data-security.rst +++ /dev/null @@ -1,21 +0,0 @@ -Securing your data in Qiskit Runtime -==================================== - -To ensure that you can securely manage your data when you use Qiskit Runtime, it is important to know exactly what data is stored and encrypted and how you can delete any stored data. - - -Protecting your sensitive data in Qiskit Runtime ------------------------------------------------- - -The data that you store in IBM Cloud is encrypted at rest by using a randomly generated key. - - -Deleting your data in Qiskit Runtime ------------------------------------- - -Deleting a service instance removes all of the content associated with that instance, such as your jobs, results, parameters, and programs. To delete an instance, from the `Instances page `__, find the instance you want to remove, click its overflow menu, then click **Delete**. You will be asked to confirm the deletion. - -Deleting Qiskit Runtime instances -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The Qiskit Runtime data retention policy describes how long your data is stored after you delete the service. The data retention policy is included in the Qiskit Runtime service description, which you can find in the `IBM Cloud Terms `__. diff --git a/docs/cloud/plans.rst b/docs/cloud/plans.rst deleted file mode 100644 index bb071dd3c..000000000 --- a/docs/cloud/plans.rst +++ /dev/null @@ -1,59 +0,0 @@ -Qiskit Runtime plans -==================== - -The Qiskit Runtime service offers these plans for running quantum programs: - -- Lite Plan: Simulator access plan (free) -- Standard Plan: Quantum hardware and simulator access plan - -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. - - - **Type**: General, context-aware - - **Simulated 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. - - - **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. - - - **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. - - - **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. - - - **Type**: Extended Clifford (for example, Clifford+T) - - **Simulated Qubits**: 63 - -Standard plan -------------- - -A pay-as-you-go plan for accessing IBM Quantum systems. Build your own programs and access all the benefits of Qiskit Runtime by running on real quantum hardware, while maintaining access to all of the simulators available in the Lite plan. - -Pricing overview ----------------- - -The Lite plan is free. The Standard plan charges you per *QR second* when running on physical systems. The following diagram illustrates what is included in a QR second. Any time spent waiting for results or in the queue for the quantum computer are excluded. - -.. figure:: ../images/Runtime_Accounting_Diagram.png - :alt: This diagram shows that everything before the program starts (such as queuing) is free. After the job starts, it costs $1.60 per second. - - -Qiskit Runtime usage is the time counted by Qiskit Runtime to process a job, and is determined by the use of internal resources. - -Next steps ----------- - -See `Manage costs `__ to learn how to determine and minimize your costs. - diff --git a/docs/cloud/quickstart-org.rst b/docs/cloud/quickstart-org.rst deleted file mode 100644 index 9d51362b8..000000000 --- a/docs/cloud/quickstart-org.rst +++ /dev/null @@ -1,117 +0,0 @@ -Plan Qiskit Runtime for an organization -======================================= - -In an organization where individuals might work on several projects, Qiskit Runtime governance can seem complex. However, access management can be used to easily enable user collaboration and to restrict visibility of users and projects when necessary. Managing access becomes more relevant with Qiskit Runtime resources that are not free: that is, Qiskit Runtime service instances that use the Standard plan (which organizations are charged for). - -Overview --------- - -.. note:: - - 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 -~~~~~~~~~~~~~~~~~ - -The are several main personas that are mentioned in this tutorial: - -- **User**: Someone who gets access to Qiskit Runtime resources (*service instances*) and can potentially collaborate with other users on these resources. Users’ access is controlled by an administrator and they cannot create or delete service instances. -- **Cloud administrator**: An IBM Cloud account owner who owns Qiskit Runtime resources and manages which users can access these resources. As the resource owner, the administrator is charged for any paid resource use. -- **IDP administrator**: An administrator who defines identities and their attributes in an identity provider (IDP). - -Terminology -~~~~~~~~~~~ - -This tutorial uses the following terms: - -- *Resource*: A generic IBM Cloud term that refers to an object that can be managed through the Cloud user interface, CLI, or API. For this tutorial, a *resource* is a Qiskit Runtime service instance. - -- *Service instance*: A service instance is used to access Cloud functions. Specifically, quantum computing on real devices or simulators. It is defined through the catalog. You can define several service instances based on the same or different plans, which offer access to different quantum computing backends. See `Qiskit Runtime plans `__ for more details. - -- *Project*: A grouping unit that enables users to work on the same resources. This tutorial uses two projects; ``ml`` and ``finance``. See `Hierarchical project structures `__ for more information. - - .. note:: - - This project is not related to the “project” concept in IBM Quantum Platform. - -Decisions ---------------- - -Before you set up Qiskit Runtime for your organization, you need to make these decisions: - -- How are user identities defined? You can set up IBM Cloud users, users from another IDP, or both. - - - If you are using a different IDP, does the Cloud administrator or the IDP administrator assign users to project resources? - - If the IDP administrator assigns users to projects, you need a string to be used as a key, such as ``project`` (which this tutorial uses) for project comparisons. - -- What are the projects and which service instances will belong to each? You must plan your project names carefully. - - - Do not make project names substrings of another. For example, if you use ``ml`` and ``chemlab`` for project names, then later you set up a project match for ``ml``, it triggers on both values, accidentally granting more access than expected. Instead, use unique names such as ``ml`` and ``chem-lab``. Alternatively, use prefix or suffix values to avoid such unintended substring matches. - - Using naming conventions, along with prefix or suffix values can help you easily allow access to several projects. - - Quantum experiments (jobs) belong to service instances, and users that have access to an instance can see its jobs. - - Service instances can be based on different plans, allowing access to different backends like real devices or simulators. See `Choose a system or simulator <../how_to/choose-system.html>`__ for details. - -- Which users need to access which projects? -- Should users be able to delete jobs? Keeping jobs in service instances gives more traceability for billing costs. This information combines well with the audit trail of `Activity Tracker `__, which tracks which user submitted the job. -- Will you use access groups that directly reference Qiskit Runtime service instances or organize services into resource groups? - - - **Access groups** are a convenient and common way of controlling user access for IBM Cloud resources. They are a simple but powerful means to consistently assign user access. We create an access group for each project and map users to access groups. Each access group uses a custom role that allows users to access specific Qiskit Runtime service instances or resource groups. - - **Resource groups** are used only when you need to maintain a clear separation of service instances. If more service instances are created in a resource group, all users that have access to the resource group see them automatically without updating access groups. If you choose to use resource groups, you will create access groups and then assign them to resource groups. - - .. note:: - - A service instance can belong to only one resource group, and after instances are assigned into resource groups, they cannot be changed. This also means that the resource group assignment can happen only at service instance creation. Therefore, resource groups might not provide enough flexibility if assignments of service instances to resource groups might need to change. - -Considerations ----------------- - -You should understand the following considerations when setting up your environment. - -Auditability -~~~~~~~~~~~~~ - -Activity tracker logs significant actions performed on Qiskit Runtime service instances. Create an instance of Activity Tracker in the region of your Qiskit Runtime instances to get an audit trail of events. Refer to the Qiskit Runtime `Activity Tracker page `__ for details about the events logged. - -This audit log contains the fields ``initiator_authnName`` and ``initiator_authnId``, which match the name shown in `Manage → Access (IAM) → Users `__. To view this field, click on the user name, then **Details** in the **IAM ID** field. - -|event| - -To capture App ID events, open your App ID instance, then navigate to **Manage Authentication -> Authentication settings** and enable **Runtime Activity**. - -Define more fine grained roles -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The actions in the custom roles can be used for more fine grained access control. For example, some users might need full access to work on service instances, while others might only need Read access to service instances, programs, and jobs. - -To achieve that, define two different custom roles such as ``MLreader`` and ``MLwriter``. Remove all cancel, delete, and update roles from the ``MLreader`` custom role, and include all actions in the ``MLwriter`` custom role. Next, add the roles to two different access groups accordingly. - -When using dynamic rules, that is, when the IDP administrator manages access through custom IDP user attributes, do not use IDP custom user attributes that are substrings of each other. For instance, don't use ``ml`` and ``mlReader``, as the string comparison of ``ml`` would also accept ``mlReader``. You could use ``MLreader`` and ``MLwriter`` to avoid this conflict. - -For an example of setting up custom roles, see `Create access groups for projects `__. - -Other Cloud resources -~~~~~~~~~~~~~~~~~~~~~~~ - -The steps used in this tutorial can be used to manage access to other Cloud resources as well. Include the appropriate permissions to the access groups of the relevant projects. - -Hierarchical project structures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In this tutorial, the mapping of users to projects and service instances was kept simple. However, by associating several users with access groups and referencing service instances from several access groups, more complex mappings can be implemented. - -This method can accommodate a hierarchical structure. That is, it can align to how users might be assigned to the Hub/Group/Project access structure in the IBM Quantum Platform. For example, a *group* could be an access group that is assigned to all service instances of the group’s projects. Users who should get access to all of the group’s projects would then only have to be added to the group’s access group. - -Consistent and repeatable deployment of the configuration -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The steps of this tutorial can be automated for consistent and repeatable management of users, projects, and the mapping between those. Refer to the `Terraform IBM Cloud Provider documentation `__ for templates. - - - - -Next steps ----------- - -See `Configure Qiskit Runtime for an organization `__ for the steps to set up Qiskit Runtime. - -.. |event| image:: ../images/org-guide-audit-example.png diff --git a/docs/cloud/quickstart-steps-org.rst b/docs/cloud/quickstart-steps-org.rst deleted file mode 100644 index e4aca0031..000000000 --- a/docs/cloud/quickstart-steps-org.rst +++ /dev/null @@ -1,108 +0,0 @@ -Configure Qiskit Runtime for an organization -============================================ - -Follow these steps to start setting up Qiskit runtime. - -Configure IAM settings ----------------------- - -First, configure some settings in the administrator’s Identity and Access Management (IAM) account. To review and configure these settings, go to `Manage → IAM → Settings `__. - -- **User list visibility** determines whether users can see each other, regardless of project assignment. The ``enabled`` setting restricts user visibility. That is, users in your account cannot see each other, even if they can access the same resources. Choose the appropriate value for your environment. See `Controlling user visibility `__ for more information. -- **API key creation** controls whether users can create API keys. In Qiskit Runtime, it is common to use API keys. If API keys are being used, choose ``disabled``. Alternatively, you can give specific permissions to each user. - -|IAM settings| - -.. _create-group-org: - -(Optional) Create resource groups ---------------------------------- - -Skip this step if you are using access groups that directly reference Qiskit Runtime service instances. - -If you chose to use resource groups, go to `Manage → Account → Resource groups (in Account resources) `__ and click **Create**. - -Create Qiskit Runtime service instances ---------------------------------------- - -If you already created Qiskit Runtime service instances, skip this step. - -- If you are using resource groups, make sure to create the service instances on the appropriate resource group. -- The service instance name, such as ``QR-ml``, is needed for access group references. - -1. From the `Qiskit Runtime Provisioning page `__, select the Create tab, then choose the appropriate service plan, depending on what you need access to: - - - **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 use all the benefits of Qiskit Runtime by running on real quantum hardware. - -2. Complete the required information, then click **Create**. - -Create access groups for projects ---------------------------------- - -First, we create a custom role that allows users to perform actions to work with Qiskit Runtime service instances for each access group. Next, we create an access group for each project and give that group the minimum set of permissions that are required to work with the project resources. In a later step, we map users to access groups. - -Follow these steps to set up an access group: - -1. Create a custom role. - - 1. From `Manage → IAM → Roles `__, click ``Create``. - - 2. Enter a name, ID, description, and select ``Qiskit Runtime`` from the service, as shown in the image: - - |custom| - - 3. Select the following roles, then click **Create**. - - - quantum-computing.device.read - - quantum-computing.job.cancel - - quantum-computing.job.create - - quantum-computing.job.read - - quantum-computing.program.create - - quantum-computing.program.delete - - quantum-computing.program.read - - quantum-computing.program.update - - quantum-computing.user.logout - - Select quantum-computing.job.delete if you want to allow users to delete jobs. - - |actions| - - .. note:: - You can optionally define more fine grained roles by following `these instructions `__. - -2. Create an access group. - - 1. Go to `Manage → IAM → Access groups `__ and click **Create**. - 2. Enter a name, like ``project-ml``, and a description. - -3. Assign access to the group. - - 1. Select the Access tab and click **Assign access**. - - 2. In the Service list, search for **Qiskit Runtime** and select it, then click **Next**. - - |service| - - 3. In Resources, select **Specific resources**. For Attribute type, choose **Service Instance**. - - 4. From the drop-down list, select the service instance that you want to add to the access group, for example, ``QR-ml``. If you are using resource groups, select the resource group instead of selecting individual service instances. Click **Next**. - - |resources| - - 5. For Roles and actions, select **Viewer** and the custom role that was created previously. Click **Add**, then **Assign**. - - |roles| - - 6. Repeat this step if you want to give an access group permission to several service instances. - -Set up your ID provider and assign users ----------------------------------------- - -Follow the steps in the `manage users topic `__. - -.. |IAM settings| image:: ../images/org-guide-iam-settings.png -.. |custom| image:: ../images/org-guide-create-custom-role.png -.. |actions| image:: ../images/org-guide-custom-role-actions.png -.. |service| image:: ../images/org-guide-create-access-group-1.png -.. |resources| image:: ../images/org-guide-create-access-group-2.png -.. |roles| image:: ../images/org-guide-create-access-group-3.png diff --git a/docs/cloud/quickstart.rst b/docs/cloud/quickstart.rst deleted file mode 100644 index 29bfc77ea..000000000 --- a/docs/cloud/quickstart.rst +++ /dev/null @@ -1,104 +0,0 @@ -Getting started -================ - -This tutorial walks you through the steps to set up a Qiskit Runtime service instance, log in to your service instance, and run your first job on a quantum computer. - -If you are an administrator who needs to set up Qiskit Runtime for your organization, refer to `Plan Qiskit Runtime for an organization `__ for instructions to set up a service instance and work with users. - - -Create a service instance ---------------------------------- - - -If you already created a Qiskit Runtime service instance or were invited to one by an administrator, skip to the next step. To determine whether you already have access to an instance, check your `IBM Cloud Instances page `__. If you have one or more instances shown, you can skip ahead to :ref:`install-packages`. - -.. figure:: ../images/instances.png - :alt: This image shows an Instances page with two instances. - - Instances page showing multiple instances. - -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 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. - - -2. Complete the required information, then click **Create**. - -.. _install-packages: - -Install or update Qiskit packages ------------------------------------ - -Install or update the following packages in your development environment. They let you create circuits and work with primitives with Qiskit Runtime. For detailed instructions, refer to the `Qiskit textbook `__. Periodically check the `Qiskit release notes `__ (or rerun these commands) so that you always have the latest version. - - .. note:: - - Be sure to run these commands even if you already installed the packages, to ensure that you have the latest versions. - - -.. code-block:: python - - # Installs the latest version of the Qiskit meta-package for circuit creation. - pip install qiskit -U - - -.. code-block:: python - - # Installs the latest version of the Qiskit Runtime package, which is needed to interact with the Qiskit Runtime primitives on IBM Cloud. - pip install qiskit-ibm-runtime -U - - -Authenticate to the service ------------------------------------ - - -To authenticate to the service, call ``QiskitRuntimeService`` with your IBM Cloud API key and the CRN: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - service = QiskitRuntimeService(channel="ibm_cloud", token="", instance="") - -.. _credentials: - -Find your access credentials -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -1. Find your API key. From the `API keys page `__, view or create your API key, then copy it to a secure location so you can use it for authentication. -2. Find your Cloud Resource Name (CRN). Open the `Instances page `__ and click your instance. In the page that opens, click the icon to copy your CRN. Save it in a secure location so you can use it for authentication. - - -Optionally save your credentials to disk -------------------------------------------- - - -Optionally save your credentials to disk (in the ``$HOME/.qiskit/qiskit-ibm.json`` file). If you don't save your credentials to disk, you must specify your credentials every time you start a new session. - -If you save your credentials to disk, you can use ``QiskitRuntimeService()`` in the future to initialize your account. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Save account to disk. - QiskitRuntimeService.save_account(channel="ibm_cloud", token="", instance="") - - service = QiskitRuntimeService() - - -If you need to update your saved credentials, run ``save_account`` again, passing in ``overwrite=True`` and the updated credentials. For more information about managing your account, see the `account management topic <../how_to/account-management.html>`__. - - -Choose a primitive to run -------------------------- - - -Qiskit Runtime uses primitives to interface with quantum computers and they are publicly available. Choose the appropriate link to continue learning how to run a primitive. - -`Getting started with Sampler `__ - -`Getting started with Estimator `__ diff --git a/docs/cloud/setup-terraform.rst b/docs/cloud/setup-terraform.rst deleted file mode 100644 index 00222209e..000000000 --- a/docs/cloud/setup-terraform.rst +++ /dev/null @@ -1,55 +0,0 @@ -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: - -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: - -- ``name`` – The name of your service instance. -- ``service`` – Specify ``quantum-computing`` to provision Qiskit Runtime instances. -- ``plan`` – Can be ``lite`` or ``paygo-standard``. -- ``location`` – Currently, this must be ``us-east``. - -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 ------------------------------------------------------- - -After the job completes, you can view the results. - -1. In your Terraform configuration file, add the following code. Change the name of the service instance (parameter “name”) and the plan (parameter “plan”) according to your requirements: - - .. code:: - - resource "ibm_resource_instance" "my-instance" { - name = "my-instance-name" - service = "quantum-computing" - plan = "lite" - location = "us-east" - } - - - -2. Create a Terraform execution plan. - - .. code:: - - terraform plan - - -3. Remove the namespace and re-create it with a new name. Note that this process might take a few minutes to complete. - - .. code:: - - terraform apply - - -4. Verify on the `Instances page `__ that your service instance has been created. - -Qiskit Runtime service instances are IAM managed resources. Access can be shaped through terraform using IAM user policies. See `IBM IAM user policy `__ for more details and examples. diff --git a/docs/compare.rst b/docs/compare.rst deleted file mode 100644 index 066468922..000000000 --- a/docs/compare.rst +++ /dev/null @@ -1,39 +0,0 @@ -How do Qiskit Runtime primitives differ from backend.run? -========================================================= - -There are two methods for accessing IBM Quantum systems. First, the -`qiskit-ibm-provider` package provides the ``backend.run()`` interface, -allowing direct access to IBM Quantum systems with no pre- or post-processing -involved. This level of access is suitable for those users who want precise -control over circuit execution and result processing. This level of access -is needed for those looking to work at the level Kernel developer developing, -for example, circuit optimization routines, error mitigation techniques, or -characterizing quantum systems. - -In contrast, Qiskit Runtime is designed to streamline algorithm and application construction -by removing the need for users to understand -technical hardware and low-level software details. Advanced processing techniques -for error suppression and mitigation are automatically applied, giving users -high-fidelity results without the burden of having to code these routines -themselves. The inclusion of sessions within Qiskit Runtime allows users -to run iterative algorithm circuits back to back, or batch collections of circuits -without having to re-queue each job. This results in more efficient quantum processor utilization -and reduces the total amount of time users spend running -complex computations. - - -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Function | backend.run | Qiskit Runtime Primitives | -+=================================================================================+=======================+===========================+ -| Abstracted interface for circuits and variational workloads | No | Yes | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Sessions to improve performance for a sequence of jobs | No | Yes | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Automated application of error suppression and mitigation techniques | No | Yes | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Increased performance for variational algorithms | No | Yes | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Pulse Gates | Yes | Yes | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ -| Dynamic circuits | Yes | No | -+---------------------------------------------------------------------------------+-----------------------+---------------------------+ diff --git a/docs/conf.py b/docs/conf.py index de5c2f652..9c4f4da8c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- - -# This code is part of Qiskit. +# This code is a Qiskit project. # # (C) Copyright IBM 2022. # @@ -12,39 +10,22 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. -# pylint: disable=invalid-name -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - # -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# import os import sys sys.path.insert(0, os.path.abspath('.')) -# Set env flag so that we can doc functions that may otherwise not be loaded -# see for example interactive visualizations in qiskit.visualization. -os.environ['QISKIT_DOCS'] = 'TRUE' - # -- Project information ----------------------------------------------------- project = 'Qiskit Runtime IBM Client' -copyright = '2022, Qiskit Development Team' # pylint: disable=redefined-builtin +project_copyright = '2022, Qiskit Development Team' author = 'Qiskit Development Team' +language = 'en' # The short X.Y version version = '' # The full version, including alpha/beta/rc tags -release = '0.16.0' - -docs_url_prefix = "ecosystem/ibm-runtime" +release = '0.17.0' # -- General configuration --------------------------------------------------- @@ -53,15 +34,10 @@ 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx.ext.extlinks', - 'sphinx_tabs.tabs', 'jupyter_sphinx', 'sphinx_autodoc_typehints', 'reno.sphinxext', 'nbsphinx', - 'sphinx_design', - "qiskit_sphinx_theme", ] templates_path = ['_templates'] @@ -91,10 +67,6 @@ autosummary_generate = True -# ----------------------------------------------------------------------------- -# Autodoc -# ----------------------------------------------------------------------------- - autodoc_default_options = { 'inherited-members': None, } @@ -111,16 +83,6 @@ 'table': 'Table %s' } - -translations_list = [ - ('en', 'English'), - ('ja_JP', 'Japanese'), - ('es_UN', 'Spanish'), -] -language = 'en' -locale_dirs = ['locale/'] -gettext_compact = False # optional. - # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. @@ -140,26 +102,15 @@ # package. Works only for the HTML builder currently. modindex_common_prefix = ['qiskit.'] -# -- Configuration for extlinks extension ------------------------------------ -# Refer to https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html - - # -- Options for HTML output ------------------------------------------------- -html_theme = "qiskit-ecosystem" +# Even though alabaster isn't very pretty, we use it +# over the normal qiskit-ecosystem theme because it's +# faster to build and these docs are only necessary +# so the API docs can be integrated into docs.quantum.ibm.com. +html_theme = "alabaster" html_title = f"{project} {release}" -html_logo = "images/ibm-quantum-logo.png" - -html_theme_options = { - # Because this is an IBM-focused project, we use a blue color scheme. - "light_css_variables": { - "color-brand-primary": "var(--qiskit-color-blue)", - }, -} - html_last_updated_fmt = '%Y/%m/%d' - html_sourcelink_suffix = '' - autoclass_content = 'both' diff --git a/docs/errors.rst b/docs/errors.rst deleted file mode 100644 index 26b8603f3..000000000 --- a/docs/errors.rst +++ /dev/null @@ -1,1446 +0,0 @@ -.. _errors: - -############### -API error codes -############### - -1XXX -==== -.. _error1xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error1000: - - **1000** - - API Internal error. - - Try the action again. If it happens again, contact IBM Quantum through `Slack `_ for help. - - * - .. _error1001: - - **1001** - - ``qObject`` is larger than the maximum size. - - Run a small Job. Split the circuits in smaller jobs. - - * - .. _error1002: - - **1002** - - Error in the validation process of the job. - - Check the Job, it is not valid to run on this backend. - - * - .. _error1003: - - **1003** - - Error in transpilation process. - - Check the Job, it is not valid to run on this backend. - - * - .. _error1004: - - **1004** - - The backend is not available. - - Use another backend to run the job. - - * - .. _error1005: - - **1005** - - Basis gates not available. - - Use another backend with basis gates. - - - * - .. _error1006: - - **1006** - - Error during call to converter microservice. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error1007: - - **1007** - - Backend not found. - - Check the backend name, maybe it is wrong. - - * - .. _error1008: - - **1008** - - Error during the validation process of a job. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error1009: - - **1009** - - Required backend information not found. - - Use another backend to run the job. - - * - .. _error1010: - - **1010** - - Error returned at backend level. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error1011: - - **1011** - - Error publishing job at the backend queue. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error1012: - - **1012** - - The user reached the maximum number of jobs running concurrently. - - Wait until some previous jobs were finished. You can cancel pending jobs to run new jobs. - - * - .. _error1101: - - **1101** - - ``Qobj`` does not conform to the schema. - - Verify the ``Qobj`` for your job conforms to the ``Qobj`` schema. - - * - .. _error1102: - - **1102** - - The number of experiments in the ``Qobj`` is higher than the number of experiments supported by the backend. - - Split the experiments into multiple jobs. The maximum number of experiments the backend supports can be found in its configuration data. - - * - .. _error1103: - - **1103** - - The number of shots in the ``Qobj`` is higher than the number of shots supported by the backend. - - Use fewer shots. The maximum number of shots the backend supports can be found in its configuration data. - - * - .. _error1104: - - **1104** - - The ``Qobj`` requests memory measurement, but the backend does not support memory. - - Run the job on a backend that supports memory or don't request memory measurement. Whether a backend supports memory measurement can be found in its configuration data. - - * - .. _error1105: - - **1105** - - The number of qubits used in the ``Qobj`` is higher than the number of quantum registers defined in the ``Qobj``. - - Correct your program and try again. - - - * - .. _error1106: - - **1106** - - The ``Qobj`` uses gates that are not among the backend's basis gates. - - Correct your program and try again. Transpiling your program will convert high level gates to basis gates. The basis gates for a backend can be found in its configuration data. - - * - .. _error1107: - - **1107** - - The ``Qobj`` includes an instruction that assumes a coupling map that is different from the backend's coupling map. - - Correct your program and try again. Transpiling your program will map instructions to the correct qubits based on the backend's coupling map. The coupling map for a backend can be found in its configuration data. - - * - .. _error1108: - - **1108** - - The backend does not support open pulse. - - Run the job on a backend that supports open pulse. Whether a backend supports open pulse can be found in its configuration data. - - * - .. _error1109: - - **1109** - - The number of qubits used in the ``Qobj`` is more than the number of qubits supported by the backend. - - Run the job on a backend that supports sufficient number of qubits for the job. The number of qubits a backend supports can be found in its configuration data. - - * - .. _error1999: - - **1999** - - Planned outage. The service is undergoing maintenance. - - Please wait. The service will be back up soon. The website portal will have more information about what the expected time window for the maintenance work is. - - -2XXX -==== -.. _error2xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error2000: - - **2000** - - Backend not found. - - Check the backend name, maybe it is wrong. - - * - .. _error2001: - - **2001** - - Backend not available for booking. - - Use another backend to book a time slot. - - * - .. _error2002: - - **2002** - - Backend not available for this action. - - Use another backend. - - * - .. _error2100: - - **2100** - - Invalid URL to Upload to Bluemix. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2200: - - **2200** - - A booking already exists. - - Select another date to book. - - * - .. _error2201: - - **2201** - - Booking data is not valid. - - Check the booking data, maybe it is wrong. - - - * - .. _error2202: - - **2202** - - Cannot cancel booking. - - Check the booking to cancel. - - * - .. _error2203: - - **2203** - - Provider does not have enough remaining time to book. - - Use another provider to book or contact your Group Administrator. - - * - .. _error2204: - - **2204** - - User already has a booking on that date. - - Select another date to book. - - * - .. _error2205: - - **2205** - - Booking not found. - - Check the booking data, maybe it is wrong. - - * - .. _error2206: - - **2206** - - Booking on calibration time. - - Select another date to book. - - * - .. _error2300: - - **2300** - - Code ID not found. - - Check the code data, maybe it is wrong. - - * - .. _error2301: - - **2301** - - Code not updated. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2302: - - **2302** - - Code wrong. - - Check the code data, maybe it is wrong. - - * - .. _error2304: - - **2304** - - Error parsing QASM. - - Check the code data, maybe it is wrong. - - - * - .. _error2305: - - **2305** - - Invalid Code. - - Check the code data, maybe it is wrong. - - * - .. _error2306: - - **2306** - - Invalid result. - - Check the code data, maybe it is wrong. - - * - .. _error2307: - - **2307** - - The ``Qobj`` requests memory measurement, but the backend does not support memory. - - Check the code data, maybe it is wrong. - - * - .. _error2308: - - **2308** - - User role not found. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error2309: - - **2309** - - Code not found. - - Check the code data, maybe it is wrong. - - - * - .. _error2310: - - **2310** - - Failed to export. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2311: - - **2311** - - Image wrong. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2313: - - **2313** - - QASM not found. - - Check the code data, maybe it is wrong. - - * - .. _error2400: - - **2400** - - Error wrong data received. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2402: - - **2402** - - Maximum attempts reached. - - Reduce the number of concurrent requests. - - * - .. _error2403: - - **2403** - - Missing data in HTTP request. - - Check your request to the endpoint. - - - * - .. _error2404: - - **2404** - - Model not found in database. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2405: - - **2405** - - Error saving new data. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2407: - - **2407** - - Authentication required. - - Try to log in again. - - * - .. _error2408: - - **2408** - - Invalid Access Token. - - Try to log in again. - - * - .. _error2409: - - **2409** - - Forbidden. - - You don't have authority to perform the action. - - * - .. _error2410: - - **2410** - - Service not accessible. - - You don't have authority to perform the action. - - * - .. _error2411: - - **2411** - - Operation not available. - - You don't have authority to perform the action. - - * - .. _error2412: - - **2412** - - Error retrieving data from database. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2600: - - **2600** - - Configuration not available for this system. - - Try to use another backend. - - * - .. _error2602: - - **2602** - - System not allowed. - - Try to use another backend. - - * - .. _error2603: - - **2603** - - Error getting topology attributes. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error2604: - - **2604** - - Error getting topology queues. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2609: - - **2609** - - Properties are empty. - - Try to use another backend. - - * - .. _error2614: - - **2614** - - Topology without kind established. - - Try to use another backend. Contact an IBM Quantum administrator. - - * - .. _error2615: - - **2615** - - The system is not available. - - Try to use another backend. - - * - .. _error2616: - - **2616** - - This system can only be used for running jobs. - - Try the Jobs API. Try to use another backend. - - * - .. _error2618: - - **2618** - - Basis gates not available. - - Try to use another backend. - - * - .. _error2620: - - **2620** - - System not found. - - Try to use another backend. - - * - .. _error2622: - - **2622** - - Properties not found. - - Try to use another backend. - - * - .. _error2900: - - **2900** - - An error occur getting the hub. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2901: - - **2901** - - Error checking hub or group administrators. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2902: - - **2902** - - Error checking systems in the Hub. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2903: - - **2903** - - Hub info not found. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error2904: - - **2904** - - Invalid backend to configure for booking. - - Use another backend. - - * - .. _error2905: - - **2905** - - Invalid parameters to configure for booking. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2906: - - **2906** - - Invalid priority value. - - Change the priority Value. - - * - .. _error2907: - - **2907** - - System not available for Hub. - - Use another backend. - - * - .. _error2908: - - **2908** - - Error checking user in the Hub. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error2909: - - **2909** - - Group not found. - - Use another Group. - - * - .. _error2910: - - **2910** - - Hub not found. - - Use another Hub. - - * - .. _error2911: - - **2911** - - Invalid Hub/Group/Project. - - Use another provider. - - * - .. _error2912: - - **2912** - - Invalid mode to configure for booking. - - Use another mode to book a backend. - - * - .. _error2913: - - **2913** - - Project not found. - - Use another project. - - * - .. _error2914: - - **2914** - - This hub is not allowed to view analytics. - - Use another hub. - -3XXX -==== -.. _error3xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error3200: - - **3200** - - Backend not valid. - - Use another backend. - - * - .. _error3202: - - **3202** - - Cannot get presigned download URL. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3203: - - **3203** - - Cannot get presigned upload URL. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3204: - - **3204** - - Error during call to converter microservice. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error3207: - - **3207** - - Job access not allowed. - - Access another job. - - * - .. _error3208: - - **3208** - - Job not cancelled. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3209: - - **3209** - - Job not running. - - Check if the action makes sense. - - * - .. _error3210: - - **3210** - - Job not saved. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3211: - - **3211** - - Job not valid. - - Check the Job sent, maybe it is wrong. - - * - .. _error3212: - - **3212** - - Job not validated. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3213: - - **3213** - - Job status not valid. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3214: - - **3214** - - Job transition not valid. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3215: - - **3215** - - Job without code identifier. - - Check the Job sent, maybe it is wrong. - - - * - .. _error3216: - - **3216** - - Limit not valid. - - Change the limit sent into the request. - - * - .. _error3218: - - **3218** - - Number of Shots not allowed. - - Change the number of shots. - - * - .. _error3220: - - **3220** - - Payload not valid. - - Change the body sent into the request. Maybe its format is wrong. - - * - .. _error3224: - - **3224** - - Q-Object memory not allowed. - - Disable the memory parameter in the Job. - - - * - .. _error3226: - - **3226** - - Q-Object not valid. - - Check the format of the Job. Maybe it is wrong. - - - * - .. _error3228: - - **3228** - - Q-Object-External-Storage property not allowed in this backend. - - Send the content of the Job inside of the body. - - * - .. _error3229: - - **3229** - - QASM no longer accepted. - - Use Q-Object format. - - * - .. _error3230: - - **3230** - - Seed not allowed. - - Don't send seed parameter. - - * - .. _error3233: - - **3233** - - The job can't be created. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3234: - - **3234** - - The job can't be validated. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3235: - - **3235** - - Job cost cannot be calculated. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error3236: - - **3236** - - The job is empty. - - Check the job sent. Maybe it is empty. - - * - .. _error3237: - - **3237** - - The job is invalid. - - Check the job sent. Maybe it is wrong. - - * - .. _error3239: - - **3239** - - Number of registers exceed the number of qubits. - - Define the same ``creg`` as ``qreg``. - - * - .. _error3242: - - **3242** - - Circuit count exceeded. - - Send smaller number of circuits in the Job. - - * - .. _error3243: - - **3243** - - Circuit is too big. - - Reduce the content of the circuit. - - * - .. _error3245: - - **3245** - - The queue is disabled. - - Use another backend. - - * - .. _error3246: - - **3246** - - The queue is unavailable. - - Use another backend. - - * - .. _error3248: - - **3248** - - Your job is too long. - - Reduce the content of the job. - - * - .. _error3249: - - **3249** - - Job fields are empty. - - Check the Job content. Maybe it is empty. - - * - .. _error3250: - - **3250** - - Job not found. - - Check the job ID to query. It is wrong. - - * - .. _error3251: - - **3251** - - Job not uploaded to object storage. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error3252: - - **3252** - - Object storage not allowed. - - Send the job into the body of the request. - - * - .. _error3253: - - **3253** - - Timeout getting the result. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3254: - - **3254** - - The job is not in queue. - - Check the status of the job. - - * - .. _error3255: - - **3255** - - Invalid share level. - - Update the share level. - - * - .. _error3259: - - **3259** - - This system can only be used for running jobs. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3265: - - **3265** - - Input type not allowed by backend. - - Use another backend. - - * - .. _error3300: - - **3300** - - Cannot download job data. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3301: - - **3301** - - Cannot upload job data. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3302: - - **3302** - - Job not found. - - Check the job information. Maybe it is wrong. - - * - .. _error3400: - - **3400** - - License not found. - - Accept the license. - - * - .. _error3402: - - **3402** - - API key not found. - - Regenerate the API Token. - - * - .. _error3405: - - **3405** - - Codes not deleted. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - - * - .. _error3407: - - **3407** - - User API token not valid. - - Check the API Token. - - * - .. _error3409: - - **3409** - - Error deleting entities from user. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3410: - - **3410** - - Error deleting user relations. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3418: - - **3418** - - Failed to create the token for the user. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3422: - - **3422** - - Old password is incorrect. - - Check your old password. It is wrong. - - * - .. _error3423: - - **3423** - - Passwords do not match. - - Check the password. It is wrong. - - * - .. _error3424: - - **3424** - - Retrieving last version licenses, including future ones. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3425: - - **3425** - - Retrieving last version licenses. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3440: - - **3440** - - Authentication is required to perform that action. - - Try to log in again. - - * - .. _error3443: - - **3443** - - Failed to check login. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3444: - - **3444** - - License required. You need to accept the License. - - Accept the license. - - * - .. _error3445: - - **3445** - - Login with IBM ID required. - - Login using IBM ID. - - * - .. _error3446: - - **3446** - - Login failed. - - Try to login again. - - - * - .. _error3452: - - **3452** - - The license is not accepted. - - Accept the License. - - * - .. _error3453: - - **3453** - - The license is required. - - Accept the License. - - * - .. _error3458: - - **3458** - - User reached the maximum limits of concurrent jobs. - - Wait until some previous jobs were finished. You can cancel pending jobs to run new jobs. - - * - .. _error3459: - - **3459** - - User is blocked by wrong password. - - Wait 5 minutes, then log in again. - - * - .. _error3460: - - **3460** - - User is blocked. - - Contact an IBM Quantum Administrator. - - * - .. _error3467: - - **3467** - - Failed to create or renew API token. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3468: - - **3468** - - Failed to get API token. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3500: - - **3500** - - Body is wrong. - - Check the body of the request. - - * - .. _error3704: - - **3704** - - Error getting status from the queue. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3811: - - **3811** - - Request not found. - - Check the request that you are trying to perform. - - * - .. _error3900: - - **3900** - - Empty response from the stats micro-service. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3901: - - **3901** - - Error parsing stats. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3902: - - **3902** - - Error retrieving stats. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3903: - - **3903** - - Invalid date. - - Update the dates. - - * - .. _error3904: - - **3904** - - Invalid end date. - - Update the end date. - - * - .. _error3905: - - **3905** - - Invalid input to the stats micro-service. - - Check the query. It is incorrect. - - * - .. _error3906: - - **3906** - - Invalid key. - - Check the query. It is incorrect. - - * - .. _error3907: - - **3907** - - Invalid start date. - - Update the start date. - - * - .. _error3908: - - **3908** - - Invalid stats type. - - Check the query. It is incorrect. - - * - .. _error3909: - - **3909** - - Missing mandatory user stats info. - - Check the query. It is incorrect. - - * - .. _error3910: - - **3910** - - Number of months too big. - - Reduce the number of months. - - * - .. _error3911: - - **3911** - - Stats micro-service is not available. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3912: - - **3912** - - Stats not found. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3913: - - **3913** - - Analytics stats not found. - - Retry the action. If it happens again, contact IBM Quantum through `Slack `__ for help. - - * - .. _error3914: - - **3914** - - Project level does not support aggregated analytics stats. - - Try to use another project. - - * - .. _error3915: - - **3915** - - Missing start/end dates; ``allTime`` not set to true for analytics stats. - - Set start and end date in the query. - -4XXX -==== -.. _error4xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error4001: - - **4001** - - Job is part of a session that's been closed - - Ensure session is not closed before all jobs in session have run - -5XXX -==== -.. _error5xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error5201: - - **5201** - - Job timed out after {} seconds. - - Reduce the complexity of the job, or number of shots. - - * - .. _error5202: - - **5202** - - Job was canceled. - - None. Job was canceled. - - * - .. _error5203: - - **5203** - - Failed to run job. - - Try to run the job again. - - * - .. _error5204: - - **5204** - - Error raised when execution on AER failed. - - Try to run the job again. - - -6XXX -==== -.. _error6xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error6000: - - **6000** - - Too many shots given ({} > {}). - - Reduce the requested number of shots. - - * - .. _error6001: - - **6001** - - Too few shots given ({} < {}). - - Increase the requested number of shots. - - * - .. _error6002: - - **6002** - - Too many experiments given ({} > {}). - - Reduce the number of experiments. - - * - .. _error6003: - - **6003** - - Too few experiments given ({} < {}). - - Increase the number of experiments. - - -7XXX -==== -.. _error7xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error7000: - - **7000** - - Instruction not in basis gates:
instruction: {}, qubits: {}, ``params``: {} - - Instruction not supported by backend. Remove the instruction shown in the error message. - - * - .. _error7001: - - **7001** - - Instruction {} is not supported. - - Remove unsupported instruction, or run on a simulator that supports it. - - * - .. _error7002: - - **7002** - - Memory output is disabled. - - Select a different backend or set ``memory=False`` in transpile / execute. - - * - .. _error7003: - - **7003** - - qubits: {} and classical bits: {} do not have equal lengths. - - Length of memory slots must be same as number of qubits used. - - * - .. _error7004: - - **7004** - - Qubit measured multiple times in circuit. - - Remove multiple measurements on qubits. - - * - .. _error7005: - - **7005** - - Error in supplied instruction. - - Refer to the `Operations glossary <../operations_glossary>`__ and verify that the instructions are correct. - - * - .. _error7006: - - **7006** - - Qubit measurement is followed by instructions. - - Cannot perform any instruction on a measured qubit. Remove all instructions following a measurement. - -8XXX -==== -.. _error8xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error8000: - - **8000** - - Channel {}{} lo setting: {} is not within acceptable range of {}. - - Set channel LO within specified range. - - * - .. _error8001: - - **8001** - - Qubits {} in measurement are not mapped. - - Assign qubits to a classical memory slot. - - * - .. _error8002: - - **8002** - - Total samples exceeds the maximum number of samples for channel {}. ({} > {}). - - Reduce number of samples below specified limit. - - * - .. _error8003: - - **8003** - - Total pulses exceeds the maximum number of pulses for channel: {}, ({} > {}). - - Reduce number of pulses below specified limit. - - * - .. _error8004: - - **8004** - - Channel {}{} is not available. - - Must use available drive channels. - - * - .. _error8006: - - **8006** - - Gate {} in line {}s not understood ({}). - - This instruction is not supported. Make sure that the gate name is correct and is found within the `Operations glossary `__. - - * - .. _error8007: - - **8007** - - QASM gate not understood: {}. - - This instruction is not understood. Make sure it is found within the `Operations glossary `__. - - * - .. _error8008: - - **8008** - - Unconnected Qubits. - - Check the topology diagram for this system (go to the `Compute resources page `__ and click the system) and make sure the qubits are connected. - - * - .. _error8009: - - **8009** - - Measurement level is not supported. - - The given measurement level is not supported on this backend. Change it to 0-2 except the measurement level specified. - - * - .. _error8011: - - **8011** - - Pulse experiments are not supported on this system. - - Pulse experiment is not supported on this backend. Use a backend that supports pulse to run this experiment. - - * - .. _error8013: - - **8013** - - This backend does not support conditional pulses. - - Conditionals are not supported on this backend. Remove the conditional instruction in your program. - - * - .. _error8014: - - **8014** - - Reset instructions are not supported. - - Reset instructions are not supported at this time for this backend. Remove the reset instruction. - - * - .. _error8016: - - **8016** - - Pulse {} has too few samples ({} > {}). - - Add more samples. - - * - .. _error8017: - - **8017** - - Pulse not a multiple of {} samples. - - Due to hardware limitations, pulses must be a multiple of a given number of samples. - - * - .. _error8018: - - **8018** - - Waveform memory exceeds the maximum amount of memory currently available. - - Reduce the number of samples in the waveform. - - * - .. _error8019: - - **8019** - - For channel {}{}, Final channel time exceeds max time ({} > {}). - - Reduce the total length of pulse sequence on the specified channel. - - * - .. _error8020: - - **8020** - - Circuit runtime is greater than the device repetition rate. - - Circuit too long, reduce length of circuit. - - - * - .. _error8021: - - **8021** - - Acquires have durations of different length. - - Set acquire operations to have the same length. - - * - .. _error8022: - - **8022** - - Pulse {} has too many samples ({} > {}). - - Reduce the number of samples in the specified pulse. - - * - .. _error8023: - - **8023** - - {0} {1} is an invalid entry. {0} should be a positive integer. - - Make the entry a positive integer. - - * - .. _error8024: - - **8024** - - At most one acquire currently supported per acquisition channel. - - Use only one acquire command per channel. - - * - .. _error8026: - - **8026** - - Supplied qubits ({0}) in acquire are not valid. - - Fix the qubits specified in the acquire commands. - - * - .. _error8027: - - **8027** - - Channel specified: {} is not available. - - Channel does not exist on system. - - * - .. _error8029: - - **8029** - - Repetition time ({0}) is not supported. - - Repetition time must be changed to a supported value. - - * - .. _error8030: - - **8030** - - Repetition delay ({0}) is not supported. - - The delay is not supported. - - - * - .. _error8031: - - **8031** - - Submitted job is too long. - - Reduce the length of the job. - - * - .. _error8033: - - **8033** - - ``Qobj`` ``type`` not provided in ``config``. - - Add ``type`` to ``qobj['config']``. - - * - .. _error8035: - - **8035** - - Instruction {0} at timestep {1}dt overlaps with instruction {2} at timestep {3}dt on channel {4}. - - Two instructions cannot be played at the same time on a channel. - - * - .. _error8036: - - **8036** - - All measure(circuit) and acquire(pulse) instructions must align to a 16 sample boundary. Measurements may be impacted by delays which have non-multiple of 16 durations. - - Due to hardware limitations, measure and acquire instructions must occur at 16 sample multiples. - - * - .. _error8037: - - **8037** - - ESP readout not enabled on this device. - - Set ``use_measure_esp=False`` or remove from run options. - - * - .. _error8039: - - **8039** - - A combination of pulses on the logical channels is exceeding the hardware output due to internal usage of hardware output. This will typically be a result of drive and control channels being mapped to the same physical channel in the hardware and the summed total of the applied pulses (including additional internal pulses for system-specific hardware functionality) exceeding unit norm. - - Lower the amplitudes of the input pulses. - - * - .. _error8041: - - **8041** - - An amplitude was requested with a norm of greater than 1. - - Lower the amplitudes of the input pulses. - - * - .. _error8042: - - **8042** - - The input pulse had some parameters which were not validated. This can be because certain parameters are expected to be real, while others are complex. It may also be due to the amplitude or duration of the pulse exceeding a limit, or other invalid combinations of parameters (for example, a Gaussian square pulse with a flat-top width greater than the pulse's total duration). - - Verify the pulse input parameters. - - * - .. _error8044: - - **8044** - - Number of samples is less than the minimum pulse width. - - Verify that the duration of all pulses meets or exceeds the minimum pulse duration. If necessary and possible, you may consider zero-padding the start/end of very short pulses such that they meet or exceed the minimum duration. - -9XXX -==== -.. _error9xxx: - -.. list-table:: - :header-rows: 1 - - * - Error code - - Message - - Solution - - * - .. _error9999: - - **9999** - - Internal error. - - Contact IBM Quantum through `Slack `__ for help. diff --git a/docs/faqs.rst b/docs/faqs.rst deleted file mode 100644 index f30adcbe1..000000000 --- a/docs/faqs.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _faqs: - -######################################### -Frequently asked questions -######################################### - -.. toctree:: - faqs/open_source_vs_ibm_cloud_primitives - faqs/max_execution_time - FAQs for IBM Cloud Qiskit Runtime - - - -.. Hiding - Indices and tables - :ref:`genindex` - :ref:`modindex` - :ref:`search` diff --git a/docs/faqs/max_execution_time.rst b/docs/faqs/max_execution_time.rst deleted file mode 100644 index 32e763372..000000000 --- a/docs/faqs/max_execution_time.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. _faqs/max_execution_time: - -======================================================================= -What is the maximum execution time for a Qiskit Runtime job or session? -======================================================================= - -Job maximum execution time -*************************** - -To ensure fairness, and as a way to help control cost, there is a -maximum execution time for each Qiskit Runtime job. If -a job exceeds this time limit, it is forcibly cancelled and a ``RuntimeJobMaxTimeoutError`` -exception is raised. - -.. note:: - As of August 7, 2023, the ``max_execution_time`` value is based on system execution time, which is the time that the QPU - complex (including control software, control electronics, QPU, and so on) is engaged in - processing the job, instead of wall clock time. - - Simulator jobs continue to use wall clock time. - -You can set the maximum execution time (in seconds) on the job options by using one of the following methods: - -.. code-block:: python - - # Initiate the Options class with parameters - options = Options(max_execution_time=360) - -.. code-block:: python - - # Create the options object with attributes and values - options = {"max_execution_time": 360} - -You can also find the system execution time for previously completed jobs by using: - -.. code-block:: python - - # Find the system execution time - print(f"Job {job.job_id()} system execution time was {job.metrics()['usage']['seconds']} seconds") - -In addition, the system calculates an appropriate job timeout value based on the -input circuits and options. This system-calculated timeout is currently capped -at 3 hours to ensure fair device usage. If a ``max_execution_time`` is -also specified for the job, the lesser of the two values is used. - -For example, if you specify ``max_execution_time=5000``, but the system determines -it should not take more than 5 minutes (300 seconds) to execute the job, then the job will be -cancelled after 5 minutes. - -Session maximum execution time -******************************* - -When a session is started, it is assigned a maximum session timeout value. After this timeout is reached, the session is terminated, any jobs that are already running continue running, and any queued jobs that remain in the session are put into a failed state. For instructions to set the session maximum time, see `Specify the session length <../how_to/run_session#session_length.html>`__. - - -Other limitations -*************************** - -- Programs cannot exceed 750KB in size. -- Inputs to jobs cannot exceed 64MB in size. -- Open plan users can use up to 10 minutes of system execution time per month (resets at 00:00 UTC on the first of each month). System execution time is the amount of time that the system is dedicated to processing your job. You can track your monthly usage on the `Platform dashboard, `__ `Jobs, `__ and `Account `__ page. \ No newline at end of file diff --git a/docs/faqs/open_source_vs_ibm_cloud_primitives.rst b/docs/faqs/open_source_vs_ibm_cloud_primitives.rst deleted file mode 100644 index 5dfa6678c..000000000 --- a/docs/faqs/open_source_vs_ibm_cloud_primitives.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _faqs/open_source_vs_ibm_cloud_primitives: - -========================================================================================================== -What is the difference between the open source primitives and primitives available through Qiskit Runtime? -========================================================================================================== - -The open source primitive contains the base classes (to define interfaces) and a reference implementation. -The Qiskit Runtime primitives provide more sophisticated implementation (such as with error -mitigation) as a cloud-based service. \ No newline at end of file diff --git a/docs/getting_started.rst b/docs/getting_started.rst deleted file mode 100644 index 026907ab3..000000000 --- a/docs/getting_started.rst +++ /dev/null @@ -1,84 +0,0 @@ -######################################### -Getting started -######################################### - -Install Qiskit packages -======================== - -Installing the following packages lets you create circuits and work with primitives -through Qiskit Runtime: - -.. code-block:: bash - - pip install qiskit - pip install qiskit-ibm-runtime - - -Find your access credentials -============================== - -You can access Qiskit Runtime from either IBM Quantum or IBM Cloud. - -**IBM Quantum** - -`Retrieve your IBM Quantum token `_, and optionally save it for easy access later. - -.. note:: - Account credentials are saved in plain text, so only do so if you are using a trusted device. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Save an IBM Quantum account. - QiskitRuntimeService.save_account(channel="ibm_quantum", token="MY_IBM_QUANTUM_TOKEN") - - - -**IBM Cloud** - -Retrieve your IBM Cloud access credentials, and optionally save it for easy access later. - -* `Retrieve your IBM Cloud token `__ -* To retrieve your Cloud Resource Name (CRN), open the `Instances page `__ and click your instance. In the page that opens, click the icon to copy your CRN. - -.. note:: - Account credentials are saved in plain text, so only do so if you are using a trusted device. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Save an IBM Cloud account. - QiskitRuntimeService.save_account(channel="ibm_cloud", token="MY_IBM_CLOUD_API_KEY", instance="MY_IBM_CLOUD_CRN") - - -Test your setup -============================== - -Run a simple circuit using `Sampler` to ensure that your environment is set up properly: - -.. code-block:: python - - from qiskit.test.reference_circuits import ReferenceCircuits - from qiskit_ibm_runtime import QiskitRuntimeService, Sampler - - # You'll need to specify the credentials when initializing QiskitRuntimeService, if they are not previously saved. - service = QiskitRuntimeService() - backend = service.backend("ibmq_qasm_simulator") - job = Sampler(backend).run(ReferenceCircuits.bell()) - print(f"job id: {job.job_id()}") - result = job.result() - print(result) - - -Getting started with primitives -================================= - -.. nbgallery:: - - tutorials/how-to-getting-started-with-sampler - tutorials/how-to-getting-started-with-estimator - - -`See more tutorials `_ diff --git a/docs/how_to/account-management.rst b/docs/how_to/account-management.rst deleted file mode 100644 index 9555dce1e..000000000 --- a/docs/how_to/account-management.rst +++ /dev/null @@ -1,62 +0,0 @@ -Manage your account -================================= - -Qiskit Runtime is available on both IBM Cloud and IBM Quantum Platform. The former requires an IBM Cloud account and the latter requires an IBM Quantum account. If you don't have the necessary account, refer to the appropriate link: - -* `Setting up your IBM Cloud account `__ -* `Access your IBM Quantum account `__ - -There are several methods for account management. Your account credentials can be saved to disk or used in a session and never saved. - -* `save_account()`: Save your account to disk for future use. -* `delete_account()`: Delete the saved account from disk. -* `active_account()`: List the account currently in the session. -* `saved_account()`: List the account stored on disk. - -Store credentials ------------------ - -The ``save_account()`` method can be used to store your account credentials on disk, in the ``$HOME/.qiskit/qiskit-ibm.json`` file. After the credentials are saved, you will only need to use ``QiskitRuntimeService()`` to initialize your account in the future. - -.. note:: - Account credentials are saved in plain text, so only do so if you are using a trusted device. - -Following are examples of saving an IBM Cloud and an IBM Quantum account. The ``channel`` parameter allows to distinguish between different account types. If you are saving multiple accounts per channel, consider using the ``name`` parameter to differentiate them. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Save an IBM Cloud account on disk. - QiskitRuntimeService.save_account(channel="ibm_cloud", token=<*IBM Cloud API key*>, instance=<*IBM Cloud CRN*> or <*IBM Cloud service name*>) - - # Save an IBM Quantum account on disk. - QiskitRuntimeService.save_account(channel="ibm_quantum", token=<*IBM Quantum API token*>) - -Initialize your account -------------------------- - -You need to initialize your account in a Python session before you can start using Qiskit Runtime. If you have the credentials already saved, you can initialize an ``QiskitRuntimeService`` instance without additional parameters. - -.. code-block:: python - - # Read default credentials from disk. - service = QiskitRuntimeService() - -If you have both an IBM Cloud and an IBM Quantum accounts saved, ``QiskitRuntimeService()`` loads the IBM Cloud account by default. To load the IBM Quantum account instead, specify ``QiskitRuntimeService(channel="ibm_quantum")``. - -Alternatively, if you specified a name for your account when saving it, you can also specify the name of the account to load. - -.. code-block:: python - - # Save an IBM Cloud account on disk and give it a name. - QiskitRuntimeService.save_account(channel="ibm_cloud", token=<*IBM Cloud API key*>, instance=<*IBM Cloud CRN*>, name="prod") - - service = QiskitRuntimeService(name="prod") - -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 - - # Initialize an IBM Cloud account without saving it. - service = QiskitRuntimeService(channel="ibm_cloud", token=<*IBM Cloud API key*>, instance=<*IBM Cloud CRN*>) diff --git a/docs/how_to/backends.rst b/docs/how_to/backends.rst deleted file mode 100644 index 3ec7d47b0..000000000 --- a/docs/how_to/backends.rst +++ /dev/null @@ -1,159 +0,0 @@ -Run on quantum backends -================================= - -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. - -Refer to the `API reference `__ for a complete list of attributes and methods. - -Initialize the service ------------------------- - -Before calling ``IBMBackend``, initialize the service: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Initialize the account first. - service = QiskitRuntimeService() - -List backends -------------- - -Use the ``backends()`` method to list all backends you have access to. This method returns a list of ``IBMBackend`` instances: - -.. code-block:: python - - service.backends() - -.. code-block:: - - [, - , - , - , - ] - -The ``backend()`` (note that this is singular: *backend*) method takes the name of the backend as the input parameter and returns an ``IBMBackend`` instance representing that particular backend: - -.. code-block:: python - - service.backend("ibmq_qasm_simulator") - -.. code-block:: - - - - -Filter backends ----------------- - -You may also optionally filter the set backends, by passing arguments that query the backend's configuration, status, or properties. For more general filters, you can make advanced functions using a lambda function. Refer to the API documentation for more details. - -Let's try getting only backends that fit these criteria: - -* Are real quantum devices (``simulator=False``) -* Are currently operational (``operational=True``) -* Have at least 5 qubits (``min_num_qubits=5``) - -.. code-block:: python - - service.backends(simulator=False, operational=True, min_num_qubits=5) - -A similar method is ``least_busy()``, which takes the same filters as ``backends()`` but returns the backend that matches the filters and has the least number of jobs pending in the queue: - -.. code-block:: python - - service.least_busy(operational=True, min_num_qubits=5) - - -Determine backend attributes -------------------------------------- - -As mentioned previously, the ``IBMBackend`` class attributes provide information about the backend. For example: - -.. code-block:: python - - backend = service.backend("ibmq_qasm_simulator") - backend.name #returns the backend's name - backend.backend_version #returns the version number - backend.simulator #returns True or False, depending on whether it is a simulator - backend.num_qubits #returns the number of qubits the backend has - -See the |IBMBackend_documentation|_ for the full list of backend attributes. - -.. |IBMBackend_documentation| replace:: ``IBMBackend`` class documentation -.. _IBMBackend_documentation: https://qiskit.org/documentation/partners/qiskit_ibm_runtime/stubs/qiskit_ibm_runtime.IBMBackend.html#qiskit_ibm_runtime.IBMBackend - -Find backend information from other channels --------------------------------------------------- - -To find your available systems and simulators on **IBM Cloud**, view the `Compute resources page `__. You must be logged in to see your available compute resources. You are shown a snapshot of each backend. To see full details, click the backend name. You can also search for backends from this page. - -To find your available systems and simulators on **IBM Quantum Platform**, view the `Compute resources page `__. You are shown a snapshot of each backend. To see full details, click the backend name. You can also sort, filter, and search from this page. - -Specify a backend when running a job ---------------------------------------- - -If you are using a runtime session, add the ``backend`` option when starting your session. For details about working with sessions, see `Run a primitive in a session `__. - -.. code-block:: python - - from qiskit.circuit.random import random_circuit - from qiskit.quantum_info import SparsePauliOp - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - circuit = random_circuit(2, 2, seed=1).decompose(reps=1) - observable = SparsePauliOp("IY") - - options = Options() - options.optimization_level = 2 - options.resilience_level = 2 - - service = QiskitRuntimeService() - with Session(service=service, backend="ibmq_qasm_simulator") as session: - estimator = Estimator(session=session, options=options) - job = estimator.run(circuit, observable) - result = job.result() - - display(circuit.draw("mpl")) - print(f" > Observable: {observable.paulis}") - print(f" > Expectation value: {result.values[0]}") - print(f" > Metadata: {result.metadata[0]}") - - -If you are not using a runtime session, you can pass the backend when initializing the primitive class. - -.. code-block:: python - - from qiskit.circuit.random import random_circuit - from qiskit.quantum_info import SparsePauliOp - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - circuit = random_circuit(2, 2, seed=1).decompose(reps=1) - observable = SparsePauliOp("IY") - - options = Options() - options.optimization_level = 2 - options.resilience_level = 2 - - service = QiskitRuntimeService() - backend = service.backend("ibmq_qasm_simulator") - estimator = Estimator(backend, options=options) - job = estimator.run(circuit, observable) - result = job.result() - - display(circuit.draw("mpl")) - print(f" > Observable: {observable.paulis}") - print(f" > Expectation value: {result.values[0]}") - print(f" > Metadata: {result.metadata[0]}") diff --git a/docs/how_to/error-mitigation.rst b/docs/how_to/error-mitigation.rst deleted file mode 100644 index 166916fc2..000000000 --- a/docs/how_to/error-mitigation.rst +++ /dev/null @@ -1,228 +0,0 @@ -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 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. - -Given this, each level corresponds to a method or methods with increasing level of quantum sampling overhead to enable you experiment with different time-accuracy tradeoffs. The following table shows you which levels and corresponding methods are available for each of the primitives. - -.. note:: - Error mitigation is task specific so the techniques you are able to apply vary based whether you are sampling a distribution or generating expectation values. - -+------------------+-------------------------------------------------------+-----------------------------------+---------+ -| Resilience Level | Definition | Estimator | Sampler | -+==================+=======================================================+===================================+=========+ -| 0 | No mitigation | None | None | -+------------------+-------------------------------------------------------+-----------------------------------+---------+ -| 1 [Default] | Minimal mitigation costs: Mitigate error associated | Twirled Readout Error eXtinction | M3 | -| | with readout errors | (:ref:`TREX `) | | -+------------------+-------------------------------------------------------+-----------------------------------+---------+ -| 2 | Medium mitigation costs. Typically reduces bias | Zero Noise Extrapolation | --- | -| | in estimators, but is not guaranteed to be zero bias. | (:ref:`ZNE `) | | -+------------------+-------------------------------------------------------+-----------------------------------+---------+ -| 3 | Heavy mitigation with layer sampling. Theoretically | Probabilistic Error Cancellation | --- | -| | expected to deliver zero bias estimators. | (:ref:`PEC `) | | -+------------------+-------------------------------------------------------+-----------------------------------+---------+ - -.. note:: - 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. Specific error mitigation methods are not guaranteed to be applied at each resilience level. - -Configure the Estimator with resilience levels ------------------------------------------------ - -.. raw:: html - -
- Resilience Level 0 - -No error mitigation is applied to the user program. - -.. raw:: html - -
- -.. raw:: html - -
- Resilience Level 1 - -.. _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 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 - -
- -.. raw:: html - -
- Resilience Level 2 - -.. _ZNE: - -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. - - Illustration of the ZNE method - -The overhead of this method scales with the number of noise factors. The default settings sample the expectation value at three noise factors, leading to a roughly 3x overhead when employing this resilience level. - -.. raw:: html - -
- -.. raw:: html - -
- Resilience Level 3 - -.. _PEC: - -Level 3 enables the Probabilistic Error Cancellation (PEC) method. This approach mitigates error by learning and inverting a sparse noise model that is able to capture correlated noise. PEC returns an unbiased estimate of an expectation value so long as learned noise model faithfully represents the actual noise model at the time of mitigation. In practice, the experimental procedure for learning the noise model has ambiguities due to certain error terms that cannot be independently distinguished. These are resolved by a symmetry assumption, which depending on the true underlying noise may lead a biased estimate of the mitigated expectation values due to using an imperfect noise model. - -The Qiskit Runtime primitive implementation of PEC specifically addresses noise in self-inverse two-qubit gates, so it first *stratifies* each input circuit into an alternating sequence of simultaneous 1-qubit gates followed by a layer of simultaneous 2-qubit gates. Then it learns the noise model associated with each unique 2-qubit gate layer. - -.. figure:: ../images/stratified.png - :alt: This image shows a stratified circuit. - - This is an example of a `stratified` circuit, where the layers of two-qubit gates are labeled layer 1 through n. Note that each :math:`U_l` is composed of two-qubit gates on the native connectivity graph of the quantum processor. The open boxes represent arbitrary single-qubit gates. - -The overhead of this method scales with the number of noise factors. The default settings sample the expectation value at three noise factors, leading to a roughly 3x overhead when employing this resilience level. - -PEC uses a quasi-probability method to mimic the effect of inverting the learned noise. This requires sampling from a randomized circuit family associated with the user’s original circuit. Applying PEC will increase the variability of the returned expectation value estimates unless the number of samples per circuit is also increased for both input and characterization circuits. The amount of samples required to counter this variability scales exponentially with the noise strength of the mitigated circuit. - -How this works: - -When estimating an unmitigated Pauli observable :math:`\langle P\rangle` the standard error in the estimated expectation value is given by :math:`\frac{1}{\sqrt{N_{\mbox{shots}}}}\left(1- \langle P\rangle^2\right)` where :math:`N_{\mbox{shots}}` is the number of shots used to estimate :math:`\langle P\rangle`. When applying PEC mitigation, the standard error becomes :math:`\sqrt{\frac{S}{N_{\mbox{samples}}}}\left(1- \langle P\rangle^2\right)` where :math:`N_{\mbox{samples}}` is the number of PEC samples. - -The sampling overhead scales exponentially with a parameter that characterizes the collective noise of the input circuit. As the Qiskit Runtime primitive learns the noise of your circuit, it will return metadata about the sampling overhead associated with that particular layer. Let's label the overhead of layer :math:`l` as :math:`\gamma_l`. Then the total sampling overhead for mitigating your circuit is the product of all the layer overheads, that is: - -:math:`S = \prod_l \gamma_l` - -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 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 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 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 - -
- -Example -^^^^^^^ - -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 - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - service = QiskitRuntimeService() - options = Options() - options.resilience_level = 2 - options.optimization_level = 3 - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - estimator = Estimator(session=session, options=options) - job = estimator.run(circuits=[psi1], observables=[H1], parameter_values=[theta1]) - psi1_H1 = job.result() - -.. note:: - 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. - Note that higher resilience levels do not guarantee better quality. Higher levels only mean greater overhead. Each method has its strengths and weaknesses. For example, TREX (Twirled Readout Error eXtinction) is good for shallow circuits because of its readout error mitigation whereas ZNE (Zero Noise Extrapolation) is good for deeper circuits. PEC can mitigate arbitrary errors but may not work in practice because of its large overhead. - -Configure Sampler with resilience levels ------------------------------------------ - - -The Sampler default resilience setting (level 1) enables readout error mitigation to allow users to generate mitigated quasi-probability distributions. - -.. raw:: html - -
- Resilience Level 1 - -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. - - Illustration of the M3 method - -.. raw:: html - -
- -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Options - - service = QiskitRuntimeService() - options = Options() - options.resilience_level = 1 - options.optimization_level = 3 - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - sampler = Sampler(session=session, options=options) - -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. We will soon add options to tune other resilience levels that include PEC. - -+---------------------------------------------------------------+----------------------------------+--------------------------------------------------------+ -| Options | Inputs | Description | -+===============================================================+==================================+========================================================+ -| options.resilience.noise_amplifier(Optional[str]) | ``LocalFoldingAmplifier`` | Amplifies noise of all gates by performing local | -| (currently only one available option) | | gate folding. | -+---------------------------------------------------------------+----------------------------------+--------------------------------------------------------+ -| options.resilience.noise_factors((Optional[Sequence[float]]) | (1, 3, 5) [Default] | Noise amplification factors, where `1` represents the | -| | | baseline noise. They all need to be greater than or | -| | | equal to the baseline. | -+---------------------------------------------------------------+----------------------------------+--------------------------------------------------------+ -| options.resilience.extrapolator(Optional[str]) | ``LinearExtrapolator`` [Default] | Polynomial extrapolation of degree one. | -| +----------------------------------+--------------------------------------------------------+ -| | ``QuadraticExtrapolator`` | Polynomial extrapolation of degree two and lower. | -| +----------------------------------+--------------------------------------------------------+ -| | ``CubicExtrapolator`` | Polynomial extrapolation of degree three and lower. | -| +----------------------------------+--------------------------------------------------------+ -| | ``QuarticExtrapolator`` | Polynomial extrapolation of degree four and lower. | -+---------------------------------------------------------------+----------------------------------+--------------------------------------------------------+ - -Example of adding ``resilience_options`` into your estimator session -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - service = QiskitRuntimeService() - options = Options() - options.optimization_level = 3 - options.resilience_level = 2 - options.resilience.noise_factors = (1, 2, 3, 4) - options.resilience.noise_amplifier = 'LocalFoldingAmplifier' - options.resilience.extrapolator = 'QuadraticExtrapolator' - - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - estimator = Estimator(session=session, options=options) - job = estimator.run(circuits=[psi1], observables=[H1], parameter_values=[theta1]) - psi1_H1 = job.result() - diff --git a/docs/how_to/error-suppression.rst b/docs/how_to/error-suppression.rst deleted file mode 100644 index 71cb45834..000000000 --- a/docs/how_to/error-suppression.rst +++ /dev/null @@ -1,103 +0,0 @@ -Configure error suppression -============================= - -Error suppression techniques optimize and transform your circuit at the point of compilation to minimize errors. This is the most basic error handling technique. - -Error suppression typically results in some classical pre-processing overhead to your overall runtime. Therefore, it is important to achieve a balance between perfecting your results and ensuring that your job completes in a reasonable amount of time. - -Primitives let you employ error suppression techniques by setting the optimization level (``optimization_level`` option) and by choosing advanced transpilation options. - -Setting the optimization level -------------------------------- - -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. - -..note:: - When using primitives, optimization levels 2 and 3 behave like level 1. - -+--------------------+---------------------------------------------------------------------------------------------------+ -| Optimization Level | Estimator & Sampler | -+====================+===================================================================================================+ -| 0 | No optimization: typically used for hardware characterization | -| | | -| | - basic translation | -| | - layout (as specified) | -| | - routing (stochastic swaps) | -| | | -+--------------------+---------------------------------------------------------------------------------------------------+ -| 1, 2, 3 | Light optimization: | -| | | -| | - Layout (trivial → vf2 → SabreLayout if routing is required) | -| | - routing (SabreSWAPs if needed) | -| | - 1Q gate optimization | -| | - Error Suppression: Dynamical Decoupling | -| | | -+--------------------+---------------------------------------------------------------------------------------------------+ - -..note:: - If you want to use more advanced optimization, use the Qiskit transpiler locally and then pass the transpiled circuits to the primitives. For instructions see the `Submitting user-transpiled circuits using primitives `__ tutorial. - -Example: configure Estimator with optimization levels -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - from qiskit.circuit.library import RealAmplitudes - from qiskit.quantum_info import SparsePauliOp - - service = QiskitRuntimeService() - options = Options(optimization_level=1) - - psi = RealAmplitudes(num_qubits=2, reps=2) - H = SparsePauliOp.from_list([("II", 1), ("IZ", 2), ("XI", 3)]) - theta = [0, 1, 1, 2, 3, 5] - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - estimator = Estimator(session=session, options=options) - job = estimator.run(circuits=[psi], observables=[H], parameter_values=[theta]) - psi1_H1 = job.result() - -.. note:: - If optimization level is not specified, the service uses ``optimization_level = 1``. - -Example: configure Sampler with optimization levels -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Options - - service = QiskitRuntimeService() - options = Options(optimization_level=1) - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - sampler = Sampler(session=session, options=options) - -Advanced transpilation options ------------------------------- - -You also have the ability to tune a variety of advanced options to configure your transpilation strategy further. These methods can be used alongside optimization levels. They allow you to change the options of interest and let your optimization level manage the rest. - -Most of the transpilation options are inherited from `qiskit.compiler.transpile `__. - -+---------------------------------------------------------------+-------------------------------------------------------------------------+ -| Options | Description | -+===============================================================+=========================================================================+ -| options.transpilation.initial_layout(Union[dict, List, None]) | Initial position of virtual qubits on physical qubits. | -+---------------------------------------------------------------+-------------------------------------------------------------------------+ -| options.transpilation.layout_method (Optional[str]) | Name of layout selection pass. One of ``trivial``, ``dense``, | -| | ``noise_adaptive``, ``sabre``. | -+---------------------------------------------------------------+-------------------------------------------------------------------------+ -| options.transpilation.routing_method (Optional[str]) | Name of routing pass: ``basic``, ``lookahead``, ``stochastic``, | -| | ``sabre``, ``none``. | -+---------------------------------------------------------------+-------------------------------------------------------------------------+ -| options.transpilation.skip_transpilation (bool) | This option is specific to Qiskit Runtime primitives. | -| | Allows for skipping transpilation entirely. If you use this method, | -| | make sure to verify that your circuit in written using the basis gates | -| | on the backend you are running on. | -+---------------------------------------------------------------+-------------------------------------------------------------------------+ -| options.transpilation.approximation_degree (Optional[float]) | heuristic dial used for circuit approximation | -| | (1.0=no approximation, 0.0=maximal approximation). | -| | Defaults to no approximation for all optimization levels | -+---------------------------------------------------------------+-------------------------------------------------------------------------+ \ No newline at end of file diff --git a/docs/how_to/noisy_simulators.rst b/docs/how_to/noisy_simulators.rst deleted file mode 100644 index 961309c0d..000000000 --- a/docs/how_to/noisy_simulators.rst +++ /dev/null @@ -1,449 +0,0 @@ -Noisy simulators in Qiskit Runtime -================================== - -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, follow `these -steps `__ -to set one up. - -.. code-block:: python - - # load necessary Runtime libraries - from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Estimator, Session, Options - - service = QiskitRuntimeService(channel="ibm_quantum") - -Preparing the environment -------------------------- - -To demonstrate the routine, we shall proceed with running an example -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 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 `__ -and `Advanced -Circuits `__ -in Qiskit documentation. - -.. code-block:: python - - from qiskit.circuit import Parameter - from qiskit import QuantumCircuit - - theta = Parameter('theta') - - qc = QuantumCircuit(2,1) - qc.x(1) - qc.h(0) - qc.cp(theta,0,1) - qc.h(0) - qc.measure(0,0) - - qc.draw('mpl') - - - - -.. image:: ../images/noisy-sim-circuit.png - - - -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 - - import numpy as np - - phases = np.linspace(0, 2*np.pi, 50) - - # phases need to be expressed as a list of lists in order to work - individual_phases = [[phase] for phase in phases] - -Running on the ideal simulator ------------------------------- - -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 in the following -code: - -.. code-block:: python - - backend = "ibmq_qasm_simulator" # use the simulator - -.. code-block:: python - - options = Options() - options.simulator.seed_simulator = 42 - options.execution.shots = 1000 - options.optimization_level = 0 # no optimization - options.resilience_level = 0 # no error mitigation - -Run the circuits on Sampler -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We shall now sample the circuit to get the result probability -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 -primitive `__. - -.. code-block:: python - - with Session(service=service, backend=backend): - sampler = Sampler(options=options) - job = sampler.run( - circuits=[qc]*len(phases), - parameter_values=individual_phases - ) - result = job.result() - -.. code-block:: python - - import matplotlib.pyplot as plt - - # the probablity of being in the 1 state for each of these values - prob_values = [dist.get(1, 0) for dist in result.quasi_dists] - - plt.plot(phases, prob_values, 'o', label='Simulator') - plt.plot(phases, np.sin(phases/2,)**2, label='Theory') - plt.xlabel('Phase') - plt.ylabel('Probability') - plt.legend() - - - - -.. parsed-literal:: - - - - - - -.. image:: ../images/noisy-sim-sampler-ideal.png - - -Run the circuits on Estimator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -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 -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 -``remove_final_measurements``. - -.. code-block:: python - - qc_no_meas = qc.remove_final_measurements(inplace=False) - qc_no_meas.draw('mpl') - - - - -.. image:: ../images/noisy-sim-estimator-circuit.png - - - -.. code-block:: python - - from qiskit.quantum_info import SparsePauliOp - - ZZ = SparsePauliOp.from_list([("ZZ", 1)]) - print(f" > Observable: {ZZ.paulis}") - - -.. parsed-literal:: - - > Observable: ['ZZ'] - - -With this observable, the expectation value is calculated by the -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 this as shown. - -.. code-block:: python - - with Session(service=service, backend=backend): - estimator = Estimator(options=options) - job = estimator.run( - circuits=[qc_no_meas]*len(phases), - parameter_values=individual_phases, - observables=[ZZ]*len(phases) - ) - result = job.result() - -.. code-block:: python - - exp_values = result.values - - plt.plot(phases, exp_values, 'o', label='Simulator') - plt.plot(phases, 2*np.sin(phases/2)**2-1, label='Theory') - plt.xlabel('Phase') - plt.ylabel('Expectation') - plt.legend() - - - - -.. parsed-literal:: - - - - - - -.. image:: ../images/noisy-sim-estimator-ideal.png - - -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 -``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 -Provider `__ -in Qiskit documentation. - -Since we are trying to mimic a real backend, we can also pass in the -``coupling_map`` that the backend topology has and the ``basis_gates`` -that the backend supports to have a more realistic noisy simulation. - -.. code-block:: python - - from qiskit.providers.fake_provider import FakeManila - from qiskit_aer.noise import NoiseModel - - # Make a noise model - fake_backend = FakeManila() - noise_model = NoiseModel.from_backend(fake_backend) - - # Set options to include the noise model - options = Options() - options.simulator = { - "noise_model": noise_model, - "basis_gates": fake_backend.configuration().basis_gates, - "coupling_map": fake_backend.configuration().coupling_map, - "seed_simulator": 42 - } - - # Set number of shots, optimization_level and resilience_level - options.execution.shots = 1000 - options.optimization_level = 0 - options.resilience_level = 0 - -:meth:`~.options.SimulatorOptions.set_backend` is the syntactic sugar for setting options. -The following code is equivalent. - -.. code-block:: python - - from qiskit.providers.fake_provider import FakeManila - - # Make a noise model - fake_backend = FakeManila() - - # Set options to include the noise model - options = Options() - options.simulator.set_backend(fake_backend) - options.simulator.seed_simulator = 42 - - # Set number of shots, optimization_level and resilience_level - options.execution.shots = 1000 - options.optimization_level = 0 - options.resilience_level = 0 - -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 previously. - -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 - - # Set options to include the noise model with error mitigation - options_with_em = Options() - options_with_em.simulator = { - "noise_model": noise_model, - "basis_gates": fake_backend.configuration().basis_gates, - "coupling_map": fake_backend.configuration().coupling_map, - "seed_simulator": 42 - } - - # Set number of shots, optimization_level and resilience_level - options_with_em.execution.shots = 1000 - options_with_em.optimization_level = 0 # no optimization - options_with_em.resilience_level = 1 # M3 for Sampler and T-REx for Estimator - -When you set the ``resilience_level`` to 1, M3 is activated in Sampler. -All available resilience level configurations can be found -`here `__. - -.. code-block:: python - - with Session(service=service, backend=backend): - # include the noise model without M3 - sampler = Sampler(options=options) - job = sampler.run( - circuits=[qc]*len(phases), - parameter_values=individual_phases - ) - result = job.result() - prob_values = [1-dist[0] for dist in result.quasi_dists] - - # include the noise model with M3 - sampler = Sampler(options=options_with_em) - job = sampler.run( - circuits=[qc]*len(phases), - parameter_values=individual_phases - ) - result = job.result() - prob_values_with_em = [1-dist[0] for dist in result.quasi_dists] - -.. code-block:: python - - plt.plot(phases, prob_values, 'o', label='Noisy') - plt.plot(phases, prob_values_with_em, 'o', label='Mitigated') - plt.plot(phases, np.sin(phases/2,)**2, label='Theory') - plt.xlabel('Phase') - plt.ylabel('Probability') - plt.legend() - - - - -.. parsed-literal:: - - - - - - -.. image:: ../images/noisy-sim-sampler-noisy.png - - -``T-REx`` is triggered in Estimator when the resilience level is set to -1. - -.. code-block:: python - - with Session(service=service, backend=backend): - # include the noise model without T-REx - estimator = Estimator(options=options) - job = estimator.run( - circuits=[qc_no_meas]*len(phases), - parameter_values=individual_phases, - observables=[ZZ]*len(phases) - ) - result = job.result() - exp_values = result.values - - # include the noise model with T-REx - estimator = Estimator(options=options_with_em) - job = estimator.run( - circuits=[qc_no_meas]*len(phases), - parameter_values=individual_phases, - observables=[ZZ]*len(phases)) - result = job.result() - exp_values_with_em = result.values - -.. code-block:: python - - plt.plot(phases, exp_values, 'o', label='Noisy') - plt.plot(phases, exp_values_with_em, 'o', label='Mitigated') - plt.plot(phases, 2*np.sin(phases/2)**2-1, label='Theory') - plt.xlabel('Phase') - plt.ylabel('Expectation') - plt.legend() - - - - -.. parsed-literal:: - - - - - - -.. 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 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 previous examples, check out this tutorial: -`Error suppression and error mitigation with Qiskit -Runtime `__. - -.. code-block:: python - - import qiskit_ibm_runtime - qiskit_ibm_runtime.version.get_version_info() - - - - -.. parsed-literal:: - - '0.8.0' - - - -.. code-block:: python - - from qiskit.tools.jupyter import * - %qiskit_version_table - - - -.. raw:: html - -

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.2
qiskit-aer0.11.1
qiskit-ibmq-provider0.19.2
qiskit0.39.2
qiskit-nature0.5.0
qiskit-finance0.3.4
qiskit-optimization0.4.0
qiskit-machine-learning0.5.0
System information
Python version3.8.13
Python compilerGCC 10.3.0
Python builddefault, Mar 25 2022 06:04:10
OSLinux
CPUs8
Memory (Gb)31.211326599121094
Wed Nov 30 02:43:41 2022 UTC
- diff --git a/docs/how_to/options.rst b/docs/how_to/options.rst deleted file mode 100644 index e2ab0bb56..000000000 --- a/docs/how_to/options.rst +++ /dev/null @@ -1,52 +0,0 @@ -Configure primitive options -=========================== - -When calling the primitives, you can pass in options, as shown in the line ``estimator = Estimator(options=options)`` in the following code example: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - service = QiskitRuntimeService() - options = Options(optimization_level=1) - # Options class also supports auto-completion. - options.resilience_level = 1 - # And are grouped by the category for easy search. - option.execution.shots = 1000 - - with Session(service=service, backend="ibmq_qasm_simulator"): - estimator = Estimator(options=options) - -You can also overwrite specific options for a job when calling ``run()``. In the following code example, the job will run with optimization level 1 and 4000 shots (instead of 1000): - -.. code-block:: python - - from qiskit.test.reference_circuits import ReferenceCircuits - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Sampler, Options - - service = QiskitRuntimeService() - backend = service.backend("ibmq_qasm_simulator") - options = Options() - options.optimization_level = 1 - option.execution.shots = 1000 - - sampler = Sampler(backend, options=options) - job = sampler.run(ReferenceCircuits.bell(), shots=4000) - - -The most commonly used options are for error suppression and mitigation, which are described in this topic. For a full list of available options, see the `Options API reference `__. - -Overview of error suppression and mitigation --------------------------------------------- - -No computing platform is perfect, and because quantum computers are such new and complex technology, we have to find new ways of dealing with these imperfections. There are several possible causes for errors: “noise” - disturbances in the physical environment, and “bit errors”, which cause the qubit's value or phase to change. IBM builds redundancy into the hardware to ensure that even if some qubits error out, an accurate result is still returned. However, we can further address errors by using error suppression and error mitigation techniques These strategies make use of pre- and post-processing to improve the quality of the results produced for the input circuit. - -* **Error suppression**: Techniques that optimize and transform your circuit at the point of compilation to minimize errors. This is the most basic error handling technique. Error suppression typically results in some classical pre-processing overhead to your overall runtime. - -Primitives let you employ error suppression techniques by setting the optimization level (``optimization_level`` option) and by choosing advanced transpilation options. See `Configure error suppression `__ for details. - -* **Error mitigation**: Techniques that 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`` when submitting your job. See `Configure error mitigation `__ for details. - - diff --git a/docs/how_to/retrieve_results.rst b/docs/how_to/retrieve_results.rst deleted file mode 100644 index 85f72bded..000000000 --- a/docs/how_to/retrieve_results.rst +++ /dev/null @@ -1,43 +0,0 @@ -Retrieve job results -================================= - -After submitting your job, a `RuntimeJob `_ instance is returned. Use the job instance to check the job status or retrieve the results by calling the appropriate method: - -.. list-table:: Job methods - - * - job.result() - - Review job results immediately after the job completes. Job results are available after the job completes. Therefore, `job.result()` is a blocking call until the job completes. - * - job.job_id() - - Return the ID that uniquely identifies that job. Retrieving the job results at a later time requires the job ID. Therefore, it is recommended that you save the IDs of jobs you might want to retrieve later. - * - job.status() - - Check the job status. - * - job = service.job() - - Retrieve a job you previously submitted. This call requires the job ID. - -Jobs are also listed on the Jobs page for your quantum service channel: - -* For the IBM Cloud channel, from the IBM Cloud console quantum `Instances page `__, click the name of your instance, then click the Jobs tab. To see the status of your job, click the refresh arrow in the upper right corner. -* For the IBM Quantum channel, in IBM Quantum platform, open the `Jobs page `__. - - -Retrieve job results at a later time -************************************ - -Call `service.job()` to retrieve a job you previously submitted. If you don't have the job ID, or if you want to retrieve multiple jobs at once; including jobs from retired systems, call `service.jobs()` with optional filters instead. See `QiskitRuntimeService.jobs `__. - -.. note:: - `service.jobs()` returns only Qiskit Runtime jobs. To retrieve other jobs, use `qiskit-ibm-provider `__ instead. - -Example -------- - -This example returns the 10 most recent runtime jobs that were run on ``ibmq_qasm_simulator``: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - # Initialize the account first. - service = QiskitRuntimeService() - - service.jobs(backend_name="ibmq_qasm_simulator") diff --git a/docs/how_to/run_session.rst b/docs/how_to/run_session.rst deleted file mode 100644 index 9511f74b0..000000000 --- a/docs/how_to/run_session.rst +++ /dev/null @@ -1,295 +0,0 @@ -Run jobs in a session -================================= - -There are several ways to set up and use sessions. The following information should not be considered mandatory steps to follow. Instead, choose the configuration that best suits your needs. To learn more about sessions, see `Introduction to sessions <../sessions.html>`__. This information assumes that you are using Qiskit Runtime `primitives <../primitives.html>`__. - -Prerequisites --------------- - -Before starting a session, you must `Set up Qiskit Runtime `__ and initialize it as a service: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - service = QiskitRuntimeService() - -Open a session ------------------ - -You can open a runtime session by using the context manager `with Session(…)` or by initializing the `Session` class. When you start a session, you can specify options, such as the backend to run on. This topic describes the most commonly used options. For the full list, see the `Sessions API documentation `__. - -.. important:: - If the first session job is canceled, subsequent session jobs will all fail. - -**Session class** - -A session can be created by initializing the `Session` class, which can then be passed to the desired primitives. Example: - -.. code-block:: python - - session= Session(service=service, backend="ibmq_qasm_simulator") - estimator = Estimator(session=session) - sampler = Sampler(session=session) - -**Context manager** - -The context manager automatically opens and closes a session for you. A session is started when the first primitive job in this context manager starts (not when it is queued). Primitives created in the context automatically use that session. Example: - -.. code-block:: python - - with Session(service=service, backend="ibmq_qasm_simulator"): - estimator = Estimator() - sampler = Sampler() - - -Specify a backend ------------------ - -When you start a session, you can specify session options, such as the backend to run on. A backend is required if you are using the IBM Quantum channel, but optional if you are using the IBM Cloud channel. Once specified, you cannot change the backend used for a session and you cannot specify multiple backends within a session. To use a different backend, open a new session. - -There are two ways to specify a backend in a session: - -**Directly specify a string with the backend name.** - -Example: - -.. code-block:: python - - service = QiskitRuntimeService() - with Session(service=service, backend="ibmq_qasm_simulator"): - ... - -**Pass the backend object.** Example: - -.. code-block:: python - - backend = service.get_backend("ibmq_qasm_simulator") - with Session(backend=backend): - ... - -.. _session_length: - -Specify the session length --------------------------- - -When a session is started, it is assigned a maximum session timeout value. After the session has been open the specified amount of time, the session expires and is forcefully closed. You can no longer submit jobs to that session. See `What happens when a session ends <../sessions.html#ends>`__ for further details. - -You can configure the maximum session timeout value through the ``max_time`` parameter, which can be specified as seconds (int) or a string, like "2h 30m 40s". This value has to be greater than the ``max_execution_time`` of the job and less than the system’s ``max_time``. The default value is the system’s ``max_time``. See `Determine session details <#determine-session-details>`__ to determine the system limit. - -When setting the session length, consider how long each job within the session might take. For example, if you run five jobs within a session and each job is estimated to be five minutes long, the maximum time for the session should at least 25 min. - -.. code-block:: python - - with Session(service=service, backend=backend, max_time="25m"): - ... - -There is also an interactive timeout value (ITTL) that cannot be configured. If no session jobs are queued within that window, the session is temporarily deactivated. For more details about session length and timeout, see `How long a session stays active <../sessions.html#active>`__. To determine a session's ITTL, follow the instructions in `Determine session details <#determine-session-details>`__ and look for the ``interactive_timeout`` value. - - -.. _close_session: - -Close a session ---------------- - -With `qiskit-ibm-runtime` 0.13 or later releases, when the session context manager is exited, the session is put into `In progress, not accepting new jobs` status. This means that the session will finish processing all running or queued jobs until the maximum timeout value is reached. After all jobs are completed, the session is immediately closed. This allows the -scheduler to run the next job without waiting for the session interactive timeout, -therefore reducing the average job queueing time. You cannot submit jobs to a -closed session. - -This behavior exists in `qiskit-ibm-runtime` 0.13 or later releases only. Previously, `session.close()` **canceled** the session. - -.. code-block:: python - - with Session(service=service, backend=backend): - estimator = Estimator() - job = estimator.run(...) - - # The session is no longer accepting jobs but the submitted job will run to completion - result = job.result() - -.. _cancel_session: - -Cancel a session ----------------- - -If a session is canceled, the session is put into `Closed` status. Any jobs that are already running continue to run but queued jobs are put into a failed state and no further jobs can be submitted to the session. This is a convenient way to quickly fail all queued jobs within a session. - -### For Qiskit runtime releases 0.13 or later - -Use the `session.cancel()` method to cancel a session. - -.. code-block:: python - - with Session(service=service, backend=backend) as session: - estimator = Estimator() - job1 = estimator.run(...) - job2 = estimator.run(...) - # You can use session.cancel() to fail all pending jobs, for example, - # if you realize you made a mistake. - session.cancel() - -For Qiskit Runtime releases 0.13 or later -+++++++++++++++++++++++++++++++++++++++++ - -Use the `session.cancel()` method to cancel a session. - -.. code-block:: python - - with Session(service=service, backend=backend) as session: - estimator = Estimator() - job1 = estimator.run(...) - job2 = estimator.run(...) - # You can use session.cancel() to fail all pending jobs, for example, - # if you realize you made a mistake. - session.cancel() - -For Qiskit Runtime releases before 0.13 -+++++++++++++++++++++++++++++++++++++++++ - -Use the `session.close()` method to cancel a session. This allows the -scheduler to run the next job without waiting for the session timeout, -therefore making it easier for everyone. You cannot submit jobs to a -closed session. - -.. code-block:: python - - with Session(service=service, backend=backend) as session: - estimator = Estimator() - job = estimator.run(...) - # Do not close here, the job might not be completed! - result = job.result() - # Reaching this line means that the job is finished. - # This close() method would fail all pending jobs. - session.close() - -Invoke multiple primitives in a session ----------------------------------------- -You are not restricted to a single primitive function within a session. In this section we will show you an example of using multiple primitives. - -First we prepare a circuit for the Sampler primitive. - -.. code-block:: python - - from qiskit.circuit.random import random_circuit - - sampler_circuit = random_circuit(2, 2, seed=0).decompose(reps=1) - sampler_circuit.measure_all() - display(circuit.draw("mpl")) - -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. - -.. code-block:: python - - from qiskit_ibm_runtime import Session, Sampler, Estimator - - with Session(backend=backend): - sampler = Sampler() - estimator = Estimator() - - result = sampler.run(sampler_circuit).result() - print(f">>> Quasi-probability distribution from the sampler job: {result.quasi_dists[0]}") - - result = estimator.run(circuit, observable).result() - print(f">>> Expectation value from the estimator job: {result.values[0]}") - -The calls can also be synchronous. You don’t need to wait for the result of a previous job before submitting another one, as shown below: - -.. code-block:: python - - from qiskit_ibm_runtime import Session, Sampler, Estimator - - with Session(backend=backend): - sampler = Sampler() - estimator = Estimator() - - sampler_job = sampler.run(sampler_circuit) - estimator_job = estimator.run(circuit, observable) - - print( - f">>> Quasi-probability distribution from the sampler job: {sampler_job.result().quasi_dists[0]}" - ) - print(f">>> Expectation value from the estimator job: {estimator_job.result().values[0]}") - -.. _session_status: - -Query session status ---------------------- - - -You can query the status of a session using `session.status()`. You can also view a session's status on the Jobs page for your channel. - -Session status can be one of the following: - -- `Pending`: Session has not started or has been deactivated. The next session job needs to wait in the queue like other jobs. -- `In progress, accepting new jobs`: Session is active and accepting new jobs. -- `In progress, not accepting new jobs`: Session is active but not accepting new jobs. Job submission to the session will be rejected, but outstanding session jobs will run to completion. The session will be automatically closed once all jobs finish. -- `Closed`: Session maximum timeout value has been reached, or session was explicitly closed. - -.. _session_details: - -Determine session details --------------------------- - -You can find details about a session by using the `session.details()` method, from the `Quantum Platform Jobs page `__, or from the IBM Cloud Jobs page, which you access from your `Instances page `__. From the session details you can determine the `maximum <..sessions#max-ttl.html>`__ and `interactive <..sessions#ttl.html>`__ time to live (TTL) values, its status, whether it's currently accepting jobs, and more. - -Example: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - - service = QiskitRuntimeService() - - with Session(service=service, backend="ibmq_qasm_simulator") as session: - estimator = Estimator() - job = estimator.run(circuit, observable) - print(session.details()) - -Output: - -.. code-block:: text - - { - 'id': 'cki5d18m3kt305s4pndg', - 'backend_name': 'ibm_algiers', - 'interactive_timeout': 300, # This is the interactive timeout, in seconds - 'max_time': 28800, # This is the maximum session timeout, in seconds - 'active_timeout': 28800, - 'state': 'closed', - 'accepting_jobs': True, - 'last_job_started': '2023-10-09T19:37:42.004Z', - 'last_job_completed': '2023-10-09T19:38:10.064Z', - 'started_at': '2023-10-09T19:37:42.004Z', - 'closed_at': '2023-10-09T19:38:39.406Z' - } - - -Full example ------------- - -In this example, we start a session, run an Estimator job, and output the result: - -.. code-block:: python - - from qiskit.circuit.random import random_circuit - from qiskit.quantum_info import SparsePauliOp - from qiskit_ibm_runtime import QiskitRuntimeService, Session, Estimator, Options - - circuit = random_circuit(2, 2, seed=1).decompose(reps=1) - observable = SparsePauliOp("IY") - - options = Options() - options.optimization_level = 2 - options.resilience_level = 2 - - service = QiskitRuntimeService() - with Session(service=service, backend="ibmq_qasm_simulator"): - estimator = Estimator(options=options) - job = estimator.run(circuit, observable) - result = job.result() - - display(circuit.draw("mpl")) - print(f" > Observable: {observable.paulis}") - print(f" > Expectation value: {result.values[0]}") - print(f" > Metadata: {result.metadata[0]}") \ No newline at end of file diff --git a/docs/images/Runtime_Accounting_Diagram.png b/docs/images/Runtime_Accounting_Diagram.png deleted file mode 100644 index 463eddb4b..000000000 Binary files a/docs/images/Runtime_Accounting_Diagram.png and /dev/null differ diff --git a/docs/images/batch.png b/docs/images/batch.png deleted file mode 100644 index 09ed05e83..000000000 Binary files a/docs/images/batch.png and /dev/null differ diff --git a/docs/images/check.png b/docs/images/check.png deleted file mode 100644 index 0cd006ab2..000000000 Binary files a/docs/images/check.png and /dev/null differ diff --git a/docs/images/clock.png b/docs/images/clock.png deleted file mode 100644 index 7dbc82ea3..000000000 Binary files a/docs/images/clock.png and /dev/null differ diff --git a/docs/images/close.png b/docs/images/close.png deleted file mode 100644 index 972705152..000000000 Binary files a/docs/images/close.png and /dev/null differ diff --git a/docs/images/compare-code.png b/docs/images/compare-code.png deleted file mode 100644 index e0339b3f1..000000000 Binary files a/docs/images/compare-code.png and /dev/null differ diff --git a/docs/images/compare-code.psd b/docs/images/compare-code.psd deleted file mode 100644 index 9221a95ea..000000000 Binary files a/docs/images/compare-code.psd and /dev/null differ diff --git a/docs/images/estimator.png b/docs/images/estimator.png deleted file mode 100644 index 4c9b0483c..000000000 Binary files a/docs/images/estimator.png and /dev/null differ diff --git a/docs/images/execution-paths.png b/docs/images/execution-paths.png deleted file mode 100644 index 415d53804..000000000 Binary files a/docs/images/execution-paths.png and /dev/null differ diff --git a/docs/images/ibm-quantum-logo.png b/docs/images/ibm-quantum-logo.png deleted file mode 100644 index 252c31b2f..000000000 Binary files a/docs/images/ibm-quantum-logo.png and /dev/null differ diff --git a/docs/images/instances.png b/docs/images/instances.png deleted file mode 100644 index 306d6d66a..000000000 Binary files a/docs/images/instances.png and /dev/null differ diff --git a/docs/images/iterative.png b/docs/images/iterative.png deleted file mode 100644 index 93f03e166..000000000 Binary files a/docs/images/iterative.png and /dev/null differ diff --git a/docs/images/jobs-failing.png b/docs/images/jobs-failing.png deleted file mode 100644 index 6c3da553e..000000000 Binary files a/docs/images/jobs-failing.png and /dev/null differ diff --git a/docs/images/logo.png b/docs/images/logo.png deleted file mode 100644 index c4f83672e..000000000 Binary files a/docs/images/logo.png and /dev/null differ diff --git a/docs/images/m3.png b/docs/images/m3.png deleted file mode 100644 index 0feed9313..000000000 Binary files a/docs/images/m3.png and /dev/null differ diff --git a/docs/images/noisy-sim-circuit.png b/docs/images/noisy-sim-circuit.png deleted file mode 100644 index 28d6fad02..000000000 Binary files a/docs/images/noisy-sim-circuit.png and /dev/null differ diff --git a/docs/images/noisy-sim-estimator-circuit.png b/docs/images/noisy-sim-estimator-circuit.png deleted file mode 100644 index 71797512c..000000000 Binary files a/docs/images/noisy-sim-estimator-circuit.png and /dev/null differ diff --git a/docs/images/noisy-sim-estimator-ideal.png b/docs/images/noisy-sim-estimator-ideal.png deleted file mode 100644 index e7bc8846a..000000000 Binary files a/docs/images/noisy-sim-estimator-ideal.png and /dev/null differ diff --git a/docs/images/noisy-sim-estimator-noisy.png b/docs/images/noisy-sim-estimator-noisy.png deleted file mode 100644 index 50c4df97f..000000000 Binary files a/docs/images/noisy-sim-estimator-noisy.png and /dev/null differ diff --git a/docs/images/noisy-sim-sampler-ideal.png b/docs/images/noisy-sim-sampler-ideal.png deleted file mode 100644 index e1ba79fbc..000000000 Binary files a/docs/images/noisy-sim-sampler-ideal.png and /dev/null differ diff --git a/docs/images/noisy-sim-sampler-noisy.png b/docs/images/noisy-sim-sampler-noisy.png deleted file mode 100644 index 8acc3151b..000000000 Binary files a/docs/images/noisy-sim-sampler-noisy.png and /dev/null differ diff --git a/docs/images/org-guide-audit-example.png b/docs/images/org-guide-audit-example.png deleted file mode 100644 index 7b4fd0d0f..000000000 Binary files a/docs/images/org-guide-audit-example.png and /dev/null differ diff --git a/docs/images/org-guide-create-access-group-1.png b/docs/images/org-guide-create-access-group-1.png deleted file mode 100644 index e44d2033b..000000000 Binary files a/docs/images/org-guide-create-access-group-1.png and /dev/null differ diff --git a/docs/images/org-guide-create-access-group-2.png b/docs/images/org-guide-create-access-group-2.png deleted file mode 100644 index d6b4fa7ea..000000000 Binary files a/docs/images/org-guide-create-access-group-2.png and /dev/null differ diff --git a/docs/images/org-guide-create-access-group-3.png b/docs/images/org-guide-create-access-group-3.png deleted file mode 100644 index 3aa56d46c..000000000 Binary files a/docs/images/org-guide-create-access-group-3.png and /dev/null differ diff --git a/docs/images/org-guide-create-appid.png b/docs/images/org-guide-create-appid.png deleted file mode 100644 index c36e0ebe6..000000000 Binary files a/docs/images/org-guide-create-appid.png and /dev/null differ diff --git a/docs/images/org-guide-create-custom-role.png b/docs/images/org-guide-create-custom-role.png deleted file mode 100644 index f0330abab..000000000 Binary files a/docs/images/org-guide-create-custom-role.png and /dev/null differ diff --git a/docs/images/org-guide-create-dynamic-rule1.png b/docs/images/org-guide-create-dynamic-rule1.png deleted file mode 100644 index 909ec479e..000000000 Binary files a/docs/images/org-guide-create-dynamic-rule1.png and /dev/null differ diff --git a/docs/images/org-guide-create-dynamic-rule2.png b/docs/images/org-guide-create-dynamic-rule2.png deleted file mode 100644 index 0d5abce29..000000000 Binary files a/docs/images/org-guide-create-dynamic-rule2.png and /dev/null differ diff --git a/docs/images/org-guide-custom-role-actions.png b/docs/images/org-guide-custom-role-actions.png deleted file mode 100644 index be3118b1d..000000000 Binary files a/docs/images/org-guide-custom-role-actions.png and /dev/null differ diff --git a/docs/images/org-guide-iam-settings.png b/docs/images/org-guide-iam-settings.png deleted file mode 100644 index f284b73da..000000000 Binary files a/docs/images/org-guide-iam-settings.png and /dev/null differ diff --git a/docs/images/org-guide-idp-reference.png b/docs/images/org-guide-idp-reference.png deleted file mode 100644 index ed7e4f8ed..000000000 Binary files a/docs/images/org-guide-idp-reference.png and /dev/null differ diff --git a/docs/images/org-guide-manage-user.png b/docs/images/org-guide-manage-user.png deleted file mode 100644 index 38f99e823..000000000 Binary files a/docs/images/org-guide-manage-user.png and /dev/null differ diff --git a/docs/images/resiliance-2.png b/docs/images/resiliance-2.png deleted file mode 100644 index 926a8a91f..000000000 Binary files a/docs/images/resiliance-2.png and /dev/null differ diff --git a/docs/images/runtime-architecture.png b/docs/images/runtime-architecture.png deleted file mode 100644 index 121840d34..000000000 Binary files a/docs/images/runtime-architecture.png and /dev/null differ diff --git a/docs/images/sampler.png b/docs/images/sampler.png deleted file mode 100644 index aa17084ff..000000000 Binary files a/docs/images/sampler.png and /dev/null differ diff --git a/docs/images/sampling-overhead.png b/docs/images/sampling-overhead.png deleted file mode 100644 index 8b893d029..000000000 Binary files a/docs/images/sampling-overhead.png and /dev/null differ diff --git a/docs/images/session-overview.png b/docs/images/session-overview.png deleted file mode 100644 index fbb6034fa..000000000 Binary files a/docs/images/session-overview.png and /dev/null differ diff --git a/docs/images/stratified.png b/docs/images/stratified.png deleted file mode 100644 index f61db7207..000000000 Binary files a/docs/images/stratified.png and /dev/null differ diff --git a/docs/images/table.png b/docs/images/table.png deleted file mode 100644 index 21b6e2bf4..000000000 Binary files a/docs/images/table.png and /dev/null differ diff --git a/docs/index.rst b/docs/index.rst index 9271be9e0..1511a3162 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,50 +1,16 @@ ######################################### -Qiskit Runtime 0.15.0 documentation +Qiskit Runtime |version| API Docs Preview ######################################### -Overview -============== - -Qiskit Runtime is a cloud-based quantum computing service developed by IBM. It offers computational *primitives* to perform foundational quantum computing tasks that use built-in error suppression and mitigation techniques. Primitives can be executed inside of *sessions*, allowing collections of circuits to be jointly run on a quantum computer without being interrupted by other users’ jobs. The combination of primitives, error suppression / mitigation, and sessions paves the way to efficiently build and execute scalable quantum applications. - -The following figure illustrates how one can use Qiskit Runtime sessions and primitives. The first session request (job) waits through the regular `fair-share queue `__. When it starts to run, the session is started. After the first session job is finished processing, the next job in the session is run. This process continues until the session is paused (due to a lack of queued session jobs) or closed. - -.. figure:: images/runtime-architecture.png - :align: center - -Key concepts -============== - -**Primitives** - -Primitives are base level operations that serve as building blocks for many quantum algorithms and applications. Through these primitives, users can obtain high-fidelity results, without needing detailed hardware knowledge. This abstraction allows you to write code, using Qiskit algorithms or otherwise, that can run on different quantum hardware or simulators without having to explicitly manage aspects such as compilation, optimization, and error suppression / mitigation. The primitives offered by :mod:`qiskit_ibm_runtime` add additional options specific to IBM services. See `Introduction to primitives `__ for further details. - -There are currently two primitives defined in Qiskit: Estimator and Sampler. - - -**Estimator** - -The estimator primitive allows you to efficiently calculate and interpret expectation values of quantum operators; the values of interest for many near-term quantum algorithms. You specify circuits that prepare quantum states and then Pauli-basis observables to measure on those states. The estimator can use advanced error suppression and mitigation capabilities to improve the accuracy of the returned expectation values. - -**Sampler** - -This primitive takes circuits as input and returns a quasi-probability distribution over the measurement outcomes. This generalizes histograms from quantum circuits, allowing for mitigation of readout errors. - -**Error suppression / mitigation** - -While building a fault-tolerant quantum computation is the ultimate goal, at present, calculations performed on near-term quantum computers are susceptible to noise. Qiskit Runtime offers several methods for preventing errors before they occur (error suppression techniques) and dealing with those that do occur (error mitigation techniques). - -**Session** - -A session allows a collection of jobs to be grouped and jointly scheduled by the Qiskit Runtime service, facilitating iterative use of quantum computers without incurring queuing delays on each iteration. This eliminates artificial delays caused by other users’ jobs running on the same quantum device during the session. See `Introduction to sessions `__ for further details. - +Qiskit Runtime docs live at docs.quantum.ibm.com and come from https://github.com/Qiskit/documentation. +This site is only used to generate our API docs, which then get migrated to +https://github.com/Qiskit/documentation. +The tutorials are also pulled into learning.quantum.ibm.com. Next steps ================================= -`Getting started `_ - `Tutorials `_ .. toctree:: @@ -53,10 +19,6 @@ Next steps :caption: Get started Overview - Getting started - backend.run vs. Qiskit Runtime - Introduction to primitives - Introduction to sessions .. toctree:: :maxdepth: 1 @@ -73,48 +35,6 @@ Next steps Submit user-transpiled circuits using primitives All tutorials -.. toctree:: - :maxdepth: 1 - :hidden: - :caption: How to - - Run a primitive in a session - Run on quantum backends - Retrieve job results - Configure primitive options - Configure error mitigation options - Configure error suppression - Manage your account - Run noisy simulations - -.. toctree:: - :maxdepth: 1 - :hidden: - :caption: Migrate - - Migrate to using Qiskit Runtime primitives - Migrate your setup from qiskit-ibmq-provider - Use Estimator to design an algorithm - Use Sampler to design an algorithm - Update parameter values while running - Algorithm tuning options (shots, transpilation, error mitigation) - Migrate backend.run() from qiskit_ibm_provider to qiskit_ibm_runtime - -.. toctree:: - :maxdepth: 1 - :hidden: - :caption: Work with Qiskit Runtime in IBM Cloud - - Getting started - Pricing plans - Plan for an organization - Configure for an organization - Manage users in an organization - Manage the cost - Set up Terraform - Architecture and workload isolation - Securing your data - Audit events .. toctree:: :maxdepth: 1 @@ -122,12 +42,7 @@ Next steps :caption: Reference API Reference - Swagger API for building applications that use Qiskit Runtime - API error codes - FAQs - Retired systems Release Notes - GitHub .. Hiding - Indices and tables :ref:`genindex` diff --git a/docs/migrate/backend_run_migration_guide.rst b/docs/migrate/backend_run_migration_guide.rst deleted file mode 100644 index d62eebc26..000000000 --- a/docs/migrate/backend_run_migration_guide.rst +++ /dev/null @@ -1,96 +0,0 @@ -Migration guide: Migrate ``backend.run()`` from ``qiskit_ibm_provider`` to ``qiskit_ibm_runtime`` -================================================================================================= - -The Qiskit Runtime interface includes two packages: -Qiskit IBM Provider (the ``qiskit_ibm_provider`` package) and -Qiskit IBM Runtime (the ``qiskit_ibm_runtime`` package). Until now, -primitives (``Sampler`` and ``Estimator``) -were run in Runtime. Custom circuits that were manually transpiled and used ``IBMBackend.run()`` -were run in Provider. - -In this release, we add support for running custom circuits using ``IBMBackend.run()`` in Runtime, -so users can run all programs through Runtime. - -This guide describes how to migrate code that implemented ``IBMBackend.run()`` -using Qiskit IBM Provider to use Qiskit IBM Runtime instead. - -**Example 1: Straightforward execution of IBMBackend.run()** - -.. code-block:: python - - from qiskit import * - from qiskit.compiler import transpile, assemble - circuit = QuantumCircuit(2, 2) - circuit.h(0) - circuit.cx(0, 1) - circuit.measure_all() - -In Provider, the code is: - -.. code-block:: python - - from qiskit_ibm_provider import IBMProvider - provider = IBMProvider() - backend = provider.get_backend("ibmq_qasm_simulator") - transpiled_circuit = transpile(circuit, backend=backend) - job = backend.run(transpiled_circuit) - print(job.result()) - -In Runtime, the code is: - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - service = QiskitRuntimeService(channel="ibm_quantum") - backend = service.backend("ibmq_qasm_simulator") - transpiled_circuit = transpile(circuit, backend=backend) - job = backend.run(transpiled_circuit) - print(job.result()) - -**Example 2: Execution of backend.run() within a session:** - -This section of code is identical in Provider and in Runtime. - -.. code-block:: python - - with backend.open_session() as session: - job1 = backend.run(transpiled_circuit) - job2 = backend.run(transpiled_circuit) - print(job1.session_id) - print(job2.session_id) - backend.cancel_session() - -Sessions are implemented differently in ``IBMBackend`` than when using primitives. -Therefore, we cannot run a primitive and use backend.run() within a single session. If you specify both, one will be run outside of the session. - -**Example 3: Primitive session containing backend.run:** - -In this example, ``sampler`` is run within session, but ``backend`` is run independently -of the session. - -.. code-block:: python - - from qiskit_ibm_runtime import Session, Sampler - with Session(backend=backend) as session: - sampler = Sampler(session=session) - job1 = sampler.run(transpiled_circuit) - job2 = backend.run(transpiled_circuit) # runs outside the session - print(job1.session_id) - print(job2.session_id) # is None - -**Example 4: Backend session containing Sampler:** - -In this example, ``backend`` is run within a session, but ``sampler`` is run independently -of the session. - -.. code-block:: python - - with backend.open_session() as session: - sampler = Sampler(backend=backend) - job1 = sampler.run(transpiled_circuit) # runs outside the session - job2 = backend.run(transpiled_circuit) - session_id = session.session_id - print(job1.session_id) # is None - print(job2.session_id) - - diff --git a/docs/migrate/migrate-estimator.rst b/docs/migrate/migrate-estimator.rst deleted file mode 100644 index 96c91cc2a..000000000 --- a/docs/migrate/migrate-estimator.rst +++ /dev/null @@ -1,351 +0,0 @@ -Calculate expectation values in an algorithm -============================================== - -The Estimator primitive is used to design an algorithm that calculates expectation values. - -Background ----------- - -.. - vale IBMQuantum.Spelling = NO - -.. |qiskit.opflow| replace:: ``qiskit.opflow`` -.. _qiskit.opflow: https://qiskit.org/documentation/apidoc/opflow.html - -.. |BaseEstimator| replace:: ``BaseEstimator`` -.. _BaseEstimator: https://qiskit.org/documentation/stubs/qiskit.primitives.BaseEstimator.html - -.. |BaseSampler| replace:: ``BaseSampler`` -.. _BaseSampler: https://qiskit.org/documentation/stubs/qiskit.primitives.BaseSampler.html - -.. |qiskit_aer.primitives| replace:: ``qiskit_aer.primitives`` -.. _qiskit_aer.primitives: https://github.com/Qiskit/qiskit-aer/tree/main/qiskit_aer/primitives - -.. |qiskit.primitives| replace:: ``qiskit.primitives`` -.. _qiskit.primitives: https://qiskit.org/documentation/apidoc/primitives.html - - - -The role of the ``Estimator`` primitive is two-fold: it acts as an **entry point** to quantum devices or -simulators, replacing the ``Backend`` interface (commonly referred to as ``backend.run()``). Additionally, it is an -**algorithmic abstraction** for expectation -value calculations, so you don't have to manually construct the final expectation circuit. -This results in a considerable reduction of the code complexity and a more compact algorithm design. - -.. note:: - - **Backend.run() model:** In this model, you accessed real backends and remote simulators using the - ``qiskit-ibmq-provider`` module (now migrated to ``qiskit-ibm-provider``). To run - **local** simulations, you could import a specific backend from ``qiskit-aer``. All of them followed - the ``backend.run()`` interface. - - .. raw:: html - -
- Code example for qiskit-ibmq-provider & backend.run() -
- - .. code-block:: python - - from qiskit import IBMQ - - # Select provider - provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main") - - # Get backend - backend = provider.get_backend("ibmq_qasm_simulator") # cloud simulator - - # Run - result = backend.run(expectation_circuits) - - .. raw:: html - -
-
- - .. raw:: html - -
- Code example for qiskit-aer & backend.run() -
- - .. code-block:: python - - from qiskit_aer import AerSimulator # former import: from qiskit import Aer - - # Get local simulator backend - backend = AerSimulator() - - # Run - result = backend.run(expectation_circuits) - - .. raw:: html - -
-
- - **Primitives model:** Access real backends and remote simulators through the ``qiskit-ibm-runtime`` - **primitives** (``Sampler`` and ``Estimator``). To run **local** simulations, you can import specific `local` primitives - from |qiskit_aer.primitives|_ and |qiskit.primitives|_. All of them follow the |BaseSampler|_ and |BaseEstimator|_ interfaces, but - **only the Runtime primitives offer access to the Runtime service, sessions, and built-in error mitigation**. - - .. raw:: html - -
- Code example for Runtime Estimator -
- - .. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Estimator - - # Define service - service = QiskitRuntimeService() - - # Get backend - backend = service.backend("ibmq_qasm_simulator") # cloud simulator - - # Define Estimator - estimator = Estimator(backend=backend) - - # Run Expectation value calculation - result = estimator.run(circuits, observables).result() - - .. raw:: html - -
-
- - .. raw:: html - -
- Code example for Aer Estimator -
- - .. code-block:: python - - from qiskit_aer import Estimator - - # Get local simulator Estimator - estimator = Estimator() - - # Run expectation value calculation - result = estimator.run(circuits, observables).result() - - .. raw:: html - -
-
- -If your code previously calculated expectation values using ``backend.run()``, you most likely used the |qiskit.opflow|_ -module to handle operators and state functions. To support this scenario, the following migration example shows how to replace -the (|qiskit.opflow|_ & ``backend.run()``) workflow with an ``Estimator``-based workflow. - -End-to-end example ------------------- - -1. Problem definition ----------------------- - -We want to compute the expectation value of a quantum state (circuit) with respect to a certain operator. -In this example, we are using the H2 molecule and an arbitrary circuit as the quantum state: - -.. code-block:: python - - from qiskit import QuantumCircuit - from qiskit.quantum_info import SparsePauliOp - - # Step 1: Define operator - op = SparsePauliOp.from_list( - [ - ("II", -1.052373245772859), - ("IZ", 0.39793742484318045), - ("ZI", -0.39793742484318045), - ("ZZ", -0.01128010425623538), - ("XX", 0.18093119978423156), - ] - ) - - # Step 2: Define quantum state - state = QuantumCircuit(2) - state.x(0) - state.x(1) - -.. _a-legacy-opflow: - -1.a. [Legacy] Convert problem to ``opflow`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -|qiskit.opflow|_ provided its own classes to represent both -operators and quantum states, so the problem defined previously would be wrapped as: - -.. code-block:: python - - from qiskit.opflow import CircuitStateFn, PauliSumOp - - opflow_op = PauliSumOp(op) - opflow_state = CircuitStateFn(state) - -This step is no longer necessary when using the primitives. - -.. note:: - - For instructions to migrate from |qiskit.opflow|_, see the `opflow migration guide `_ . - -2. Calculate expectation values on real device or cloud simulator -------------------------------------------------------------------- - - -2.a. [Legacy] Use ``opflow`` & ``backend.run()`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The legacy workflow required many steps to compute an expectation -value: - -.. note:: - - Replace ``ibmq_qasm_simulator`` with your device name to see the - complete workflow for a real device. - -.. code-block:: python - - from qiskit.opflow import StateFn, PauliExpectation, CircuitSampler - from qiskit import IBMQ - - # Define the state to sample - measurable_expression = StateFn(opflow_op, is_measurement=True).compose(opflow_state) - - # Convert to expectation value calculation object - expectation = PauliExpectation().convert(measurable_expression) - - # Define provider and backend - provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main") - backend = provider.get_backend("ibmq_qasm_simulator") - - # Inject backend into circuit sampler - sampler = CircuitSampler(backend).convert(expectation) - - # Evaluate - expectation_value = sampler.eval().real - -.. code-block:: python - - >>> print("expectation: ", expectation_value) - expectation: -1.065734058826613 - -2.b. [New] Use the ``Estimator`` Runtime primitive -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``Estimator`` simplifies the user-side syntax, making it a more -convenient tool for algorithm design. - -.. note:: - - Replace ``ibmq_qasm_simulator`` with your device name to see the - complete workflow for a real device. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Estimator - - service = QiskitRuntimeService(channel="ibm_quantum") - backend = service.backend("ibmq_qasm_simulator") - - estimator = Estimator(backend=backend) - - expectation_value = estimator.run(state, op).result().values - -Note that the Estimator returns a list of values, as it can perform batched evaluations. - -.. code-block:: python - - >>> print("expectation: ", expectation_value) - expectation: [-1.06329149] - -The ``Estimator`` Runtime primitive offers a series of features and tuning options that do not have a legacy alternative -to migrate from, but can help improve your performance and results. For more information, refer to the following: - -- `Error mitigation tutorial `_ -- `Setting execution options topic `_ -- `Primitive execution options API reference `_ -- `How to run a session topic `_ - - -3. Other execution alternatives (non-Runtime) ----------------------------------------------- - -This section describes how to use non-Runtime primitives to test an algorithm using local simulation. Let's assume that we want to solve the problem defined previously with a local state vector simulation. - -3.a. [Legacy] Using the Qiskit Aer simulator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: python - - from qiskit.opflow import StateFn, PauliExpectation, CircuitSampler - from qiskit_aer import AerSimulator - - # Define the state to sample - measurable_expression = StateFn(opflow_op, is_measurement=True).compose(opflow_state) - - # Convert to expectation value calculation object - expectation = PauliExpectation().convert(measurable_expression) - - # Define statevector simulator - simulator = AerSimulator(method="statevector", shots=100) - - # Inject backend into circuit sampler - circuit_sampler = CircuitSampler(simulator).convert(expectation) - - # Evaluate - expectation_value = circuit_sampler.eval().real - -.. code-block:: python - - >>> print("expectation: ", expectation_value) - expectation: -1.0636533500290943 - - -3.b. [New] Use the Reference ``Estimator`` or Aer ``Estimator`` primitive -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Reference ``Estimator`` lets you perform either an exact or a shot-based noisy simulation based -on the ``Statevector`` class in the ``qiskit.quantum_info`` module. - -.. code-block:: python - - from qiskit.primitives import Estimator - - estimator = Estimator() - - expectation_value = estimator.run(state, op).result().values - - # for shot-based simulation: - expectation_value = estimator.run(state, op, shots=100).result().values - -.. code-block:: python - - >>> print("expectation: ", expectation_value) - expectation: [-1.03134297] - -You can still access the Aer Simulator through its dedicated -``Estimator``. This can be handy for performing simulations with noise models. In this example, -the simulation method has been updated to match the result from 3.a. - -.. code-block:: python - - from qiskit_aer.primitives import Estimator # import change!!! - - estimator = Estimator(run_options= {"method": "statevector"}) - - expectation_value = estimator.run(state, op, shots=100).result().values - -.. code-block:: python - - >>> print("expectation: ", expectation_value) - expectation: [-1.06365335] - -For more information about using the Aer primitives, see the -`VQE tutorial `_ . - -For more information about running noisy simulations with the **Runtime primitives**, see this -`topic `_. diff --git a/docs/migrate/migrate-guide.rst b/docs/migrate/migrate-guide.rst deleted file mode 100644 index 7cd1610fb..000000000 --- a/docs/migrate/migrate-guide.rst +++ /dev/null @@ -1,205 +0,0 @@ -.. _migrate to primitives: - -Migrate to using Qiskit Runtime primitives -============================================ - -This guide describes key patterns of behavior and use cases with code examples to help you migrate code from -the legacy ``qiskit-ibmq-provider`` package to use the Qiskit Runtime primitives. - -Primitives are the recommended tool to write quantum algorithms, as they encapsulate common device queries -seen in application packages and allow for managed performance through the Qiskit Runtime service. -However, if your algorithm requires more granular information, such as pre-shot measurements, the primitives might -not provide the desired abstraction level. - -The Qiskit Runtime primitives implement the reference ``Sampler`` and ``Estimator`` interfaces found in -`qiskit.primitives `_. These interfaces let you -switch between primitive implementations with minimal code changes. Different primitive implementations -can be found in the ``qiskit``, ``qiskit_aer``, and ``qiskit_ibm_runtime`` libraries. -Each implementation serves a specific purpose: - -* The primitives in ``qiskit`` can perform local state vector simulations - useful for quickly prototyping algorithms. -* The primitives in ``qiskit_aer`` give access to the local Aer simulators for tasks such as noisy simulation. -* The primitives in ``qiskit_ibm_runtime`` provide access to cloud simulators and real hardware through the Qiskit - Runtime service. They include exclusive features such as built-in circuit optimization and error mitigation support. - -.. attention:: - - The **only primitives that provide access to the Qiskit Runtime service** are those imported - from ``qiskit_ibm_runtime`` (Qiskit Runtime Primitives). - -When migrating, the key to writing an equivalent algorithm using primitives is to first identify what is the minimal -unit of information your algorithm is based on: - -* If it uses an **expectation value**, you will need an ``Estimator``. -* If it uses a **probability distribution** (from sampling the device), you will need a ``Sampler``. - -After determining which primitive to use, identify where the algorithm accesses the backend. Look for the call to -``backend.run()``. -Next, you will replace this call with the respective primitive call, as shown in the following examples. - -.. - Add this in later when it's done and we have the link - For instructions to migrate code based on ``QuantumInstance``, refer to the `Quantum Instance migration guide `__. - -Algorithm developers who need to refactor algorithms to use primitives instead of `backend.run` should refer to these topics: - -* `Update code that performs circuit sampling `__ -* `Update code that calculates expectation values `__ - -The following topics are use cases with code migration examples: - - -* `Update parameter values while running `__ -* `Algorithm tuning options (shots, transpilation, error mitigation) `__ - -.. _why-migrate: - -Why use Qiskit Runtime? --------------------------------------------- - -.. list-table:: - :header-rows: 1 - - * - Function - - Backend.run - - Runtime Primitives - - * - Simplified algorithm building blocks - - :octicon:`x` - - :octicon:`check` - - * - Flexible interface - - :octicon:`check` - - :octicon:`check` - - * - Elastic compute integration - - :octicon:`check` - - :octicon:`check` - - * - Queuing efficiency - - :octicon:`x` - - :octicon:`check` - - * - Data caching - - :octicon:`x` - - :octicon:`clock` - - * - Error mitigation support - - :octicon:`x` - - :octicon:`check` - - * - SAAS enablement - - :octicon:`x` - - :octicon:`clock` - -Key: - -- :octicon:`x` Not supported -- :octicon:`check` Full support -- :octicon:`clock` Future support - - -**Benefits of using Qiskit Runtime**: - -* Simplify algorithm design and optimization. -* Run circuits faster by using sessions - a context manager designed to efficiently manage iterative workloads and minimize artificial latency between quantum and classical sub-components. -* Access our most powerful quantum systems with our latest performance and hardware optimization, including capabilities like error suppression and mitigation. -* Easily integrate Qiskit Runtime with your cloud or on-premise classical compute resources by using the quantum serverless toolkit. - -**Simplified interface**: - -Use primitives to write code more efficiently. For details, see the examples topics, such as `Using Estimator to design an algorithm `__. - - .. figure:: ../images/compare-code.png - :alt: Two code snippets, side by side - - Code without primitives, and the same code after being rewritten to use primitives. - - -.. _migfaqs: - -FAQs --------------------------------------------- - -Users might have the following questions when planning to migrate their -code to Qiskit Runtime: - -.. raw:: html - -
- Which channel should I use? - -After deciding to use Qiskit Runtime primitives, the user must determine whether to access Qiskit Runtime -through IBM Cloud or IBM Quantum Platform. Some information that might help you decide includes: - -* The available plans: - - * Qiskit Runtime is available in both the Open (free access) or Premium (contract-based paid access) plan on IBM Quantum Platform. See `IBM Quantum access plans `__ for details. - * Qiskit Runtime is accessible through the Lite (free access) or Standard (pay-as-you-go access) plan in IBM Cloud. See `Plans <../cloud/plans.html>`__ for details. - -* The use case requirements: - - * IBM Quantum Platform offers a visual circuit composer (Quantum Composer) and a Jupyter Notebook environment (Quantum Lab). - * IBM Cloud offers a cloud native service that is ideal if users need to integrate quantum capabilities with other cloud services. - -.. raw:: html - -
- -.. raw:: html - -
- How do I set up my channel? - -After deciding which channel to use to interact with Qiskit Runtime, you -can get set up on either platform using the instructions below: - -* To get started with Qiskit Runtime on IBM Quantum Platform, see `Experiment with Qiskit Runtime `__. -* To get started with Qiskit Runtime on IBM Cloud, see the `Getting Started guide <../cloud/get-started.html>`__. - -.. raw:: html - -
- -.. raw:: html - -
- Should I modify the Qiskit Terra algorithms? - -As of v0.22, `Qiskit Terra algorithms `__ use Qiskit Runtime primitives. Thus, there is no need for -users to modify amplitude estimators or any other Qiskit Terra algorithms. - -.. raw:: html - -
- -.. raw:: html - -
- Which primitive should I use? - -When choosing which primitive to use, you first need to understand -whether the algorithm uses a **quasi-probability distribution** sampled from a quantum state (a list of -quasi-probabilities), or an **expectation value** of a certain observable -with respect to a quantum state (a real number). - -A probability distribution is often of interest in optimization problems -that return a classical bit string, encoding a certain solution to a -problem at hand. In these cases, you might be interested in finding a bit -string that corresponds to a ket value with the largest probability of -being measured from a quantum state, for example. - -An expectation value of an observable could be the target quantity in -scenarios where knowing a quantum state is not relevant. This -often occurs in optimization problems or chemistry applications. For example, when trying to discover the extremal energy of a system. - -.. raw:: html - -
- -Related links -------------- - -* `Get started with Estimator <../tutorials/how-to-getting-started-with-estimator.ipynb>`__ -* `Get started with Sampler <../tutorials/how-to-getting-started-with-sampler.ipynb>`__ -* `Tutorial: Migrate from qiskit-ibmq-provider to qiskit-ibm-provider `__ diff --git a/docs/migrate/migrate-sampler.rst b/docs/migrate/migrate-sampler.rst deleted file mode 100644 index f1d3e8705..000000000 --- a/docs/migrate/migrate-sampler.rst +++ /dev/null @@ -1,427 +0,0 @@ -Circuit sampling in an algorithm -================================= - -The Sampler primitive is used to design an algorithm that samples circuits and extracts probability distributions. - -Background ----------- - -.. |qiskit.opflow| replace:: ``qiskit.opflow`` -.. _qiskit.opflow: https://qiskit.org/documentation/apidoc/opflow.html - -.. |BaseEstimator| replace:: ``BaseEstimator`` -.. _BaseEstimator: https://qiskit.org/documentation/stubs/qiskit.primitives.BaseEstimator.html - -.. |BaseSampler| replace:: ``BaseSampler`` -.. _BaseSampler: https://qiskit.org/documentation/stubs/qiskit.primitives.BaseSampler.html - -.. |qiskit_aer.primitives| replace:: ``qiskit_aer.primitives`` -.. _qiskit_aer.primitives: https://github.com/Qiskit/qiskit-aer/tree/main/qiskit_aer/primitives - -.. |qiskit.primitives| replace:: ``qiskit.primitives`` -.. _qiskit.primitives: https://qiskit.org/documentation/apidoc/primitives.html - -.. |QuasiDistribution.binary_probabilities| replace:: ``QuasiDistribution.binary_probabilities()`` -.. _QuasiDistribution.binary_probabilities: https://qiskit.org/documentation/stubs/qiskit.result.QuasiDistribution.binary_probabilities.html#qiskit.result.QuasiDistribution.binary_probabilities - - -The role of the ``Sampler`` primitive is two-fold: it acts as an **entry point** to quantum devices or -simulators, replacing ``backend.run()``. Additionally, it is an **algorithmic abstraction** to extract probability distributions from measurement counts. - -Both ``Sampler`` and ``backend.run()`` take in circuits as inputs. The main difference is the format of the -output: ``backend.run()`` outputs **counts**, while ``Sampler`` processes those counts and outputs -the **quasi-probability distribution** associated with them. - - -.. note:: - - **Backend.run() model:** In this model, you used the - ``qiskit-ibmq-provider`` (now migrated to ``qiskit-ibm-provider``) module to access real backends and remote simulators. - To run **local** simulations, you could import a specific backend from ``qiskit-aer``. All of them followed - the ``backend.run()`` interface. - - .. raw:: html - -
- Code example with qiskit-ibmq-provider & backend.run() -
- - .. code-block:: python - - from qiskit import IBMQ - - # Select provider - provider = IBMQ.load_account() - - # Get backend - backend = provider.get_backend("ibmq_qasm_simulator") # Use the cloud simulator - - # Run - result = backend.run(circuits) - - .. raw:: html - -
-
- - .. raw:: html - -
- Code example for qiskit-aer & backend.run() -
- - .. code-block:: python - - from qiskit_aer import AerSimulator # former import: from qiskit import Aer - - # Get local simulator backend - backend = AerSimulator() - - # Run - result = backend.run(circuits) - - .. raw:: html - -
-
- - **Primitives model:** Access real backends and remote simulators through the `qiskit-ibm-runtime` - **primitives** (`Sampler` and `Estimator`). To run **local** simulations, import specific `local` primitives - from |qiskit_aer.primitives|_ and |qiskit.primitives|_. All of them follow the |BaseSampler|_ and |BaseEstimator|_ interfaces, but - **only the Runtime primitives offer access to the Runtime service, sessions, and built-in error mitigation**. - - .. raw:: html - -
- Code example for Runtime Sampler -
- - .. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Sampler - - # Define service - service = QiskitRuntimeService() - - # Get backend - backend = service.backend("ibmq_qasm_simulator") # Use a cloud simulator - - # Define Sampler - sampler = Sampler(backend=backend) - - # Run Quasi-Probability calculation - result = sampler.run(circuits).result() - - .. raw:: html - -
-
- - .. raw:: html - -
- Code example for Aer Sampler -
- - .. code-block:: python - - from qiskit_aer import Sampler - - # Get local simulator Sampler - sampler = Sampler() - - # Run Quasi-Probability calculation - result = sampler.run(circuits).result() - - .. raw:: html - -
-
- -Next, we will show an end-to-end example of sampling a circuit: first, with ``backend.run()``, then by using the ``Sampler``. - -End-to-end example ------------------- - - -1. Problem definition ----------------------- - -We want to find the probability (or quasi-probability) distribution associated with a quantum state: - -.. attention:: - - Important: If you want to use the ``Sampler`` primitive, the circuit **must contain measurements**. - -.. code-block:: python - - from qiskit import QuantumCircuit - - circuit = QuantumCircuit(4) - circuit.h(range(2)) - circuit.cx(0,1) - circuit.measure_all() # measurement! - -2. Calculate probability distribution on a real device or cloud simulator -------------------------------------------------------------------------- - - -2.a. [Legacy] Use ``backend.run()`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The required steps to reach our goal with ``backend.run()`` are: - -1. Run circuits -2. Get counts from the result object -3. Use the counts and shots to calculate the probability distribution - - -.. raw:: html - -
- -First, we run the circuit in a cloud simulator and output the result object: - -.. note:: - - Replace ``ibmq_qasm_simulator`` with your device name to see the - complete workflow for a real device. - -.. code-block:: python - - from qiskit import IBMQ - - # Define provider and backend - provider = IBMQ.load_account() - backend = provider.get_backend("ibmq_qasm_simulator") - - # Run - result = backend.run(circuit, shots=1024).result() - -.. code-block:: python - - >>> print("result: ", result) - result: Result(backend_name='ibmq_qasm_simulator', backend_version='0.11.0', - qobj_id='65bb8a73-cced-40c1-995a-8961cc2badc4', job_id='63fc95612751d57b6639f777', - success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, - data=ExperimentResultData(counts={'0x0': 255, '0x1': 258, '0x2': 243, '0x3': 268}), - header=QobjExperimentHeader(clbit_labels=[['meas', 0], ['meas', 1], ['meas', 2], ['meas', 3]], - creg_sizes=[['meas', 4]], global_phase=0.0, memory_slots=4, metadata={}, n_qubits=4, - name='circuit-930', qreg_sizes=[['q', 4]], qubit_labels=[['q', 0], ['q', 1], ['q', 2], ['q', 3]]), - status=DONE, metadata={'active_input_qubits': [0, 1, 2, 3], 'batched_shots_optimization': False, - 'device': 'CPU', 'fusion': {'enabled': False}, 'input_qubit_map': [[3, 3], [2, 2], [1, 1], [0, 0]], - 'measure_sampling': True, 'method': 'stabilizer', 'noise': 'ideal', 'num_clbits': 4, 'num_qubits': 4, - 'parallel_shots': 1, 'parallel_state_update': 16, 'remapped_qubits': False, - 'sample_measure_time': 0.001001096}, seed_simulator=2191402198, time_taken=0.002996865)], - date=2023-02-27 12:35:00.203255+01:00, status=COMPLETED, header=QobjHeader(backend_name='ibmq_qasm_simulator', - backend_version='0.1.547'), metadata={'max_gpu_memory_mb': 0, 'max_memory_mb': 386782, 'mpi_rank': 0, - 'num_mpi_processes': 1, 'num_processes_per_experiments': 1, 'omp_enabled': True, 'parallel_experiments': 1, - 'time_taken': 0.003215252, 'time_taken_execute': 0.00303248, 'time_taken_load_qobj': 0.000169435}, - time_taken=0.003215252, client_version={'qiskit': '0.39.5'}) - -Now we get the probability distribution from the output: - -.. code-block:: python - - counts = result.get_counts(circuit) - quasi_dists = {} - for key,count in counts.items(): - quasi_dists[key] = count/1024 - -.. code-block:: python - - >>> print("counts: ", counts) - >>> print("quasi_dists: ", quasi_dists) - counts: {'0000': 255, '0001': 258, '0010': 243, '0011': 268} - quasi_dists: {'0000': 0.2490234375, '0001': 0.251953125, '0010': 0.2373046875, '0011': 0.26171875} - - -2.b. [New] Use the ``Sampler`` Runtime primitive -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -While the user-side syntax of the ``Sampler`` is very similar to ``backend.run()``, -notice that the workflow is now simplified, as the quasi-probability distribution is returned -**directly** (no need to perform post-processing), together with some key metadata. - -.. note:: - - Replace ``ibmq_qasm_simulator`` with your device name to see the - complete workflow for a real device. - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService, Sampler - - service = QiskitRuntimeService(channel="ibm_quantum") - backend = service.backend("ibmq_qasm_simulator") - - sampler = Sampler(backend=backend) - - result = sampler.run(circuit, shots=1024).result() - quasi_dists = result.quasi_dists - -.. code-block:: python - - >>> print("result: ", result) - >>> print("quasi_dists: ", quasi_dists) - result: SamplerResult(quasi_dists=[{0: 0.2802734375, 1: 0.2509765625, 2: 0.232421875, 3: 0.236328125}], - metadata=[{'header_metadata': {}, 'shots': 1024, 'readout_mitigation_overhead': 1.0, - 'readout_mitigation_time': 0.03801989182829857}]) - quasi_dists: [{0: 0.2802734375, 1: 0.2509765625, 2: 0.232421875, 3: 0.236328125}] - -.. attention:: - - Be careful with the output format. With ``Sampler``, the states are no longer represented - by bit strings, for example, ``"11"``, - but by integers, for example, ``3``. To convert the ``Sampler`` output to bit strings, - you can use the |QuasiDistribution.binary_probabilities|_ method, as shown below. - -.. code-block:: python - - >>> # convert the output to bit strings - >>> binary_quasi_dist = quasi_dists[0].binary_probabilities() - >>> print("binary_quasi_dist: ", binary_quasi_dist) - binary_quasi_dist: {'0000': 0.2802734375, '0001': 0.2509765625, '0010': 0.232421875, '0011': 0.236328125} - -The ``Sampler`` Runtime primitive offers several features and tuning options that do not have a legacy alternative -to migrate from, but can help improve your performance and results. For more information, refer to the following: - -- `Error mitigation tutorial `_ -- `Setting execution options topic `_ -- `How to run a session topic `_ - - -3. Other execution alternatives (non-Runtime) ---------------------------------------------- - -The following migration paths use non-Runtime primitives to use local simulation to test an algorithm. Let's assume that we want to use a local state vector simulation to solve the problem defined above. - -3.a. [Legacy] Use the Qiskit Aer simulator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -.. code-block:: python - - from qiskit_aer import AerSimulator - - # Define the statevector simulator - simulator = AerSimulator(method="statevector") - - # Run and get counts - result = simulator.run(circuit, shots=1024).result() - -.. code-block:: python - - >>> print("result: ", result) - result: Result(backend_name='aer_simulator_statevector', backend_version='0.11.2', - qobj_id='e51e51bc-96d8-4e10-aa4e-15ee6264f4a0', job_id='c603daa7-2c03-488c-8c75-8c6ea0381bbc', - success=True, results=[ExperimentResult(shots=1024, success=True, meas_level=2, - data=ExperimentResultData(counts={'0x2': 236, '0x0': 276, '0x3': 262, '0x1': 250}), - header=QobjExperimentHeader(clbit_labels=[['meas', 0], ['meas', 1], ['meas', 2], ['meas', 3]], - creg_sizes=[['meas', 4]], global_phase=0.0, memory_slots=4, metadata={}, n_qubits=4, name='circuit-930', - qreg_sizes=[['q', 4]], qubit_labels=[['q', 0], ['q', 1], ['q', 2], ['q', 3]]), status=DONE, - seed_simulator=3531074553, metadata={'parallel_state_update': 16, 'parallel_shots': 1, - 'sample_measure_time': 0.000405246, 'noise': 'ideal', 'batched_shots_optimization': False, - 'remapped_qubits': False, 'device': 'CPU', 'active_input_qubits': [0, 1, 2, 3], 'measure_sampling': True, - 'num_clbits': 4, 'input_qubit_map': [[3, 3], [2, 2], [1, 1], [0, 0]], 'num_qubits': 4, 'method': 'statevector', - 'fusion': {'applied': False, 'max_fused_qubits': 5, 'threshold': 14, 'enabled': True}}, time_taken=0.001981756)], - date=2023-02-27T12:38:18.580995, status=COMPLETED, header=QobjHeader(backend_name='aer_simulator_statevector', - backend_version='0.11.2'), metadata={'mpi_rank': 0, 'num_mpi_processes': 1, 'num_processes_per_experiments': 1, - 'time_taken': 0.002216379, 'max_gpu_memory_mb': 0, 'time_taken_execute': 0.002005713, 'max_memory_mb': 65536, - 'time_taken_load_qobj': 0.000200642, 'parallel_experiments': 1, 'omp_enabled': True}, - time_taken=0.0025920867919921875) - -Now let's get the probability distribution from the output: - -.. code-block:: python - - counts = result.get_counts(circuit) - quasi_dists = {} - for key,count in counts.items(): - quasi_dists[key] = count/1024 - -.. code-block:: python - - >>> print("counts: ", counts) - >>> print("quasi_dists: ", quasi_dists) - counts: {'0010': 236, '0000': 276, '0011': 262, '0001': 250} - quasi_dists: {'0010': 0.23046875, '0000': 0.26953125, '0011': 0.255859375, '0001': 0.244140625} - -3.b. [New] Use the Reference ``Sampler`` or Aer ``Sampler`` primitive -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The Reference ``Sampler`` lets you perform an exact or a shot-based noisy simulation based -on the ``Statevector`` class in the ``qiskit.quantum_info`` module. - -.. code-block:: python - - from qiskit.primitives import Sampler - - sampler = Sampler() - - result = sampler.run(circuit).result() - quasi_dists = result.quasi_dists - -.. code-block:: python - - >>> print("result: ", result) - >>> print("quasi_dists: ", quasi_dists) - result: SamplerResult(quasi_dists=[{0: 0.249999999999, 1: 0.249999999999, - 2: 0.249999999999, 3: 0.249999999999}], metadata=[{}]) - quasi_dists: [{0: 0.249999999999, 1: 0.249999999999, 2: 0.249999999999, - 3: 0.249999999999}] - -If shots are specified, this primitive outputs a shot-based simulation (no longer exact): - -.. code-block:: python - - from qiskit.primitives import Sampler - - sampler = Sampler() - - result = sampler.run(circuit, shots=1024).result() - quasi_dists = result.quasi_dists - -.. code-block:: python - - >>> print("result: ", result) - >>> print("quasi_dists: ", quasi_dists) - result: SamplerResult(quasi_dists=[{0: 0.2490234375, 1: 0.2578125, - 2: 0.2431640625, 3: 0.25}], metadata=[{'shots': 1024}]) - quasi_dists: [{0: 0.2490234375, 1: 0.2578125, 2: 0.2431640625, 3: 0.25}] - -You can still access the Aer simulator through its dedicated -``Sampler``. This can be handy for performing simulations with noise models. In this example, -the simulation method has been updated to match the result from 3.a. - -.. code-block:: python - - from qiskit_aer.primitives import Sampler as AerSampler # import change! - - sampler = AerSampler(run_options= {"method": "statevector"}) - - result = sampler.run(circuit, shots=1024).result() - quasi_dists = result.quasi_dists - -.. code-block:: python - - >>> print("result: ", result) - >>> print("quasi_dists: ", quasi_dists) - result: SamplerResult(quasi_dists=[{1: 0.2802734375, 2: 0.2412109375, 0: 0.2392578125, - 3: 0.2392578125}], metadata=[{'shots': 1024, 'simulator_metadata': - {'parallel_state_update': 16, 'parallel_shots': 1, 'sample_measure_time': 0.000409608, - 'noise': 'ideal', 'batched_shots_optimization': False, 'remapped_qubits': False, - 'device': 'CPU', 'active_input_qubits': [0, 1, 2, 3], 'measure_sampling': True, - 'num_clbits': 4, 'input_qubit_map': [[3, 3], [2, 2], [1, 1], [0, 0]], 'num_qubits': 4, - 'method': 'statevector', 'fusion': {'applied': False, 'max_fused_qubits': 5, - 'threshold': 14, 'enabled': True}}}]) - quasi_dists: [{1: 0.2802734375, 2: 0.2412109375, 0: 0.2392578125, 3: 0.2392578125}] - -.. code-block:: python - - >>> # Convert the output to bit strings - >>> binary_quasi_dist = quasi_dists[0].binary_probabilities() - >>> print("binary_quasi_dist: ", binary_quasi_dist) - binary_quasi_dist: {'0001': 0.2802734375, '0010': 0.2412109375, '0000': 0.2392578125, '0011': 0.2392578125} - -For information, see `Noisy simulators in Qiskit Runtime `_. diff --git a/docs/migrate/migrate-setup.rst b/docs/migrate/migrate-setup.rst deleted file mode 100644 index 53fbe39a5..000000000 --- a/docs/migrate/migrate-setup.rst +++ /dev/null @@ -1,170 +0,0 @@ -Migrate setup from ``qiskit-ibmq-provider`` -============================================== - -This guide describes how to migrate code from the legacy IBMQ provider (`qiskit-ibmq-provider`) package to use Qiskit Runtime (`qiskit-ibm-runtime`). This guide includes instructions to migrate legacy runtime programs to the new syntax. However, the ability to use custom uploaded programs is pending deprecation, so these should be migrated to use primitives instead. - -Changes in Class name and location ------------------------------------ - -The classes related to Qiskit Runtime that used to be included in ``qiskit-ibmq-provider`` are now part of ``qiskit-ibm-runtime``. Before, the provider used to populate the ``qiskit.providers.ibmq.runtime`` namespace with objects for Qiskit Runtime. These now live in the ``qiskit_ibm_runtime`` module. - -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``: - -.. - I had to take the :class: formatting out of the following table because it was too wide for the page and was writing on top of the right-hand navigation menu when everything was in tags. When I took off one tag, sphinx put it in a scrollable table that didn't overrun the right-hand navigation, so I took them all out for consistency - - -.. list-table:: Migrate from ``qiskit.providers.ibmq.runtime`` in ``qiskit-ibmq-provider`` to ``qiskit-ibm-runtime`` - :header-rows: 1 - - * - class in ``qiskit-ibmq-provider`` - - class in ``qiskit-ibm-runtime`` - - Notes - * - ``qiskit.providers.ibmq.runtime.IBMRuntimeService`` - - ``qiskit_ibm_runtime.QiskitRuntimeService``` - - ``IBMRuntimeService`` class was removed from ``qiskit-ibm-runtime`` 0.6 and replaced by the new class in ``qiskit-ibm-runtime``. - * - ``qiskit.providers.ibmq.runtime.RuntimeJob`` - - ``qiskit_ibm_runtime.RuntimeJob`` - - - * - ``qiskit.providers.ibmq.runtime.RuntimeProgram`` - - ``qiskit_ibm_runtime.RuntimeProgram`` - - - * - ``qiskit.providers.ibmq.runtime.UserMessenger`` - - ``qiskit_ibm_runtime.program.UserMessenger`` - - Notice the new location, in ``qiskit_ibm_runtime.program`` - * - ``qiskit.providers.ibmq.runtime.ProgramBackend`` - - ``qiskit_ibm_runtime.program.ProgramBackend`` - - Notice the new location, in ``qiskit_ibm_runtime.program`` - * - ``qiskit.providers.ibmq.runtime.ResultDecoder`` - - ``qiskit_ibm_runtime.program.ResultDecoder`` - - Notice the new location, in ``qiskit_ibm_runtime.program`` - * - ``qiskit.providers.ibmq.runtime.RuntimeEncoder`` - - ``qiskit_ibm_runtime.RuntimeEncoder`` - - - * - ``qiskit.providers.ibmq.runtime.RuntimeDecoder`` - - ``qiskit_ibm_runtime.RuntimeDecoder`` - - - * - ``qiskit.providers.ibmq.runtime.ParameterNamespace`` - - ``qiskit_ibm_runtime.ParameterNamespace`` - - - * - ``qiskit.providers.ibmq.runtime.RuntimeOptions`` - - ``qiskit_ibm_runtime.RuntimeOptions`` - - - -Import path -------------- - -The import path has changed as follows: - -**Legacy** - -.. code-block:: python - - from qiskit import IBMQ - -**Updated** - -.. code-block:: python - - from qiskit_ibm_runtime import QiskitRuntimeService - -Save and load accounts ------------------------------------- - -Use the updated code to work with accounts. - -**Legacy - Save accounts** - -.. code-block:: python - - IBMQ.save_account("", overwrite=True) - -**Updated - Save accounts** -The new syntax accepts credentials for Qiskit Runtime on IBM Cloud or IBM Quantum Platform. For more information about retrieving account credentials, see the `getting started guide `_. - -.. code-block:: python - - # IBM cloud channel - QiskitRuntimeService.save_account(channel="ibm_cloud", token="", instance="", overwrite=True) - - # IBM quantum channel - QiskitRuntimeService.save_account(channel="ibm_quantum", token="", overwrite=True) - -**Updated - Name saved credentials** -You can now name your saved credentials and load the credentials by name. - -**Example:** - -.. code-block:: python - - # Save different accounts for open and premium access - - QiskitRuntimeService.save_account(channel="ibm_quantum", token="", instance="h1/g1/p1", name="premium") - QiskitRuntimeService.save_account(channel="ibm_quantum", token="", instance="h2/g2/p2", name="open") - - # Load the "open" credentials - - service = QiskitRuntimeService(name="open") - -**Legacy - Load accounts** - -.. code-block:: python - - IBMQ.load_account() - -**Updated - Load accounts** - -The new syntax combines the functionality from ``load_account()`` and ``get_provider()`` in one statement. The ``channel`` input parameter is optional. If multiple accounts have been saved in one device and no ``channel`` is provided, the default is ``"ibm_cloud"``. - -.. code-block:: python - - # To access saved credentials for the IBM cloud channel - service = QiskitRuntimeService(channel="ibm_cloud") - - # To access saved credentials for the IBM quantum channel - service = QiskitRuntimeService(channel="ibm_quantum") - - -Channel selection (get a provider) ------------------------------------------- - -Use the updated code to select a channel. - -**Legacy** - -.. code-block:: python - - provider = IBMQ.get_provider(project="my_project", group="my_group", hub="my_hub") - -**Updated** - -The new syntax combines the functionality from ``load_account()`` and ``get_provider()`` in one statement. -When using the ``ibm_quantum`` channel, the ``hub``, ``group``, and ``project`` are specified through the new -``instance`` keyword. - -.. code-block:: python - - # To access saved credentials for the IBM cloud channel - service = QiskitRuntimeService(channel="ibm_cloud") - - # To access saved credentials for the IBM quantum channel and select an instance - service = QiskitRuntimeService(channel="ibm_quantum", instance="my_hub/my_group/my_project") - - -Get the backend ------------------- -Use the updated code to view backends. - -**Legacy** - -.. code-block:: python - - provider = IBMQ.get_provider(hub="h1", group="g1", project="p1") - backend = provider.get_backend("ibm_backend") - -**Updated** - -.. code-block:: python - - # You can specify the instance in service.backend() instead of initializing a new service - backend = service.backend("ibm_backend", instance="h1/g1/p1") diff --git a/docs/migrate/migrate-tuning.rst b/docs/migrate/migrate-tuning.rst deleted file mode 100644 index 40527d8e0..000000000 --- a/docs/migrate/migrate-tuning.rst +++ /dev/null @@ -1,132 +0,0 @@ -Guide on algorithm tuning options -================================= - -One of the advantages of the primitives is that they abstract away the circuit execution setup so that algorithm developers -can focus on the pure algorithmic components. However, sometimes, to get the most out of an algorithm, you might want -to tune certain primitive options. This section describes some of the common settings you might need. - -.. |qiskit.primitives| replace:: ``qiskit.primitives`` -.. _qiskit.primitives: https://qiskit.org/documentation/apidoc/primitives.html - -.. |qiskit_aer.primitives| replace:: ``qiskit_aer.primitives`` -.. _qiskit_aer.primitives: https://qiskit.org/documentation/locale/de_DE/apidoc/aer_primitives.html - -.. attention:: - - This section focuses on Qiskit Runtime primitive :class:`.Options` (imported from ``qiskit_ibm_runtime``). While - most of the `primitives` interface is common across implementations, most :class:`.Options` are not. Consult the - corresponding API references for information about the |qiskit.primitives|_ and |qiskit_aer.primitives|_ options. - -1. Shots -~~~~~~~~ - -For some algorithms, setting a specific number of shots is a core part of their routines. Previously, shots could be set during the call to `backend.run()`. For example, ``backend.run(shots=1024)``. Now, that setting is part of the execution -options ("second level option"). This can be done during the primitive setup: - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator, Options - - options = Options() - options.execution.shots = 1024 - - estimator = Estimator(session=session, options=options) - - -If you need to modify the number of shots set between iterations (primitive calls), you can set the -shots directly in the ``run()`` method. This overwrites the initial ``shots`` setting. - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator - - estimator = Estimator(session=session) - - estimator.run(circuits=circuits, observables=observables, shots=50) - - # other logic - - estimator.run(circuits=circuits, observables=observables, shots=100) - -For more information about the primitive options, refer to the -`Options class API reference `_. - - -2. Transpilation -~~~~~~~~~~~~~~~~ - -By default, the Qiskit Runtime primitives perform circuit transpilation. The optimization level you choose affects the transpilation strategy and might include additional error suppression mechanisms. Level 0 only involves basic transpilation. -To learn about each optimization level, view the Optimization level table in the -`Error suppression topic `__. - -.. note:: - When using primitives, optimization levels 2 and 3 behave like level 1. If you want to use more advanced optimization, use the Qiskit transpiler locally and then pass the transpiled circuits to the primitives. For instructions see the `Submitting user-transpiled circuits using primitives `__ tutorial. - -The optimization level option is a "first level option", and can be set as follows: - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator, Options - - options = Options(optimization_level=1) - - # or.. - options = Options() - options.optimization_level = 1 - - estimator = Estimator(session=session, options=options) - - -You might want to configure your transpilation strategy further, and for this, there are advanced transpilation -options you can set up. These are "second level options", and can be set as follows: - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator, Options - - options = Options() - options.transpilation.initial_layout = ... - options.transpilation.routing_method = ... - - estimator = Estimator(session=session, options=options) - -For more information, and a complete list of advanced transpilation options, see the Advanced transpilation options table in the -`Error suppression topic `__. - -To specify settings that are not available through the primitives interface or use custom transpiler passes, set ``skip_transpilation=True`` to submit user-transpiled circuits. This is described in the -`Submitting user-transpiled circuits using primitives tutorial `_. - -The ``skip_transpilation`` option is an advanced transpilation option, and is set as follows: - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator, Options - - options = Options() - options.transpilation.skip_transpilation = True - - estimator = Estimator(session=session, options=options) - - -3. Error mitigation -~~~~~~~~~~~~~~~~~~~ - -You might want to use different error mitigation methods and see how these affect the performance of your -algorithm. These can also be set through the ``resilience_level`` option. The method selected for each level is -different for ``Sampler`` and ``Estimator``. You can find more information in the -`Configure error mitigation topic `_. - -The configuration is similar to the other options: - -.. code-block:: python - - from qiskit_ibm_runtime import Estimator, Options - - options = Options(resilience_level = ) - - # or... - - options = Options() - options.resilience_level = 2 - - estimator = Estimator(session=session, options=options) diff --git a/docs/migrate/migrate-update-parm.rst b/docs/migrate/migrate-update-parm.rst deleted file mode 100644 index e7084ee02..000000000 --- a/docs/migrate/migrate-update-parm.rst +++ /dev/null @@ -1,75 +0,0 @@ -Parametrized circuits with primitives -======================================= - - -Parametrized circuits are a commonly used tool for quantum algorithm design. -Because `backend.run()` did not accept parametrized circuits, the parameter binding step had to be integrated in the algorithm workflow. The primitives can perform the parameter binding step internally, which results in a simplification of the algorithm-side logic. - -The following example summarizes the new workflow for managing parametrized circuits. - -Example ---------- -Let's define a parametrized circuit: - -.. code-block:: python - - from qiskit.circuit import QuantumCircuit, ParameterVector - - n = 3 - thetas = ParameterVector('θ',n) - - qc = QuantumCircuit(n, 1) - qc.h(0) - - for i in range(n-1): - qc.cx(i, i+1) - - for i,t in enumerate(thetas): - qc.rz(t, i) - - for i in reversed(range(n-1)): - qc.cx(i, i+1) - - qc.h(0) - qc.measure(0, 0) - - qc.draw() - -We want to assign the following parameter values to the circuit: - -.. code-block:: python - - import numpy as np - theta_values = [np.pi/2, np.pi/2, np.pi/2] - - -Legacy ---------- -Previously, the parameter values had to be bound to their respective circuit parameters before calling `backend.run()`. - -.. code-block:: python - - from qiskit import Aer - - bound_circuit = qc.bind_parameters(theta_values) - bound_circuit.draw() - - backend = Aer.get_backend('aer_simulator') - job = backend.run(bound_circuit) - counts = job.result().get_counts() - print(counts) - -Primitives ------------- -Now, the primitives take in parametrized circuits directly, together with the parameter values, and the parameter assignment operation can be performed more efficiently on the server side of the primitive. - -This feature is particularly interesting when working with iterative algorithms because the parametrized circuit remains unchanged between calls while the parameter values change. The primitives can transpile once and then cache the unbound circuit, using classical resources more efficiently. Moreover, only the updated parameters are transferred to the cloud, saving additional bandwidth. - -.. code-block:: python - - from qiskit.primitives import Sampler - - sampler = Sampler() - job = sampler.run(qc, theta_values) - result = job.result().quasi_dists - print(result) diff --git a/docs/primitives.rst b/docs/primitives.rst deleted file mode 100644 index b7bfa0d3e..000000000 --- a/docs/primitives.rst +++ /dev/null @@ -1,67 +0,0 @@ -Introduction to primitives -============================= - -With Qiskit Runtime, we are introducing a new set of interfaces, in the form of primitives, to expand on how users run jobs on quantum computers. - -The existing Qiskit interface to backends (`backend.run()`) was originally designed to accept a list of circuits and return counts for every job. Over time, it became clear that users have diverse purposes for quantum computing, and therefore the ways in which they define the requirements for their computing jobs are expanding. Therefore, their results also look different. - -For example, an algorithm researcher and developer cares about information beyond counts; they are more focused on efficiently calculating quasi-probability distribution and expectation values of observables. - -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 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 --------------------- - -The following primitives are available: - - -+-----------------------+-----------------------+------------------------------------+ -| Primitive | Description | Example output | -+=======================+=======================+====================================+ -| Estimator | Allows a user to | .. image:: images/estimator.png | -| | specify a list of | | -| | circuits and | | -| | observables and | | -| | selectively group | | -| | between the lists to | | -| | efficiently evaluate | | -| | expectation values | | -| | and variances for a | | -| | parameter input. It | | -| | is designed to enable | | -| | users to efficiently | | -| | calculate and | | -| | interpret expectation | | -| | values of quantum | | -| | operators that are | | -| | required for many | | -| | near-term quantum | | -| | algorithms. | | -+-----------------------+-----------------------+------------------------------------+ -| Sampler | Allows a user to | .. image:: images/sampler.png | -| | input a circuit and | | -| | then generate | | -| | quasi-probability | | -| | distribution. | | -| | This generation | | -| | enables users to more | | -| | efficiently evaluate | | -| | the possibility of | | -| | multiple relevant | | -| | data points in the | | -| | context of | | -| | destructive | | -| | interference. | | -+-----------------------+-----------------------+------------------------------------+ - - -How to use primitives ---------------------- - -Primitive interfaces vary based on the type of task that you want to run on the quantum computer and the corresponding data that you want returned as a result. After identifying the appropriate primitive for your program, you can use Qiskit to prepare inputs, such as circuits, observables (for Estimator), and customizable options to optimize your job. For more information, see the appropriate topic: - -* `Getting started with Estimator <./tutorials/how-to-getting-started-with-estimator.ipynb>`__ -* `Getting started with Sampler <./tutorials/how-to-getting-started-with-sampler.ipynb>`__ -* :ref:`Migrate from qiskit-ibmq-provider to qiskit-ibm-runtime ` diff --git a/docs/retired.rst b/docs/retired.rst deleted file mode 100644 index ce0d38382..000000000 --- a/docs/retired.rst +++ /dev/null @@ -1,74 +0,0 @@ -######################################### -Retired systems -######################################### - -The following systems have been retired. For the full list of available systems, run `service.backends()`. For more information, see `Run on quantum backends `__. - -To retrieve job results from retired backends, use `QiskitRuntimeService.jobs `_ for runtime jobs and `qiskit-ibm-provider `_ for everything else. - - -+-------------------------------+----------------------+ -| System name | Qubit count | -+===============================+======================+ -| ``ibm_washington`` | 127 | -+-------------------------------+----------------------+ -| ``ibmq_oslo`` | 7 | -+-------------------------------+----------------------+ -| ``ibmq_geneva`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_toronto`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_montreal`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_armonk`` | 1 | -+-------------------------------+----------------------+ -| ``ibmq_brooklyn`` | 65 | -+-------------------------------+----------------------+ -| ``ibmq_bogota`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_santiago`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_casablanca`` | 7 | -+-------------------------------+----------------------+ -| ``ibmq_sydney`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_dublin`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_manhattan`` | 65 | -+-------------------------------+----------------------+ -| ``ibmq_5_yorktown`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_16_melbourne`` | 15 | -+-------------------------------+----------------------+ -| ``ibmq_paris`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_rome`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_athens`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_berlin`` | 27 | -+-------------------------------+----------------------+ -| ``ibmq_boeblingen`` | 20 | -+-------------------------------+----------------------+ -| ``ibmq_ourense`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_vigo`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_valencia`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_almaden`` | 20 | -+-------------------------------+----------------------+ -| ``ibmq_singapore`` | 20 | -+-------------------------------+----------------------+ -| ``ibmq_johannesburg`` | 20 | -+-------------------------------+----------------------+ -| ``ibmq_essex`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_burlington`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_london`` | 5 | -+-------------------------------+----------------------+ -| ``ibmq_rochester`` | 53 | -+-------------------------------+----------------------+ -| ``ibmq_cambridge`` | 28 | -+-------------------------------+----------------------+ diff --git a/docs/sessions.rst b/docs/sessions.rst deleted file mode 100644 index 3a986d077..000000000 --- a/docs/sessions.rst +++ /dev/null @@ -1,199 +0,0 @@ -Introduction to sessions -============================= - -A session allows a collection of jobs to be grouped and jointly scheduled by the Qiskit Runtime service, facilitating iterative use of quantum computers without incurring queuing delays on each iteration. This eliminates artificial delays caused by other users’ jobs running on the same quantum device during the session. - -.. image:: images/session-overview.png - :width: 400 - -Compared with jobs that use the `fair-share scheduler `__, sessions become particularly beneficial when running programs that require iterative calls between classical and quantum resources, where a large number of jobs are submitted sequentially. This is the case, for example, when training a variational algorithm such as VQE or QAOA, or in device characterization experiments. - -Runtime sessions can be used in conjunction with Qiskit Runtime primitives. Primitive program interfaces vary based on the type of task that you want to run on the quantum computer and the corresponding data that you want returned as a result. After identifying the appropriate primitive for your program, you can use Qiskit to prepare inputs, such as circuits, observables (for Estimator), and customizable options to optimize your job. For more information, see the `Primitives `__ topic. - -Benefits of using sessions ---------------------------- - -There are several benefits to using sessions: - -* Jobs that belong to a single algorithm run are run together without interruption, increasing efficiency if your program submits multiple sequential jobs. - - .. note:: - * The queuing time does not decrease for the first job submitted within a session. Therefore, a session does not provide any benefits if you only need to run a single job. - * If the first session job is cancelled, subsequent session jobs will all fail. - -* When using sessions, the uncertainty around queuing time is significantly reduced. This allows better estimation of a workload's total runtime and better resource management. -* In a device characterization context, being able to run experiments closely together helps prevent device drifts and provide more accurate results. -* While the session is active, you can submit different jobs, inspect job results, and re-submit new jobs without opening a new session. -* You maintain the flexibility to deploy your programs either remotely (cloud / on-premises) or locally (your laptop). - -The mechanics of sessions (queuing) ----------------------------------------- - -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 no jobs that are part of the active session are ready, the session is deactivated (paused), and the next job from the regular fair-share queue is run. See :ref:`ttl` for more information. - -A quantum processor still executes one job at a time. Therefore, jobs that belong to a session still need to wait for their turn if one is already running. - -.. note:: - * Internal systems jobs such as calibration have priority over session jobs. - -Maximum session timeout -++++++++++++++++++++++++++++ - -When a session is started, it is assigned a *maximum session timeout* -value. You can set this value by using the ``max_time`` parameter, which -can be greater than the program's ``max_execution_time``. For -instructions, see `Run a primitive in a session `__. - -If you do not specify a timeout value, it is set to the system limit. - -To find the maximum session timeout value for a session, follow the instructions in `Determine session details `__. - - -.. _ttl: - -Interactive timeout value -+++++++++++++++++++++++++++++ - -Every session has an *interactive timeout value* (ITTL, or interactive time to live). If there are no session jobs queued within the -ITTL window, the session is temporarily deactivated and normal job -selection resumes. A deactivated session can be resumed if it has not -reached its maximum timeout value. The session is resumed when a -subsequent session job starts. Once a session is deactivated, its next -job waits in the queue like other jobs. - -After a session is deactivated, the next job in the queue is selected to -run. This newly selected job (which can belong to a different user) can -run as a singleton, but it can also start a different session. In other -words, a deactivated session does not block the creation of other -sessions. Jobs from this new session would then take priority until it -is deactivated or closed, at which point normal job selection resumes. - -To find the interactive timeout value for a session, follow the instructions in `Determine session details `__. - -.. _ends: - -What happens when a session ends -------------------------------------- - -A session ends by reaching its maximum timeout value, when it is `closed `__, or when it is canceled by using the `session.cancel()` method. What happens to unfinished session jobs when the session ends depends on how it ended: - - -.. note:: - Previously, `session.close()` **canceled** the session. Starting with `qiskit-ibm-runtime` 0.13, `session.close()` **closes** the session. The `session.cancel()` method was added in `qiskit-ibm-runtime` 0.13. - -If the maximum timeout value was reached: - - Any jobs that are already running continue to run. - - Any queued jobs remaining in the session are put into a failed state. - - No further jobs can be submitted to the session. - - The session cannot be reopened. - -If the maximum timeout value has not been reached: - -- When using `qiskit-ibm-runtime` 0.13 or later releases: - - If a session is closed: - - Session status becomes "In progress, not accepting new jobs". - - New job submissions to the session are rejected. - - Queued or running jobs continue to run. - - The session cannot be reopened. - - If a session is canceled: - - Session status becomes "Closed." - - Running jobs continue to run. - - Queued jobs are put into a failed state. - - The session cannot be reopened. - -- When using Qiskit Runtime releases before 0.13: - - Any jobs that are already running continue to run. - - Any queued jobs remaining in the session are put into a failed state. - - No further jobs can be submitted to the session. - - The session cannot be reopened. - -Different ways of using sessions ----------------------------------- - -Sessions can be used for iterative or batch execution. - -Iterative -+++++++++++++++++++++ - -Any session job submitted within the five-minute interactive timeout, also known as interactive time to live (ITTL), is processed immediately. This allows some time for variational algorithms, such as VQE, to perform classical post-processing. - -- When a session is active, its jobs get priority until ITTL or max timeout is reached. -- Post-processing could be done anywhere, such as a personal computer, cloud service, or an HPC environment. - -.. image:: images/iterative.png - -.. note:: - There might be a limit imposed on the ITTL value depending on whether your hub is Premium, Open, and so on. - -This is an example of running an iterative workload that uses the classical SciPy optimizer to minimize a cost function. In this model, SciPy uses the output of the cost function to calculate its next input. - -.. code-block:: python - - def cost_func(params, ansatz, hamiltonian, estimator): - # Return estimate of energy from estimator - - energy = estimator.run(ansatz, hamiltonian, parameter_values=params).result().values[0] - return energy - - x0 = 2 * np.pi * np.random.random(num_params) - - session = Session(backend=backend) - - estimator = Estimator(session=session, options={"shots": int(1e4)}) - res = minimize(cost_func, x0, args=(ansatz, hamiltonian, estimator), method="cobyla") - - # Close the session because we didn't use a context manager. - session.close() - - -Batch -+++++++++++++++++++++ - -Ideal for running experiments closely together to avoid device drifts, that is, to maintain device characterization. - -- Suitable for batching many jobs together. -- The classical computation, such as compilation, of the jobs is run in parallel. This means running multiple jobs in a batch would be significantly faster than running them serially. - - -.. note:: - When batching, jobs are not guaranteed to run in the order they are submitted. - -.. image:: images/batch.png - -The following example shows how you can divide up a long list of circuits into multiple jobs and run them as a batch to take advantage of the parallel processing. - -.. code-block:: python - - backend = service.backend("ibm_sherbrooke") - - with Session(backend=backend): - estimator = Estimator() - start_idx = 0 - jobs = [] - while start_idx < len(circuits): - end_idx = start_idx + backend.max_circuits - jobs.append(estimator.run(circuits[start_idx:end_idx], obs[start_idx:end_idx], params[start_idx:end_idx])) - start_idx = end_idx - -Sessions and reservations -------------------------- - -IBM Quantum Premium users can access both reservations and sessions on specific backends. Such users should plan ahead and decide whether to use a session or a reservation. You *can* use a session within a reservation. However, if you use a session within a reservation and some session jobs don’t finish during the reservation window, the remaining pending jobs might fail. If you use session inside a reservation, we suggest you set a realistic ``max_time`` value. - -.. image:: images/jobs-failing.png - -Summary ---------- - -- Jobs within an active session take priority over other queued jobs. -- A session becomes active when its first job starts running. -- A session stays active until one of the following happens: - - Its maximum timeout value is reached. In this case all queued jobs are canceled, but running jobs will finish. - - Its interactive timeout value is reached. In this case the session is deactivated but can be resumed if another session job starts running. - - The session is closed or cancelled. This can be done using the corresponding methods or upon exiting a session context. -- Sessions can be used for iterative or batch execution. - -Next steps ------------- - -`Run a primitive in a session `__ diff --git a/program_source/__init__.py b/program_source/__init__.py deleted file mode 100644 index 2ba089a0d..000000000 --- a/program_source/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# This code is part of qiskit-runtime. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Main entry point for the qiskit_runtime""" - - -try: - from .version import version as __version__ -except ImportError: - __version__ = "0.0.0" diff --git a/program_source/circuit_runner/__init__.py b/program_source/circuit_runner/__init__.py deleted file mode 100644 index 24326fd26..000000000 --- a/program_source/circuit_runner/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# This code is part of qiskit-runtime. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -Qiskit circuit runner module -""" diff --git a/program_source/circuit_runner/circuit_runner.json b/program_source/circuit_runner/circuit_runner.json deleted file mode 100644 index b32e38692..000000000 --- a/program_source/circuit_runner/circuit_runner.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "circuit-runner", - "description": "A runtime program that takes one or more circuits, compiles them, executes them, and optionally applies measurement error mitigation.", - "max_execution_time": 14400, - "version": "1.0", - "parameters": [ - {"name": "circuits", "description": "A circuit or a list of circuits.", "type": "A QuantumCircuit or a list of QuantumCircuits.", "required": true}, - {"name": "shots", "description": "Number of repetitions of each circuit, for sampling. Default: 1024.", "type": "int", "required": false}, - {"name": "initial_layout", "description": "Initial position of virtual qubits on physical qubits.", "type": "dict or list", "required": false}, - {"name": "layout_method", "description": "Name of layout selection pass ('trivial', 'dense', 'noise_adaptive', 'sabre')", "type": "string", "required": false}, - {"name": "routing_method", "description": "Name of routing pass ('basic', 'lookahead', 'stochastic', 'sabre').", "type": "string", "required": false}, - {"name": "translation_method", "description": "Name of translation pass ('unroller', 'translator', 'synthesis').", "type": "string", "required": false}, - {"name": "seed_transpiler", "description": "Sets random seed for the stochastic parts of the transpiler.", "type": "int", "required": false}, - {"name": "optimization_level", "description": "How much optimization to perform on the circuits (0-3). Higher levels generate more optimized circuits. Default is 1.", "type": "int", "required": false}, - {"name": "init_qubits", "description": "Whether to reset the qubits to the ground state for each shot.", "type": "bool", "required": false}, - {"name": "rep_delay", "description": "Delay between programs in seconds.", "type": "float", "required": false}, - {"name": "transpiler_options", "description": "Additional compilation options.", "type": "dict", "required": false}, - {"name": "measurement_error_mitigation", "description": "Whether to apply measurement error mitigation. Default is False.", "type": "bool", "required": false} - ], - "return_values": [ - {"name": "-", "description": "Circuit execution results.", "type": "RunnerResult object"} - ] -} diff --git a/program_source/circuit_runner/circuit_runner.py b/program_source/circuit_runner/circuit_runner.py deleted file mode 100644 index 82a9aaf7d..000000000 --- a/program_source/circuit_runner/circuit_runner.py +++ /dev/null @@ -1,68 +0,0 @@ -# This code is part of qiskit-runtime. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Circuit-runner runtime program. - -This is a simplified version of the circuit-runner program. -""" - -from qiskit.compiler import transpile, schedule - - -def main( - backend, - user_messenger, # pylint: disable=unused-argument - circuits, - initial_layout=None, - seed_transpiler=None, - optimization_level=None, - transpiler_options=None, - scheduling_method=None, - schedule_circuit=False, - inst_map=None, - meas_map=None, - measurement_error_mitigation=False, - **kwargs, -): - """Run the circuits on the backend.""" - - # transpiling the circuits using given transpile options - transpiler_options = transpiler_options or {} - circuits = transpile( - circuits, - initial_layout=initial_layout, - seed_transpiler=seed_transpiler, - optimization_level=optimization_level, - backend=backend, - **transpiler_options, - ) - - if schedule_circuit: - circuits = schedule( - circuits=circuits, - backend=backend, - inst_map=inst_map, - meas_map=meas_map, - method=scheduling_method, - ) - - if not isinstance(circuits, list): - circuits = [circuits] - - # Compute raw results - result = backend.run(circuits, **kwargs).result() - - if measurement_error_mitigation: - # Performs measurement error mitigation. - pass - - return result.to_dict() diff --git a/program_source/version.py b/program_source/version.py deleted file mode 100644 index af762813a..000000000 --- a/program_source/version.py +++ /dev/null @@ -1,5 +0,0 @@ -# THIS FILE IS GENERATED FROM QISKIT_RUNTIME SETUP.PY -# pylint: disable=missing-module-docstring,invalid-name -short_version = "0.1.0" -version = "0.1.0.dev0+378fb03" -release = False diff --git a/qiskit_ibm_runtime/VERSION.txt b/qiskit_ibm_runtime/VERSION.txt index 04a373efe..c5523bd09 100644 --- a/qiskit_ibm_runtime/VERSION.txt +++ b/qiskit_ibm_runtime/VERSION.txt @@ -1 +1 @@ -0.16.0 +0.17.0 diff --git a/qiskit_ibm_runtime/__init__.py b/qiskit_ibm_runtime/__init__.py index bb3963f49..ca70e1557 100644 --- a/qiskit_ibm_runtime/__init__.py +++ b/qiskit_ibm_runtime/__init__.py @@ -24,7 +24,7 @@ execute significantly faster within its improved hybrid quantum/classical process. Primitives and sessions ------------------------ +======================= Qiskit Runtime has two predefined primitives: ``Sampler`` and ``Estimator``. These primitives provide a simplified interface for performing foundational quantum @@ -68,7 +68,7 @@ print(f"Estimator results: {job.result()}") Backend data ------------- +============ :class:`QiskitRuntimeService` also has methods, such as :meth:`backend`, :meth:`backends`, and :meth:`least_busy`, that allow you to query for a target @@ -76,86 +76,76 @@ that contains methods and attributes describing the backend. Supplementary Information -------------------------- - -.. dropdown:: Account initialization - :animate: fade-in-slide-down +========================= - You need to initialize your account before you can start using the Qiskit Runtime service. - This is done by initializing a :class:`QiskitRuntimeService` instance with your - account credentials. If you don't want to pass in the credentials each time, you - can use the :meth:`QiskitRuntimeService.save_account` method to save the credentials - on disk. - - Qiskit Runtime is available on both IBM Cloud and IBM Quantum, and you can specify - ``channel="ibm_cloud"`` for IBM Cloud and ``channel="ibm_quantum"`` for IBM Quantum. The default - is IBM Cloud. +Account initialization +------------------------- -.. dropdown:: Runtime Jobs - :animate: fade-in-slide-down +You need to initialize your account before you can start using the Qiskit Runtime service. +This is done by initializing a :class:`QiskitRuntimeService` instance with your +account credentials. If you don't want to pass in the credentials each time, you +can use the :meth:`QiskitRuntimeService.save_account` method to save the credentials +on disk. - When you use the ``run()`` method of the :class:`Sampler` or :class:`Estimator` - to invoke the primitive, a - :class:`RuntimeJob` instance is returned. This class has all the basic job - methods, such as :meth:`RuntimeJob.status`, :meth:`RuntimeJob.result`, and - :meth:`RuntimeJob.cancel`. +Qiskit Runtime is available on both IBM Cloud and IBM Quantum, and you can specify +``channel="ibm_cloud"`` for IBM Cloud and ``channel="ibm_quantum"`` for IBM Quantum. The default +is IBM Cloud. -.. dropdown:: Logging - :animate: fade-in-slide-down +Runtime Jobs +------------ - ``qiskit-ibm-runtime`` uses the ``qiskit_ibm_runtime`` logger. +When you use the ``run()`` method of the :class:`Sampler` or :class:`Estimator` +to invoke the primitive, a +:class:`RuntimeJob` instance is returned. This class has all the basic job +methods, such as :meth:`RuntimeJob.status`, :meth:`RuntimeJob.result`, and +:meth:`RuntimeJob.cancel`. - Two environment variables can be used to control the logging: +Logging +------- - * ``QISKIT_IBM_RUNTIME_LOG_LEVEL``: Specifies the log level to use. - If an invalid level is set, the log level defaults to ``WARNING``. - The valid log levels are ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, and ``CRITICAL`` - (case-insensitive). If the environment variable is not set, then the parent logger's level - is used, which also defaults to ``WARNING``. - * ``QISKIT_IBM_RUNTIME_LOG_FILE``: Specifies the name of the log file to use. If specified, - messages will be logged to the file only. Otherwise messages will be logged to the standard - error (usually the screen). +``qiskit-ibm-runtime`` uses the ``qiskit_ibm_runtime`` logger. - For more advanced use, you can modify the logger itself. For example, to manually set the level - to ``WARNING``:: +Two environment variables can be used to control the logging: - import logging - logging.getLogger('qiskit_ibm_runtime').setLevel(logging.WARNING) + * ``QISKIT_IBM_RUNTIME_LOG_LEVEL``: Specifies the log level to use. + If an invalid level is set, the log level defaults to ``WARNING``. + The valid log levels are ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR``, and ``CRITICAL`` + (case-insensitive). If the environment variable is not set, then the parent logger's level + is used, which also defaults to ``WARNING``. + * ``QISKIT_IBM_RUNTIME_LOG_FILE``: Specifies the name of the log file to use. If specified, + messages will be logged to the file only. Otherwise messages will be logged to the standard + error (usually the screen). -.. dropdown:: Interim and final results - :animate: fade-in-slide-down +For more advanced use, you can modify the logger itself. For example, to manually set the level +to ``WARNING``:: - Some runtime programs provide interim results that inform you about program - progress. You can choose to stream the interim results and final result when you run the - program by passing in the ``callback`` parameter, or at a later time using - the :meth:`RuntimeJob.stream_results` method. For example:: + import logging + logging.getLogger('qiskit_ibm_runtime').setLevel(logging.WARNING) - from qiskit.test.reference_circuits import ReferenceCircuits - from qiskit_ibm_runtime import QiskitRuntimeService, Sampler +Interim and final results +------------------------- - service = QiskitRuntimeService() - backend = service.backend("ibmq_qasm_simulator") +Some runtime programs provide interim results that inform you about program +progress. You can choose to stream the interim results and final result when you run the +program by passing in the ``callback`` parameter, or at a later time using +the :meth:`RuntimeJob.stream_results` method. For example:: - def result_callback(job_id, result): - print(result) + from qiskit.test.reference_circuits import ReferenceCircuits + from qiskit_ibm_runtime import QiskitRuntimeService, Sampler - # Stream results as soon as the job starts running. - job = Sampler(backend).run(ReferenceCircuits.bell(), callback=result_callback) - print(job.result()) + service = QiskitRuntimeService() + backend = service.backend("ibmq_qasm_simulator") -.. dropdown:: Uploading a program - :animate: fade-in-slide-down + def result_callback(job_id, result): + print(result) - Authorized users can upload their custom Qiskit Runtime programs. - A Qiskit Runtime program is a piece of Python - code and its metadata that takes certain inputs, performs - quantum and maybe classical processing, and returns the results. + # Stream results as soon as the job starts running. + job = Sampler(backend).run(ReferenceCircuits.bell(), callback=result_callback) + print(job.result()) - Files related to writing a runtime program are in the - ``qiskit_ibm_runtime/program`` directory. Classes -========================== +======= .. autosummary:: :toctree: ../stubs/ @@ -165,8 +155,6 @@ def result_callback(job_id, result): Session IBMBackend RuntimeJob - RuntimeProgram - ParameterNamespace RuntimeOptions RuntimeEncoder RuntimeDecoder @@ -177,7 +165,6 @@ def result_callback(job_id, result): from .qiskit_runtime_service import QiskitRuntimeService from .ibm_backend import IBMBackend from .runtime_job import RuntimeJob -from .runtime_program import RuntimeProgram, ParameterNamespace from .runtime_options import RuntimeOptions from .utils.json import RuntimeEncoder, RuntimeDecoder from .session import Session # pylint: disable=cyclic-import diff --git a/qiskit_ibm_runtime/api/clients/runtime.py b/qiskit_ibm_runtime/api/clients/runtime.py index f59708cff..b895b8644 100644 --- a/qiskit_ibm_runtime/api/clients/runtime.py +++ b/qiskit_ibm_runtime/api/clients/runtime.py @@ -47,74 +47,6 @@ def __init__( ) self._api = Runtime(self._session) - def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]: - """Return a list of runtime programs. - - Args: - limit: The number of programs to return. - skip: The number of programs to skip. - - Returns: - A list of runtime programs. - """ - return self._api.list_programs(limit, skip) - - def program_create( - self, - program_data: str, - name: str, - description: str, - max_execution_time: int, - is_public: Optional[bool] = False, - spec: Optional[Dict] = None, - ) -> Dict: - """Create a new program. - - Args: - name: Name of the program. - program_data: Program data (base64 encoded). - description: Program description. - max_execution_time: Maximum execution time. - is_public: Whether the program should be public. - spec: Backend requirements, parameters, interim results, return values, etc. - - Returns: - Server response. - """ - return self._api.create_program( - program_data=program_data, - name=name, - description=description, - max_execution_time=max_execution_time, - is_public=is_public, - spec=spec, - ) - - def program_get(self, program_id: str) -> Dict: - """Return a specific program. - - Args: - program_id: Program ID. - - Returns: - Program information. - """ - return self._api.program(program_id).get() - - def set_program_visibility(self, program_id: str, public: bool) -> None: - """Sets a program's visibility. - - Args: - program_id: Program ID. - public: If ``True``, make the program visible to all. - If ``False``, make the program visible to just your account. - - """ - if public: - self._api.program(program_id).make_public() - else: - self._api.program(program_id).make_private() - def program_run( self, program_id: str, @@ -168,44 +100,6 @@ def program_run( **hgp_dict, ) - def program_delete(self, program_id: str) -> None: - """Delete the specified program. - - Args: - program_id: Program ID. - """ - self._api.program(program_id).delete() - - def program_update( - self, - program_id: str, - program_data: str = None, - name: str = None, - description: str = None, - max_execution_time: int = None, - spec: Optional[Dict] = None, - ) -> None: - """Update a program. - - Args: - program_id: Program ID. - program_data: Program data (base64 encoded). - name: Name of the program. - description: Program description. - max_execution_time: Maximum execution time. - spec: Backend requirements, parameters, interim results, return values, etc. - """ - if program_data: - self._api.program(program_id).update_data(program_data) - - if any([name, description, max_execution_time, spec]): - self._api.program(program_id).update_metadata( - name=name, - description=description, - max_execution_time=max_execution_time, - spec=spec, - ) - def job_get(self, job_id: str, exclude_params: bool = None) -> Dict: """Get job data. @@ -374,13 +268,13 @@ def list_backends( """ return self._api.backends(hgp=hgp, channel_strategy=channel_strategy)["devices"] - def cloud_instance(self) -> bool: + def is_qctrl_enabled(self) -> bool: """Returns a boolean of whether or not the instance has q-ctrl enabled. Returns: Boolean value. """ - return self._api.cloud_instance() + return self._api.is_qctrl_enabled() def backend_configuration(self, backend_name: str) -> Dict[str, Any]: """Return the configuration of the IBM backend. diff --git a/qiskit_ibm_runtime/api/rest/program.py b/qiskit_ibm_runtime/api/rest/program.py deleted file mode 100644 index ce76bdeac..000000000 --- a/qiskit_ibm_runtime/api/rest/program.py +++ /dev/null @@ -1,106 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Program REST adapter.""" - -from typing import Dict, Any, Optional -from concurrent import futures - -from qiskit_ibm_provider.api.rest.base import RestAdapterBase -from ..session import RetrySession - - -class Program(RestAdapterBase): - """Rest adapter for program related endpoints.""" - - URL_MAP = { - "self": "", - "data": "/data", - "run": "/jobs", - "private": "/private", - "public": "/public", - } - - _executor = futures.ThreadPoolExecutor() - - def __init__(self, session: RetrySession, program_id: str, url_prefix: str = "") -> None: - """Job constructor. - - Args: - session: Session to be used in the adapter. - program_id: ID of the runtime program. - url_prefix: Prefix to use in the URL. - """ - super().__init__(session, "{}/programs/{}".format(url_prefix, program_id)) - - def get(self) -> Dict[str, Any]: - """Return program information. - - Returns: - JSON response. - """ - url = self.get_url("self") - return self.session.get(url).json() - - def make_public(self) -> None: - """Sets a runtime program's visibility to public.""" - url = self.get_url("public") - self.session.put(url) - - def make_private(self) -> None: - """Sets a runtime program's visibility to private.""" - url = self.get_url("private") - self.session.put(url) - - def delete(self) -> None: - """Delete this program.""" - url = self.get_url("self") - self.session.delete(url) - - def update_data(self, program_data: str) -> None: - """Update program data. - - Args: - program_data: Program data (base64 encoded). - """ - url = self.get_url("data") - self.session.put( - url, data=program_data, headers={"Content-Type": "application/octet-stream"} - ) - - def update_metadata( - self, - name: str = None, - description: str = None, - max_execution_time: int = None, - spec: Optional[Dict] = None, - ) -> None: - """Update program metadata. - - Args: - name: Name of the program. - description: Program description. - max_execution_time: Maximum execution time. - spec: Backend requirements, parameters, interim results, return values, etc. - """ - url = self.get_url("self") - payload: Dict = {} - if name: - payload["name"] = name - if description: - payload["description"] = description - if max_execution_time: - payload["cost"] = max_execution_time - if spec: - payload["spec"] = spec - - self.session.patch(url, json=payload) diff --git a/qiskit_ibm_runtime/api/rest/runtime.py b/qiskit_ibm_runtime/api/rest/runtime.py index 856a677f9..b5a58648b 100644 --- a/qiskit_ibm_runtime/api/rest/runtime.py +++ b/qiskit_ibm_runtime/api/rest/runtime.py @@ -22,7 +22,6 @@ from qiskit_ibm_provider.utils import local_to_utc from .runtime_session import RuntimeSession -from .program import Program from ...utils import RuntimeEncoder from .cloud_backend import CloudBackend @@ -39,17 +38,6 @@ class Runtime(RestAdapterBase): "cloud_instance": "/instance", } - def program(self, program_id: str) -> "Program": - """Return an adapter for the program. - - Args: - program_id: ID of the program. - - Returns: - The program adapter. - """ - return Program(self.session, program_id) - def program_job(self, job_id: str) -> "ProgramJob": """Return an adapter for the job. @@ -72,59 +60,6 @@ def runtime_session(self, session_id: str) -> "RuntimeSession": """ return RuntimeSession(self.session, session_id) - def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]: - """Return a list of runtime programs. - - Args: - limit: The number of programs to return. - skip: The number of programs to skip. - - Returns: - A list of runtime programs. - """ - url = self.get_url("programs") - payload: Dict[str, int] = {} - if limit: - payload["limit"] = limit - if skip: - payload["offset"] = skip - return self.session.get(url, params=payload).json() - - def create_program( - self, - program_data: str, - name: str, - description: str, - max_execution_time: int, - is_public: Optional[bool] = False, - spec: Optional[Dict] = None, - ) -> Dict: - """Upload a new program. - - Args: - program_data: Program data (base64 encoded). - name: Name of the program. - description: Program description. - max_execution_time: Maximum execution time. - is_public: Whether the program should be public. - spec: Backend requirements, parameters, interim results, return values, etc. - - Returns: - JSON response. - """ - url = self.get_url("programs") - payload = { - "name": name, - "data": program_data, - "cost": max_execution_time, - "description": description, - "is_public": is_public, - } - if spec is not None: - payload["spec"] = spec - data = json.dumps(payload) - return self.session.post(url, data=data).json() - def program_run( self, program_id: str, @@ -295,7 +230,7 @@ def backends( params["channel_strategy"] = channel_strategy return self.session.get(url, params=params, timeout=timeout).json() - def cloud_instance(self) -> bool: + def is_qctrl_enabled(self) -> bool: """Return boolean of whether or not the instance has q-ctrl enabled. Returns: diff --git a/qiskit_ibm_runtime/constants.py b/qiskit_ibm_runtime/constants.py index 3a5568cab..6dc82872a 100644 --- a/qiskit_ibm_runtime/constants.py +++ b/qiskit_ibm_runtime/constants.py @@ -14,7 +14,7 @@ from qiskit.providers.jobstatus import JobStatus -from .program.result_decoder import ResultDecoder +from .utils.result_decoder import ResultDecoder from .utils.estimator_result_decoder import EstimatorResultDecoder from .utils.sampler_result_decoder import SamplerResultDecoder from .utils.runner_result import RunnerResult diff --git a/qiskit_ibm_runtime/options/options.py b/qiskit_ibm_runtime/options/options.py index d5ae665de..063e76e5b 100644 --- a/qiskit_ibm_runtime/options/options.py +++ b/qiskit_ibm_runtime/options/options.py @@ -58,7 +58,7 @@ class Options: Refer to the `Qiskit Runtime documentation - `_. + `_. for more information about the error mitigation methods used at each level. max_execution_time: Maximum execution time in seconds, which is based @@ -69,7 +69,7 @@ class Options: Refer to the `Max execution time documentation - `_. + `_. for more information. transpilation: Transpilation options. See :class:`TranspilationOptions` for all diff --git a/qiskit_ibm_runtime/program/__init__.py b/qiskit_ibm_runtime/program/__init__.py deleted file mode 100644 index 8740e8fac..000000000 --- a/qiskit_ibm_runtime/program/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -""" -==================================================== -Runtime Programs (:mod:`qiskit_ibm_runtime.program`) -==================================================== - -.. currentmodule:: qiskit_ibm_runtime.program - -This package contains files to help you write your custom Qiskit Runtime programs. - -Only authorized users can upload their custom Qiskit Runtime programs. -A Qiskit Runtime program is a piece of Python -code and its metadata that takes certain inputs, performs -quantum and maybe classical processing, and returns the results. - -Each runtime program has both ``data`` and ``metadata``. Program data is -the Python code to be executed. Program metadata provides usage information, -such as program description, its inputs and outputs, and backend requirements. - -Each program data needs to have a ``main(backend, user_messenger, **kwargs)`` -method, which serves as the entry point to the program. The ``backend`` parameter -is a :class:`ProgramBackend` instance whose :meth:`ProgramBackend.run` method -can be used to submit circuits. The ``user_messenger`` is a :class:`UserMessenger` -instance whose :meth:`UserMessenger.publish` method can be used to publish interim and -final results. -See `qiskit_ibm_runtime/program/program_template.py` for a program data -template file. - -Each program metadata must include at least the program name, description, and -maximum execution time. You can find description of each metadata field in -the :meth:`QiskitRuntimeService.upload_program` method. Instead of passing in -the metadata fields individually, you can pass in a JSON file or a dictionary -to :meth:`QiskitRuntimeService.upload_program` via the ``metadata`` parameter. -`qiskit_ibm_runtime/program/program_metadata_sample.json` -is a sample file of program metadata. - -You can use the :meth:`QiskitRuntimeService.upload_program` to upload a program. -For example:: - - from qiskit_ibm_runtime import QiskitRuntimeService - - service = QiskitRuntimeService() - program_id = service.upload_program( - data="my_vqe.py", - metadata="my_vqe_metadata.json" - ) - -In the example above, the file ``my_vqe.py`` contains the program data, and -``my_vqe_metadata.json`` contains the program metadata. - -Method :meth:`QiskitRuntimeService.delete_program` allows you to delete a -program. - - -Classes -========================== -.. autosummary:: - :toctree: ../stubs/ - - ProgramBackend - UserMessenger - ResultDecoder -""" - -from .program_backend import ProgramBackend -from .user_messenger import UserMessenger -from .result_decoder import ResultDecoder diff --git a/qiskit_ibm_runtime/program/program_backend.py b/qiskit_ibm_runtime/program/program_backend.py deleted file mode 100644 index 6225dfdce..000000000 --- a/qiskit_ibm_runtime/program/program_backend.py +++ /dev/null @@ -1,57 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Base class for program backend.""" - -import logging -from typing import Union, List, Dict -from abc import abstractmethod, ABC - -from qiskit.providers.backend import BackendV1 as Backend -from qiskit.providers.job import JobV1 as Job -from qiskit.circuit import QuantumCircuit - -logger = logging.getLogger(__name__) - - -class ProgramBackend(Backend, ABC): - """Base class for a program backend. - - The ``main()`` function of your runtime program will receive an instance - of this class as the first parameter. You can then use the instance - to submit circuits to the target backend. - """ - - @abstractmethod - def run( - self, - circuits: Union[QuantumCircuit, List[QuantumCircuit]], - **run_config: Dict, - ) -> Job: - """Run on the backend. - - Runtime circuit execution is synchronous, and control will not go - back until the execution finishes. You can use the `timeout` parameter - to set a timeout value to wait for the execution to finish. Note that if - the execution times out, circuit execution results will not be available. - - Args: - circuits: An individual or a - list of :class:`~qiskit.circuits.QuantumCircuit` - to run on the backend. - **run_config: Extra arguments used to configure the run. - - Returns: - The job to be executed. - """ - # pylint: disable=arguments-differ - pass diff --git a/qiskit_ibm_runtime/program/program_metadata_sample.json b/qiskit_ibm_runtime/program/program_metadata_sample.json deleted file mode 100644 index 238fb96a3..000000000 --- a/qiskit_ibm_runtime/program/program_metadata_sample.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "runtime-simple", - "description": "Simple runtime program used for testing.", - "max_execution_time": 300, - "spec": { - "backend_requirements": { - "min_num_qubits": 5 - }, - "parameters": { - "type": "object", - "properties": { - "iterations": { - "description": "Number of iterations to run. Each iteration generates and runs a random circuit.", - "type": "integer" - } - }, - "required": ["iterations"] - }, - "return_values": { - "type": "string", - "description": "A string that says 'Hello, World!'." - }, - "interim_results": { - "type": "object", - "properties": { - "iteration": { - "description": "Iteration number.", - "type": "integer" - }, - "counts": { - "description": "Histogram data of the circuit result.", - "type": "object" - } - } - } - } -} diff --git a/qiskit_ibm_runtime/program/program_template.py b/qiskit_ibm_runtime/program/program_template.py deleted file mode 100644 index a876c85f1..000000000 --- a/qiskit_ibm_runtime/program/program_template.py +++ /dev/null @@ -1,51 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. -# pylint: disable=unused-argument -# pylint: disable=invalid-name - -"""Runtime program template. - -The ``main()`` method is the entry point of a runtime program. It takes a -:class:`ProgramBackend` and a :class:`UserMessenger` that can be used to -send circuits to the backend and messages to the user, respectively. -""" - -from typing import Any - -from qiskit_ibm_runtime.program import UserMessenger, ProgramBackend - - -def program(backend: ProgramBackend, user_messenger: UserMessenger, **kwargs): - """Function that does classical-quantum calculation.""" - # UserMessenger can be used to publish interim results. - user_messenger.publish("This is an interim result.") - return "final result" - - -def main(backend: ProgramBackend, user_messenger: UserMessenger, **kwargs) -> Any: - """This is the main entry point of a runtime program. - - The name of this method must not change. It also must have ``backend`` - and ``user_messenger`` as the first two positional arguments. - - Args: - backend: Backend for the circuits to run on. - user_messenger: Used to communicate with the program user. - **kwargs: User inputs. - - Returns: - The final result of the runtime program. - """ - # Massage the input if necessary. - result = program(backend, user_messenger, **kwargs) - # Final results can be directly returned - return result diff --git a/qiskit_ibm_runtime/program/user_messenger.py b/qiskit_ibm_runtime/program/user_messenger.py deleted file mode 100644 index e1aa71257..000000000 --- a/qiskit_ibm_runtime/program/user_messenger.py +++ /dev/null @@ -1,46 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Base class for handling communication with program users.""" - -import json -from typing import Any, Type - -from ..utils.json import RuntimeEncoder - - -class UserMessenger: - """Base class for handling communication with program users. - - The ``main()`` function of your runtime program will receive an instance - of this class as the second parameter. You can then use the instance - to send results back to the program user. - """ - - def publish( - self, - message: Any, - encoder: Type[json.JSONEncoder] = RuntimeEncoder, - ) -> None: - """Publish message. - - You can use this method to publish messages, such as interim and final results, - to the program user. The messages will be made immediately available to the user, - but they may choose not to receive the messages. - - Args: - message: Message to be published. Can be any type. - encoder: An optional JSON encoder for serializing - """ - # pylint: disable=unused-argument - # Default implementation for testing. - print(json.dumps(message, cls=encoder)) diff --git a/qiskit_ibm_runtime/qiskit_runtime_service.py b/qiskit_ibm_runtime/qiskit_runtime_service.py index 6ef274fad..85a2c1190 100644 --- a/qiskit_ibm_runtime/qiskit_runtime_service.py +++ b/qiskit_ibm_runtime/qiskit_runtime_service.py @@ -43,15 +43,13 @@ from .exceptions import IBMNotAuthorizedError, IBMInputValueError, IBMAccountError from .exceptions import ( IBMRuntimeError, - RuntimeDuplicateProgramError, RuntimeProgramNotFound, RuntimeJobNotFound, ) from .hub_group_project import HubGroupProject # pylint: disable=cyclic-import -from .program.result_decoder import ResultDecoder +from .utils.result_decoder import ResultDecoder from .runtime_job import RuntimeJob -from .runtime_program import RuntimeProgram, ParameterNamespace -from .utils import RuntimeDecoder, to_base64_string, to_python_identifier +from .utils import RuntimeDecoder, to_python_identifier from .api.client_parameters import ClientParameters from .runtime_options import RuntimeOptions from .ibm_backend import IBMBackend @@ -196,7 +194,6 @@ def __init__( self._channel_strategy = channel_strategy or self._account.channel_strategy self._channel = self._account.channel - self._programs: Dict[str, RuntimeProgram] = {} self._backends: Dict[str, "ibm_backend.IBMBackend"] = {} self._backend_configs: Dict[str, Any] = {} @@ -320,11 +317,21 @@ def _validate_channel_strategy(self) -> None: instance do not match. """ + qctrl_enabled = self._api_client.is_qctrl_enabled() if self._channel_strategy == "q-ctrl": - qctrl_enabled = self._api_client.cloud_instance() if not qctrl_enabled: raise IBMNotAuthorizedError( - "This account is not authorized to use ``q-ctrl`` as a channel strategy." + "The instance passed in is not compatible with Q-CTRL channel strategy. " + "Please switch to or create an instance with the Q-CTRL strategy enabled. " + "See https://cloud.ibm.com/docs/quantum-computing?" + "topic=quantum-computing-get-started for more information" + ) + else: + if qctrl_enabled: + raise IBMNotAuthorizedError( + "The instance passed in is only compatible with Q-CTRL performance " + "management strategy. " + "To use this instance, set channel_strategy='q-ctrl'." ) def _discover_cloud_backends(self) -> Dict[str, "ibm_backend.IBMBackend"]: @@ -562,7 +569,7 @@ def backends( QiskitRuntimeService.backends(open_pulse=True) For the full list of backend attributes, see the `IBMBackend` class documentation - + Returns: The list of available backends that match the filter. @@ -814,182 +821,10 @@ def backend( def get_backend(self, name: str = None, **kwargs: Any) -> Backend: return self.backend(name, **kwargs) - def pprint_programs( - self, - refresh: bool = False, - detailed: bool = False, - limit: int = 20, - skip: int = 0, - ) -> None: - """Pretty print information about available runtime programs. - - Args: - refresh: If ``True``, re-query the server for the programs. Otherwise - return the cached value. - detailed: If ``True`` print all details about available runtime programs. - limit: The number of programs returned at a time. Default and maximum - value of 20. - skip: The number of programs to skip. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - programs = self.programs(refresh, limit, skip) - for prog in programs: - print("=" * 50) - if detailed: - print(str(prog)) - else: - print( - f"{prog.program_id}:", - ) - print(f" Name: {prog.name}") - print(f" Description: {prog.description}") - - def programs( - self, refresh: bool = False, limit: int = 20, skip: int = 0 - ) -> List[RuntimeProgram]: - """Return available runtime programs. - - Currently only program metadata is returned. - - Args: - refresh: If ``True``, re-query the server for the programs. Otherwise - return the cached value. - limit: The number of programs returned at a time. ``None`` means no limit. - skip: The number of programs to skip. - - Returns: - A list of runtime programs. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - if skip is None: - skip = 0 - if not self._programs or refresh: - self._programs = {} - current_page_limit = 20 - offset = 0 - while True: - response = self._api_client.list_programs(limit=current_page_limit, skip=offset) - program_page = response.get("programs", []) - # count is the total number of programs that would be returned if - # there was no limit or skip - count = response.get("count", 0) - if limit is None: - limit = count - for prog_dict in program_page: - program = self._to_program(prog_dict) - self._programs[program.program_id] = program - num_cached_programs = len(self._programs) - if num_cached_programs == count or num_cached_programs >= (limit + skip): - # Stop if there are no more programs returned by the server or - # if the number of cached programs is greater than the sum of limit and skip - break - offset += len(program_page) - if limit is None: - limit = len(self._programs) - return list(self._programs.values())[skip : limit + skip] - - def program(self, program_id: str, refresh: bool = False) -> RuntimeProgram: - """Retrieve a runtime program. - - Currently only program metadata is returned. - - Args: - program_id: Program ID. - refresh: If ``True``, re-query the server for the program. Otherwise - return the cached value. - - Returns: - Runtime program. - - Raises: - RuntimeProgramNotFound: If the program does not exist. - IBMRuntimeError: If the request failed. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - if program_id not in self._programs or refresh: - try: - response = self._api_client.program_get(program_id) - except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeProgramNotFound(f"Program not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to get program: {ex}") from None - - self._programs[program_id] = self._to_program(response) - - return self._programs[program_id] - - def _to_program(self, response: Dict) -> RuntimeProgram: - """Convert server response to ``RuntimeProgram`` instances. - - Args: - response: Server response. - - Returns: - A ``RuntimeProgram`` instance. - """ - backend_requirements = {} - parameters = {} - return_values = {} - interim_results = {} - if "spec" in response: - backend_requirements = response["spec"].get("backend_requirements", {}) - parameters = response["spec"].get("parameters", {}) - return_values = response["spec"].get("return_values", {}) - interim_results = response["spec"].get("interim_results", {}) - - return RuntimeProgram( - program_name=response["name"], - program_id=response["id"], - description=response.get("description", ""), - parameters=parameters, - return_values=return_values, - interim_results=interim_results, - max_execution_time=response.get("cost", 0), - creation_date=response.get("creation_date", ""), - update_date=response.get("update_date", ""), - backend_requirements=backend_requirements, - is_public=response.get("is_public", False), - data=response.get("data", ""), - api_client=self._api_client, - ) - def run( self, program_id: str, - inputs: Union[Dict, ParameterNamespace], + inputs: Dict, options: Optional[Union[RuntimeOptions, Dict]] = None, callback: Optional[Callable] = None, result_decoder: Optional[Union[Type[ResultDecoder], Sequence[Type[ResultDecoder]]]] = None, @@ -1026,30 +861,12 @@ def run( RuntimeProgramNotFound: If the program cannot be found. IBMRuntimeError: An error occurred running the program. """ - if program_id not in ["sampler", "estimator", "circuit-runner", "qasm3-runner"]: - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) qrt_options: RuntimeOptions = options if options is None: qrt_options = RuntimeOptions() elif isinstance(options, Dict): qrt_options = RuntimeOptions(**options) - # If using params object, extract as dictionary. - if isinstance(inputs, ParameterNamespace): - inputs.validate() - inputs = vars(inputs) - qrt_options.validate(channel=self.channel) hgp_name = None @@ -1066,7 +883,6 @@ def run( warnings.warn( f"The backend {backend.name} currently has a status of {status.status_msg}." ) - try: response = self._api_client.program_run( program_id=program_id, @@ -1113,282 +929,6 @@ def run( ) return job - def upload_program(self, data: str, metadata: Optional[Union[Dict, str]] = None) -> str: - """Upload a runtime program. - - In addition to program data, the following program metadata is also - required: - - - name - - max_execution_time - - Program metadata can be specified using the `metadata` parameter or - individual parameter (for example, `name` and `description`). If the - same metadata field is specified in both places, the individual parameter - takes precedence. For example, if you specify:: - - upload_program(metadata={"name": "name1"}, name="name2") - - ``name2`` will be used as the program name. - - Args: - data: Program data or path of the file containing program data to upload. - metadata: Name of the program metadata file or metadata dictionary. - A metadata file needs to be in the JSON format. The ``parameters``, - ``return_values``, and ``interim_results`` should be defined as JSON Schema. - See :file:`program/program_metadata_sample.json` for an example. The - fields in metadata are explained below. - - * name: Name of the program. Required. - * max_execution_time: Maximum execution time in seconds. Required. - * description: Program description. - * is_public: Whether the runtime program should be visible to the public. - The default is ``False``. - * spec: Specifications for backend characteristics and input parameters - required to run the program, interim results and final result. - - * backend_requirements: Backend requirements. - * parameters: Program input parameters in JSON schema format. - * return_values: Program return values in JSON schema format. - * interim_results: Program interim results in JSON schema format. - - Returns: - Program ID. - - Raises: - IBMInputValueError: If required metadata is missing. - RuntimeDuplicateProgramError: If a program with the same name already exists. - IBMNotAuthorizedError: If you are not authorized to upload programs. - IBMRuntimeError: If the upload failed. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - program_metadata = self._read_metadata(metadata=metadata) - - for req in ["name", "max_execution_time"]: - if req not in program_metadata or not program_metadata[req]: - raise IBMInputValueError(f"{req} is a required metadata field.") - - if "def main(" not in data: - # This is the program file - with open(data, "r", encoding="utf-8") as file: - data = file.read() - - try: - program_data = to_base64_string(data) - response = self._api_client.program_create( - program_data=program_data, **program_metadata - ) - except RequestsApiError as ex: - if ex.status_code == 409: - raise RuntimeDuplicateProgramError( - "Program with the same name already exists." - ) from None - if ex.status_code == 403: - raise IBMNotAuthorizedError("You are not authorized to upload programs.") from None - raise IBMRuntimeError(f"Failed to create program: {ex}") from None - return response["id"] - - def _read_metadata(self, metadata: Optional[Union[Dict, str]] = None) -> Dict: - """Read metadata. - - Args: - metadata: Name of the program metadata file or metadata dictionary. - - Returns: - Return metadata. - """ - upd_metadata: dict = {} - if metadata is not None: - if isinstance(metadata, str): - with open(metadata, "r", encoding="utf-8") as file: - upd_metadata = json.load(file) - else: - upd_metadata = metadata - # TODO validate metadata format - metadata_keys = [ - "name", - "max_execution_time", - "description", - "spec", - "is_public", - ] - return {key: val for key, val in upd_metadata.items() if key in metadata_keys} - - def update_program( - self, - program_id: str, - data: str = None, - metadata: Optional[Union[Dict, str]] = None, - name: str = None, - description: str = None, - max_execution_time: int = None, - spec: Optional[Dict] = None, - ) -> None: - """Update a runtime program. - - Program metadata can be specified using the `metadata` parameter or - individual parameters, such as `name` and `description`. If the - same metadata field is specified in both places, the individual parameter - takes precedence. - - Args: - program_id: Program ID. - data: Program data or path of the file containing program data to upload. - metadata: Name of the program metadata file or metadata dictionary. - name: New program name. - description: New program description. - max_execution_time: New maximum execution time. - spec: New specifications for backend characteristics, input parameters, - interim results and final result. - - Raises: - RuntimeProgramNotFound: If the program doesn't exist. - IBMRuntimeError: If the request failed. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - if not any([data, metadata, name, description, max_execution_time, spec]): - warnings.warn( - "None of the 'data', 'metadata', 'name', 'description', " - "'max_execution_time', or 'spec' parameters is specified. " - "No update is made." - ) - return - - if data: - if "def main(" not in data: - # This is the program file - with open(data, "r", encoding="utf-8") as file: - data = file.read() - data = to_base64_string(data) - - if metadata: - metadata = self._read_metadata(metadata=metadata) - combined_metadata = self._merge_metadata( - metadata=metadata, - name=name, - description=description, - max_execution_time=max_execution_time, - spec=spec, - ) - - try: - self._api_client.program_update(program_id, program_data=data, **combined_metadata) - except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeProgramNotFound(f"Program not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to update program: {ex}") from None - - if program_id in self._programs: - program = self._programs[program_id] - program._refresh() - - def _merge_metadata(self, metadata: Optional[Dict] = None, **kwargs: Any) -> Dict: - """Merge multiple copies of metadata. - Args: - metadata: Program metadata. - **kwargs: Additional metadata fields to overwrite. - Returns: - Merged metadata. - """ - merged = {} - metadata = metadata or {} - metadata_keys = ["name", "max_execution_time", "description", "spec"] - for key in metadata_keys: - if kwargs.get(key, None) is not None: - merged[key] = kwargs[key] - elif key in metadata.keys(): - merged[key] = metadata[key] - return merged - - def delete_program(self, program_id: str) -> None: - """Delete a runtime program. - - Args: - program_id: Program ID. - - Raises: - RuntimeProgramNotFound: If the program doesn't exist. - IBMRuntimeError: If the request failed. - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - try: - self._api_client.program_delete(program_id=program_id) - except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeProgramNotFound(f"Program not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to delete program: {ex}") from None - - if program_id in self._programs: - del self._programs[program_id] - - def set_program_visibility(self, program_id: str, public: bool) -> None: - """Sets a program's visibility. - - Args: - program_id: Program ID. - public: If ``True``, make the program visible to all. - If ``False``, make the program visible to just your account. - - Raises: - RuntimeProgramNotFound: if program not found (404) - IBMRuntimeError: if update failed (401, 403) - """ - warnings.warn( - ( - "Custom programs are being deprecated as of qiskit-ibm-runtime 0.14.0 and will " - "be removed on November 27, 2023. You can instead convert your custom programs " - "to use Qiskit Runtime primitives with Quantum Serverless. Refer to the migration " - "guide for instructions: " - "https://qiskit-extensions.github.io/quantum-serverless/migration" - "/migration_from_qiskit_runtime_programs.html" - ), - DeprecationWarning, - stacklevel=2, - ) - try: - self._api_client.set_program_visibility(program_id, public) - except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeProgramNotFound(f"Program not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to set program visibility: {ex}") from None - - if program_id in self._programs: - program = self._programs[program_id] - program._is_public = public - def job(self, job_id: str) -> RuntimeJob: """Retrieve a runtime job. diff --git a/qiskit_ibm_runtime/runtime_job.py b/qiskit_ibm_runtime/runtime_job.py index 297933ef6..f448e376d 100644 --- a/qiskit_ibm_runtime/runtime_job.py +++ b/qiskit_ibm_runtime/runtime_job.py @@ -24,6 +24,7 @@ from qiskit.providers.backend import Backend from qiskit.providers.jobstatus import JobStatus, JOB_FINAL_STATES +from qiskit.providers.models import BackendProperties from qiskit.providers.job import JobV1 as Job # pylint: disable=unused-import,cyclic-import @@ -40,7 +41,7 @@ RuntimeJobTimeoutError, RuntimeJobMaxTimeoutError, ) -from .program.result_decoder import ResultDecoder +from .utils.result_decoder import ResultDecoder from .api.clients import RuntimeClient, RuntimeWebsocketClient, WebsocketClientCloseCode from .exceptions import IBMError from .api.exceptions import RequestsApiError @@ -429,6 +430,20 @@ def update_tags(self, new_tags: List[str]) -> List[str]: "the job.".format(self.job_id()) ) + def properties(self, refresh: bool = False) -> Optional[BackendProperties]: + """Return the backend properties for this job. + + Args: + refresh: If ``True``, re-query the server for the backend properties. + Otherwise, return a cached version. + + Returns: + The backend properties used for this job, at the time the job was run, + or ``None`` if properties are not available. + """ + + return self._backend.properties(refresh, self.creation_date) + def _set_status_and_error_message(self) -> None: """Fetch and set status and error message.""" if self._status not in JOB_FINAL_STATES: diff --git a/qiskit_ibm_runtime/runtime_program.py b/qiskit_ibm_runtime/runtime_program.py deleted file mode 100644 index a21063a90..000000000 --- a/qiskit_ibm_runtime/runtime_program.py +++ /dev/null @@ -1,428 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Qiskit runtime program.""" - -import logging -import re -from typing import Optional, Dict -from types import SimpleNamespace -from qiskit_ibm_runtime.exceptions import IBMInputValueError, IBMNotAuthorizedError -from .exceptions import IBMRuntimeError, RuntimeProgramNotFound -from .api.clients.runtime import RuntimeClient -from .api.exceptions import RequestsApiError - -logger = logging.getLogger(__name__) - - -class RuntimeProgram: - """Class representing program metadata. - - This class contains the metadata describing a program, such as its - name, ID, description, etc. - - You can use the :class:`~qiskit_ibm_runtime.QiskitRuntimeService` - to retrieve the metadata of a specific program or all programs. For example:: - - from qiskit_ibm_runtime import QiskitRuntimeService - - service = QiskitRuntimeService() - - # To retrieve metadata of all programs. - programs = service.programs() - - # To retrieve metadata of a single program. - program = service.program(program_id='sampler') - print(f"Program {program.name} takes parameters {program.parameters().metadata}") - """ - - def __init__( - self, - program_name: str, - program_id: str, - description: str, - parameters: Optional[Dict] = None, - return_values: Optional[Dict] = None, - interim_results: Optional[Dict] = None, - max_execution_time: int = 0, - backend_requirements: Optional[Dict] = None, - creation_date: str = "", - update_date: str = "", - is_public: Optional[bool] = False, - data: str = "", - api_client: Optional[RuntimeClient] = None, - ) -> None: - """RuntimeProgram constructor. - - Args: - program_name: Program name. - program_id: Program ID. - description: Program description. - parameters: Documentation on program parameters. - return_values: Documentation on program return values. - interim_results: Documentation on program interim results. - max_execution_time: Maximum execution time. - backend_requirements: Backend requirements. - creation_date: Program creation date. - update_date: Program last updated date. - is_public: ``True`` if program is visible to all. ``False`` if it's only visible to you. - data: Program data. - api_client: Runtime api client. - """ - self._name = program_name - self._id = program_id - self._description = description - self._max_execution_time = max_execution_time - self._backend_requirements = backend_requirements or {} - self._parameters = parameters or {} - self._return_values = return_values or {} - self._interim_results = interim_results or {} - self._creation_date = creation_date - self._update_date = update_date - self._is_public = is_public - self._data = data - self._api_client = api_client - - def __str__(self) -> str: - def _format_common(schema: Dict) -> None: - """Add title, description and property details to `formatted`.""" - if "description" in schema: - formatted.append(" " * 4 + "Description: {}".format(schema["description"])) - if "type" in schema: - formatted.append(" " * 4 + "Type: {}".format(str(schema["type"]))) - if "properties" in schema: - formatted.append(" " * 4 + "Properties:") - for property_name, property_value in schema["properties"].items(): - formatted.append(" " * 8 + "- " + property_name + ":") - for key, value in property_value.items(): - formatted.append( - " " * 12 + "{}: {}".format(camel_to_sentence_case(key), str(value)) - ) - formatted.append( - " " * 12 + "Required: " + str(property_name in schema.get("required", [])) - ) - - def _format_backend_requirements(schema: Dict) -> None: - """Add backend requirements details to `formatted`.""" - if "min_num_qubits" in schema: - formatted.append( - " " * 4 + "Minimum number of qubits: {}".format(str(schema["min_num_qubits"])) - ) - for key, value in schema.items(): - if key not in ["min_num_qubits"]: - formatted.append( - " " * 4 + "{}: {}".format(snake_to_sentence_case(key), str(value)) - ) - - def snake_to_sentence_case(snake_case_text: str) -> str: - """Converts snake_case to Sentence case""" - snake_case_words = snake_case_text.split("_") - return camel_to_sentence_case( - snake_case_words[0] + "".join(x.title() for x in snake_case_words[1:]) - ) - - def camel_to_sentence_case(camel_case_text: str) -> str: - """Converts camelCase to Sentence case""" - if camel_case_text == "": - return camel_case_text - sentence_case_text = re.sub("([A-Z])", r" \1", camel_case_text) - return sentence_case_text[:1].upper() + sentence_case_text[1:].lower() - - formatted = [ - f"{self.program_id}:", - f" Name: {self.name}", - f" Description: {self.description}", - f" Creation date: {self.creation_date}", - f" Update date: {self.update_date}", - f" Max execution time: {self.max_execution_time}", - ] - - formatted.append(" Backend requirements:") - if self._backend_requirements: - _format_backend_requirements(self._backend_requirements) - else: - formatted.append(" " * 4 + "none") - - formatted.append(" Input parameters:") - if self._parameters: - _format_common(self._parameters) - else: - formatted.append(" " * 4 + "none") - - formatted.append(" Interim results:") - if self._interim_results: - _format_common(self._interim_results) - else: - formatted.append(" " * 4 + "none") - - formatted.append(" Returns:") - if self._return_values: - _format_common(self._return_values) - else: - formatted.append(" " * 4 + "none") - return "\n".join(formatted) - - def to_dict(self) -> Dict: - """Convert program metadata to dictionary format. - - Returns: - Program metadata in dictionary format. - """ - return { - "program_id": self.program_id, - "name": self.name, - "description": self.description, - "max_execution_time": self.max_execution_time, - "backend_requirements": self.backend_requirements, - "parameters": self.parameters(), - "return_values": self.return_values, - "interim_results": self.interim_results, - "is_public": self._is_public, - } - - def parameters(self) -> "ParameterNamespace": - """Program parameter namespace. - - You can use the returned namespace to assign parameter values and pass - the namespace to :meth:`qiskit_ibm_runtime.QiskitRuntimeService.run`. - The namespace allows you to use auto-completion to find program parameters. - - Note that each call to this method returns a new namespace instance and - does not include any modification to the previous instance. - - Returns: - Program parameter namespace. - """ - return ParameterNamespace(self._parameters) - - @property - def program_id(self) -> str: - """Program ID. - - Returns: - Program ID. - """ - return self._id - - @property - def name(self) -> str: - """Program name. - - Returns: - Program name. - """ - return self._name - - @property - def description(self) -> str: - """Program description. - - Returns: - Program description. - """ - return self._description - - @property - def return_values(self) -> Dict: - """Program return value definitions. - - Returns: - Return value definitions for this program. - """ - return self._return_values - - @property - def interim_results(self) -> Dict: - """Program interim result definitions. - - Returns: - Interim result definitions for this program. - """ - return self._interim_results - - @property - def max_execution_time(self) -> int: - """Maximum execution time in seconds. - - A program execution exceeding this time will be forcibly terminated. - - Returns: - Maximum execution time. - """ - return self._max_execution_time - - @property - def backend_requirements(self) -> Dict: - """Backend requirements. - - Returns: - Backend requirements for this program. - """ - return self._backend_requirements - - @property - def creation_date(self) -> str: - """Program creation date. - - Returns: - Program creation date. - """ - return self._creation_date - - @property - def update_date(self) -> str: - """Program last updated date. - - Returns: - Program last updated date. - """ - return self._update_date - - @property - def is_public(self) -> bool: - """Whether the program is visible to all. - - Returns: - Whether the program is public. - """ - return self._is_public - - @property - def data(self) -> str: - """Program data. - - Returns: - Program data. - - Raises: - IBMNotAuthorizedError: if user is not the program author. - """ - if not self._data: - self._refresh() - if not self._data: - raise IBMNotAuthorizedError( - "Only program authors are authorized to retrieve program data" - ) - return self._data - - def _refresh(self) -> None: - """Refresh program data and metadata - - Raises: - RuntimeProgramNotFound: If the program does not exist. - IBMRuntimeError: If the request failed. - """ - try: - response = self._api_client.program_get(self._id) - except RequestsApiError as ex: - if ex.status_code == 404: - raise RuntimeProgramNotFound(f"Program not found: {ex.message}") from None - raise IBMRuntimeError(f"Failed to get program: {ex}") from None - self._backend_requirements = {} - self._parameters = {} - self._return_values = {} - self._interim_results = {} - if "spec" in response: - self._backend_requirements = response["spec"].get("backend_requirements", {}) - self._parameters = response["spec"].get("parameters", {}) - self._return_values = response["spec"].get("return_values", {}) - self._interim_results = response["spec"].get("interim_results", {}) - self._name = response["name"] - self._id = response["id"] - self._description = response.get("description", "") - self._max_execution_time = response.get("cost", 0) - self._creation_date = response.get("creation_date", "") - self._update_date = response.get("update_date", "") - self._is_public = response.get("is_public", False) - self._data = response.get("data", "") - - def __repr__(self) -> str: - return f"<{self.__class__.__name__}('{self._id}')>" - - -class ParameterNamespace(SimpleNamespace): - """A namespace for program parameters with validation. - - This class provides a namespace for program parameters with auto-completion - and validation support. - """ - - def __init__(self, parameters: Dict): - """ParameterNamespace constructor. - - Args: - parameters: The program's input parameters. - """ - super().__init__() - # Allow access to the raw program parameters dict - self.__metadata = parameters - # For localized logic, create store of parameters in dictionary - self.__program_params: dict = {} - - for parameter_name, parameter_value in parameters.get("properties", {}).items(): - # (1) Add parameters to a dict by name - setattr(self, parameter_name, None) - # (2) Store the program params for validation - self.__program_params[parameter_name] = parameter_value - - @property - def metadata(self) -> Dict: - """Returns the parameter metadata""" - return self.__metadata - - def validate(self) -> None: - """Validate program input values. - - Note: - This method only verifies that required parameters have values. It - does not fail the validation if the namespace has extraneous parameters. - - Raises: - IBMInputValueError: if validation fails - """ - - # Iterate through the user's stored inputs - for parameter_name, _ in self.__program_params.items(): - # Set invariants: User-specified parameter value (value) and if it's required (req) - value = getattr(self, parameter_name, None) - # Check there exists a program parameter of that name. - if value is None and parameter_name in self.metadata.get("required", []): - raise IBMInputValueError("Param (%s) missing required value!" % parameter_name) - - def __str__(self) -> str: - """Creates string representation of object""" - # Header - header = "| {:10.10} | {:12.12} | {:12.12} " "| {:8.8} | {:>15} |".format( - "Name", "Value", "Type", "Required", "Description" - ) - params_str = "\n".join( - [ - "| {:10.10} | {:12.12} | {:12.12}| {:8.8} | {:>15} |".format( - parameter_name, - str(getattr(self, parameter_name, "None")), - str(parameter_value.get("type", "None")), - str(parameter_name in self.metadata.get("required", [])), - str(parameter_value.get("description", "None")), - ) - for parameter_name, parameter_value in self.__program_params.items() - ] - ) - - return "ParameterNamespace (Values):\n%s\n%s\n%s" % ( - header, - "-" * len(header), - params_str, - ) - - def to_dict(self) -> Dict: - """Convert to dictionary.""" - return self.__program_params diff --git a/qiskit_ibm_runtime/session.py b/qiskit_ibm_runtime/session.py index a1a6b739c..7b9905ac7 100644 --- a/qiskit_ibm_runtime/session.py +++ b/qiskit_ibm_runtime/session.py @@ -15,13 +15,13 @@ from typing import Dict, Optional, Type, Union, Callable, Any from types import TracebackType from functools import wraps +from threading import Lock from qiskit_ibm_provider.utils.converters import hms_to_seconds from qiskit_ibm_runtime import QiskitRuntimeService from .runtime_job import RuntimeJob -from .runtime_program import ParameterNamespace -from .program.result_decoder import ResultDecoder +from .utils.result_decoder import ResultDecoder from .ibm_backend import IBMBackend from .utils.default_session import set_cm_session from .utils.deprecation import deprecate_arguments @@ -88,7 +88,7 @@ def __init__( forcibly closed. Can be specified as seconds (int) or a string like "2h 30m 40s". This value must be less than the `system imposed maximum - `_. + `_. Raises: ValueError: If an input value is invalid. @@ -116,6 +116,7 @@ def __init__( backend = backend.name self._backend = backend + self._setup_lock = Lock() self._session_id: Optional[str] = None self._active = True self._max_time = ( @@ -128,7 +129,7 @@ def __init__( def run( self, program_id: str, - inputs: Union[Dict, ParameterNamespace], + inputs: Dict, options: Optional[Dict] = None, callback: Optional[Callable] = None, result_decoder: Optional[Type[ResultDecoder]] = None, @@ -155,22 +156,28 @@ def run( options["backend"] = self._backend if not self._session_id: + # Make sure only one thread can send the session starter job. + self._setup_lock.acquire() # TODO: What happens if session max time != first job max time? # Use session max time if this is first job. options["session_time"] = self._max_time - job = self._service.run( - program_id=program_id, - options=options, - inputs=inputs, - session_id=self._session_id, - start_session=self._session_id is None, - callback=callback, - result_decoder=result_decoder, - ) - - if self._session_id is None: - self._session_id = job.job_id() + try: + job = self._service.run( + program_id=program_id, + options=options, + inputs=inputs, + session_id=self._session_id, + start_session=self._session_id is None, + callback=callback, + result_decoder=result_decoder, + ) + + if self._session_id is None: + self._session_id = job.job_id() + finally: + if self._setup_lock.locked(): + self._setup_lock.release() if self._backend is None: self._backend = job.backend().name diff --git a/qiskit_ibm_runtime/utils/estimator_result_decoder.py b/qiskit_ibm_runtime/utils/estimator_result_decoder.py index b4423d14c..9046b4950 100644 --- a/qiskit_ibm_runtime/utils/estimator_result_decoder.py +++ b/qiskit_ibm_runtime/utils/estimator_result_decoder.py @@ -17,7 +17,7 @@ from qiskit.primitives import EstimatorResult -from ..program.result_decoder import ResultDecoder +from .result_decoder import ResultDecoder class EstimatorResultDecoder(ResultDecoder): diff --git a/qiskit_ibm_runtime/program/result_decoder.py b/qiskit_ibm_runtime/utils/result_decoder.py similarity index 100% rename from qiskit_ibm_runtime/program/result_decoder.py rename to qiskit_ibm_runtime/utils/result_decoder.py diff --git a/qiskit_ibm_runtime/utils/runner_result.py b/qiskit_ibm_runtime/utils/runner_result.py index a1d8455c5..02af5b3ba 100644 --- a/qiskit_ibm_runtime/utils/runner_result.py +++ b/qiskit_ibm_runtime/utils/runner_result.py @@ -19,7 +19,7 @@ from qiskit.result.postprocess import _hex_to_bin from qiskit.exceptions import QiskitError -from ..program import ResultDecoder +from .result_decoder import ResultDecoder from .json import RuntimeDecoder diff --git a/qiskit_ibm_runtime/utils/sampler_result_decoder.py b/qiskit_ibm_runtime/utils/sampler_result_decoder.py index d84a020eb..626f45ee4 100644 --- a/qiskit_ibm_runtime/utils/sampler_result_decoder.py +++ b/qiskit_ibm_runtime/utils/sampler_result_decoder.py @@ -18,7 +18,7 @@ from qiskit.result import QuasiDistribution from qiskit.primitives import SamplerResult -from ..program.result_decoder import ResultDecoder +from .result_decoder import ResultDecoder class SamplerResultDecoder(ResultDecoder): diff --git a/releasenotes/notes/0.16/q-ctrl-instance-check-46181d51f16d18bc.yaml b/releasenotes/notes/0.16/q-ctrl-instance-check-46181d51f16d18bc.yaml new file mode 100644 index 000000000..a48934c7f --- /dev/null +++ b/releasenotes/notes/0.16/q-ctrl-instance-check-46181d51f16d18bc.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + If a cloud instance that is ``q-ctrl`` enabled is used while ``q-ctrl`` is not + passed in as the ``channel_strategy``, an error will be raised. diff --git a/releasenotes/notes/0.16/remove-custom-programs-aea76f4dd19cd481.yaml b/releasenotes/notes/0.16/remove-custom-programs-aea76f4dd19cd481.yaml new file mode 100644 index 000000000..8823cfb37 --- /dev/null +++ b/releasenotes/notes/0.16/remove-custom-programs-aea76f4dd19cd481.yaml @@ -0,0 +1,4 @@ +--- +upgrade: + - | + Methods related to using custom programs are removed. diff --git a/releasenotes/notes/0.16/thread-safe-sessions-d08c8367e98447e7.yaml b/releasenotes/notes/0.16/thread-safe-sessions-d08c8367e98447e7.yaml new file mode 100644 index 000000000..4880e2d53 --- /dev/null +++ b/releasenotes/notes/0.16/thread-safe-sessions-d08c8367e98447e7.yaml @@ -0,0 +1,6 @@ +--- +prelude: > + Sessions are now thread-safe and allow for multiple concurrent interactive + experiments. +features: + - Sessions are now thread-safe. diff --git a/releasenotes/notes/job-properties-2b5c2f66c50d7d2d.yaml b/releasenotes/notes/job-properties-2b5c2f66c50d7d2d.yaml new file mode 100644 index 000000000..cd9bfcad4 --- /dev/null +++ b/releasenotes/notes/job-properties-2b5c2f66c50d7d2d.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Added a new method :meth:`~qiskit_ibm_runtime.RuntimeJob.properties` which returns the + backend properties of the job at the time the job was run. + diff --git a/requirements-dev.txt b/requirements-dev.txt index 8387babf6..e7779c798 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -19,11 +19,7 @@ ddt>=1.2.0,!=1.4.0,!=1.4.3 # Documentation nbsphinx Sphinx>=6 -sphinx-tabs>=1.1.11 sphinx-automodapi sphinx-autodoc-typehints<=1.19.2 -sphinx-design>=0.4.0 -sphinx-intl jupyter-sphinx reno>=2.11.0 -qiskit-sphinx-theme~=1.16.0 diff --git a/test/ibm_test_case.py b/test/ibm_test_case.py index f58158a22..c724ae113 100644 --- a/test/ibm_test_case.py +++ b/test/ibm_test_case.py @@ -13,7 +13,6 @@ """Custom TestCase for IBM Provider.""" import os -import copy import logging import inspect import warnings @@ -29,7 +28,6 @@ from .utils import setup_test_logging from .decorators import IntegrationTestDependencies, integration_test_setup -from .templates import RUNTIME_PROGRAM, RUNTIME_PROGRAM_METADATA, PROGRAM_PREFIX class IBMTestCase(BaseQiskitTestCase): @@ -107,25 +105,6 @@ def tearDown(self) -> None: with suppress(Exception): service.delete_job(job.job_id()) - def _upload_program( - self, - service: QiskitRuntimeService, - name: str = None, - max_execution_time: int = 300, - data: str = None, - is_public: bool = False, - ) -> str: - """Upload a new program.""" - name = name or PROGRAM_PREFIX - data = data or RUNTIME_PROGRAM - metadata = copy.deepcopy(RUNTIME_PROGRAM_METADATA) - metadata["name"] = name - metadata["max_execution_time"] = max_execution_time - metadata["is_public"] = is_public - program_id = service.upload_program(data=data, metadata=metadata) - self.to_delete[service.channel].append(program_id) - return program_id - class IBMIntegrationJobTestCase(IBMIntegrationTestCase): """Custom integration test case for job-related tests.""" diff --git a/test/integration/test_job.py b/test/integration/test_job.py index 444d420f2..697d8aeff 100644 --- a/test/integration/test_job.py +++ b/test/integration/test_job.py @@ -25,7 +25,6 @@ RuntimeJobFailureError, RuntimeInvalidStateError, RuntimeJobNotFound, - RuntimeJobMaxTimeoutError, ) from ..ibm_test_case import IBMIntegrationJobTestCase from ..decorators import run_integration_test, production_only, quantum_only @@ -96,40 +95,6 @@ def test_run_program_failed(self, service): job.result() self.assertIn("KeyError", str(err_cm.exception)) - @unittest.skip("Custom programs not currently supported.") - @run_integration_test - def test_run_program_failed_ran_too_long(self, service): - """Test a program that failed since it ran longer than maximum execution time.""" - max_execution_time = 60 - inputs = {"iterations": 1, "sleep_per_iteration": 61} - program_id = self._upload_program(service, max_execution_time=max_execution_time) - job = self._run_program(service, program_id=program_id, inputs=inputs) - - job.wait_for_final_state() - job_result_raw = service._api_client.job_results(job.job_id()) - self.assertEqual(JobStatus.ERROR, job.status()) - self.assertIn( - API_TO_JOB_ERROR_MESSAGE["CANCELLED - RAN TOO LONG"].format( - job.job_id(), job_result_raw - ), - job.error_message(), - ) - with self.assertRaises(RuntimeJobMaxTimeoutError): - job.result() - - @unittest.skip("Custom programs not currently supported.") - @run_integration_test - def test_run_program_override_max_execution_time(self, service): - """Test that the program max execution time is overridden.""" - program_max_execution_time = 400 - job_max_execution_time = 350 - program_id = self._upload_program(service, max_execution_time=program_max_execution_time) - job = self._run_program( - service, program_id=program_id, max_execution_time=job_max_execution_time - ) - job.wait_for_final_state() - self.assertEqual(job._api_client.job_get(job.job_id())["cost"], job_max_execution_time) - @run_integration_test @production_only def test_cancel_job_queued(self, service): diff --git a/test/integration/test_program.py b/test/integration/test_program.py deleted file mode 100644 index 380cd7c6b..000000000 --- a/test/integration/test_program.py +++ /dev/null @@ -1,220 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Tests for runtime service.""" - -import os -import tempfile -import unittest - -from qiskit_ibm_runtime.exceptions import IBMNotAuthorizedError -from qiskit_ibm_runtime.exceptions import ( - RuntimeProgramNotFound, -) -from qiskit_ibm_runtime.runtime_program import RuntimeProgram -from ..ibm_test_case import IBMIntegrationTestCase -from ..decorators import run_integration_test, quantum_only -from ..templates import RUNTIME_PROGRAM, PROGRAM_PREFIX - - -class TestIntegrationProgram(IBMIntegrationTestCase): - """Integration tests for runtime modules.""" - - @run_integration_test - @quantum_only - def test_list_programs(self, service): - """Test listing programs.""" - program_id = self._upload_program(service) - programs = service.programs() - self.assertTrue(programs) - found = False - for prog in programs: - self._validate_program(prog) - if prog.program_id == program_id: - found = True - self.assertTrue(found, f"Program {program_id} not found!") - - @run_integration_test - @quantum_only - def test_list_programs_with_limit_skip(self, service): - """Test listing programs with limit and skip.""" - for _ in range(4): - self._upload_program(service) - programs = service.programs(limit=3, refresh=True) - all_ids = [prog.program_id for prog in programs] - self.assertEqual(len(all_ids), 3, f"Retrieved programs: {all_ids}") - programs = service.programs(limit=2, skip=1) - some_ids = [prog.program_id for prog in programs] - self.assertEqual(len(some_ids), 2, f"Retrieved programs: {some_ids}") - self.assertNotIn(all_ids[0], some_ids) - self.assertIn(all_ids[1], some_ids) - self.assertIn(all_ids[2], some_ids) - - @run_integration_test - @quantum_only - def test_list_program(self, service): - """Test listing a single program.""" - program_id = self._upload_program(service) - program = service.program(program_id) - self.assertEqual(program_id, program.program_id) - self._validate_program(program) - - @run_integration_test - @quantum_only - def test_retrieve_program_data(self, service): - """Test retrieving program data""" - program_id = self._upload_program(service) - program = service.program(program_id) - self.assertEqual(RUNTIME_PROGRAM, program.data) - self._validate_program(program) - - @run_integration_test - def test_retrieve_unauthorized_program_data(self, service): - """Test retrieving program data when user is not the program author""" - programs = service.programs() - not_mine = None - for prog in programs: - if prog.is_public: - not_mine = prog - break - if not_mine is None: - self.skipTest("Cannot find a program that's not mine!") - with self.assertRaises(IBMNotAuthorizedError): - return not_mine.data - - @run_integration_test - @quantum_only - def test_upload_program(self, service): - """Test uploading a program.""" - max_execution_time = 3000 - program_id = self._upload_program(service, max_execution_time=max_execution_time) - self.assertTrue(program_id) - program = service.program(program_id) - self.assertTrue(program) - self.assertEqual(max_execution_time, program.max_execution_time) - - @run_integration_test - @quantum_only - def test_upload_program_file(self, service): - """Test uploading a program using a file.""" - temp_fp = tempfile.NamedTemporaryFile(mode="w", delete=False) - self.addCleanup(os.remove, temp_fp.name) - temp_fp.write(RUNTIME_PROGRAM) - temp_fp.close() - - program_id = self._upload_program(service, data=temp_fp.name) - self.assertTrue(program_id) - program = service.program(program_id) - self.assertTrue(program) - - @unittest.skip("Skip until authorized to upload public on cloud") - @unittest.skipIf( - not os.environ.get("QISKIT_IBM_USE_STAGING_CREDENTIALS", ""), - "Only runs on staging", - ) - @run_integration_test - def test_upload_public_program(self, service): - """Test uploading a public program.""" - max_execution_time = 3000 - is_public = True - program_id = self._upload_program( - service, max_execution_time=max_execution_time, is_public=is_public - ) - self.assertTrue(program_id) - program = service.program(program_id) - self.assertTrue(program) - self.assertEqual(max_execution_time, program.max_execution_time) - self.assertEqual(program.is_public, is_public) - - @unittest.skip("Skip until authorized to upload public on cloud") - @unittest.skipIf( - not os.environ.get("QISKIT_IBM_USE_STAGING_CREDENTIALS", ""), - "Only runs on staging", - ) - @run_integration_test - def test_set_visibility(self, service): - """Test setting the visibility of a program.""" - program_id = self._upload_program(service) - # Get the initial visibility - prog: RuntimeProgram = service.program(program_id) - start_vis = prog.is_public - # Flip the original value - service.set_program_visibility(program_id, not start_vis) - # Get the new visibility - prog: RuntimeProgram = service.program(program_id, refresh=True) - end_vis = prog.is_public - # Verify changed - self.assertNotEqual(start_vis, end_vis) - - @run_integration_test - @quantum_only - def test_delete_program(self, service): - """Test deleting program.""" - program_id = self._upload_program(service) - service.delete_program(program_id) - with self.assertRaises(RuntimeProgramNotFound): - service.program(program_id, refresh=True) - - @run_integration_test - @quantum_only - def test_double_delete_program(self, service): - """Test deleting a deleted program.""" - program_id = self._upload_program(service) - service.delete_program(program_id) - with self.assertRaises(RuntimeProgramNotFound): - service.delete_program(program_id) - - @run_integration_test - @quantum_only - def test_update_program_data(self, service): - """Test updating program data.""" - program_v1 = """ -def main(backend, user_messenger, **kwargs): - return "version 1" - """ - program_v2 = """ -def main(backend, user_messenger, **kwargs): - return "version 2" - """ - program_id = self._upload_program(service, data=program_v1) - self.assertEqual(program_v1, service.program(program_id).data) - service.update_program(program_id=program_id, data=program_v2) - self.assertEqual(program_v2, service.program(program_id).data) - - @run_integration_test - @quantum_only - def test_update_program_metadata(self, service): - """Test updating program metadata.""" - program_id = self._upload_program(service) - original = service.program(program_id) - new_metadata = { - "name": PROGRAM_PREFIX, - "description": "test_update_program_metadata", - "max_execution_time": original.max_execution_time + 100, - "spec": {"return_values": {"type": "object", "description": "Some return value"}}, - } - service.update_program(program_id=program_id, metadata=new_metadata) - updated = service.program(program_id, refresh=True) - self.assertEqual(new_metadata["name"], updated.name) - self.assertEqual(new_metadata["description"], updated.description) - self.assertEqual(new_metadata["max_execution_time"], updated.max_execution_time) - self.assertEqual(new_metadata["spec"]["return_values"], updated.return_values) - - def _validate_program(self, program): - """Validate a program.""" - self.assertTrue(program) - self.assertTrue(program.name) - self.assertTrue(program.program_id) - self.assertTrue(program.description) - self.assertTrue(program.max_execution_time) - self.assertTrue(program.creation_date) - self.assertTrue(program.update_date) diff --git a/test/integration/test_proxies.py b/test/integration/test_proxies.py index 6f63e26f7..a6c6c0ed5 100644 --- a/test/integration/test_proxies.py +++ b/test/integration/test_proxies.py @@ -64,7 +64,7 @@ def test_proxies_cloud_runtime_client(self, dependencies: IntegrationTestDepende params = dependencies.service._client_params params.proxies = ProxyConfiguration(urls=VALID_PROXIES) client = RuntimeClient(params) - client.list_programs(limit=1) + client.jobs_get(limit=1) api_line = pproxy_desired_access_log_line(params.url) self.proxy_process.terminate() # kill to be able of reading the output proxy_output = self.proxy_process.stdout.read().decode("utf-8") @@ -81,7 +81,7 @@ def test_proxies_ibm_quantum_runtime_client( url=dependencies.url, proxies={"urls": VALID_PROXIES}, ) - service.programs(limit=1) + service.jobs(limit=1) auth_line = pproxy_desired_access_log_line(dependencies.url) api_line = list(service._hgps.values())[0]._runtime_client._session.base_url @@ -162,7 +162,7 @@ def test_invalid_proxy_port_runtime_client( ) with self.assertRaises(RuntimeRequestsApiError) as context_manager: client = RuntimeClient(params) - client.list_programs(limit=1) + client.jobs_get(limit=1) self.assertIsInstance(context_manager.exception.__cause__, ProxyError) @integration_test_setup(supported_channel=["ibm_quantum"], init_service=False) @@ -203,7 +203,7 @@ def test_invalid_proxy_address_runtime_client( ) with self.assertRaises(RuntimeRequestsApiError) as context_manager: client = RuntimeClient(params) - client.list_programs(limit=1) + client.jobs_get(limit=1) self.assertIsInstance(context_manager.exception.__cause__, ProxyError) diff --git a/test/program.py b/test/program.py index 25ee2a8f8..dfa2f1fc2 100644 --- a/test/program.py +++ b/test/program.py @@ -12,57 +12,7 @@ """Utility functions for runtime testing.""" -import uuid -import copy from datetime import datetime, timezone -from qiskit_ibm_runtime import QiskitRuntimeService - - -DEFAULT_DATA = "def main() {}" -DEFAULT_METADATA = { - "name": "qiskit-test", - "description": "Test program.", - "max_execution_time": 300, - "spec": { - "backend_requirements": {"min_num_qubits": 5}, - "parameters": { - "properties": { - "param1": { - "description": "Desc 1", - "type": "string", - "enum": ["a", "b", "c"], - }, - "param2": {"description": "Desc 2", "type": "integer", "min": 0}, - }, - "required": ["param1"], - }, - "return_values": { - "type": "object", - "description": "Return values", - "properties": {"ret_val": {"description": "Some return value.", "type": "string"}}, - }, - "interim_results": { - "properties": {"int_res": {"description": "Some interim result", "type": "string"}} - }, - }, -} - - -def upload_program( - service: QiskitRuntimeService, - name: str = None, - max_execution_time: int = 300, - is_public: bool = False, -) -> str: - """Upload a new program.""" - name = name or uuid.uuid4().hex - data = DEFAULT_DATA - metadata = copy.deepcopy(DEFAULT_METADATA) - metadata.update(name=name) - metadata.update(is_public=is_public) - metadata.update(max_execution_time=max_execution_time) - program_id = service.upload_program(data=data, metadata=metadata) - return program_id def run_program( @@ -95,8 +45,8 @@ def run_program( service._api_client.set_final_status(final_status) elif job_classes: service._api_client.set_job_classes(job_classes) - if program_id is None: - program_id = upload_program(service) + if not program_id: + program_id = "sampler" job = service.run( program_id=program_id, options=options, diff --git a/test/serialization.py b/test/serialization.py index 372cea5dd..f7f38c683 100644 --- a/test/serialization.py +++ b/test/serialization.py @@ -14,7 +14,7 @@ import json -from qiskit_ibm_runtime.program import ResultDecoder +from qiskit_ibm_runtime.utils.result_decoder import ResultDecoder def get_complex_types(): diff --git a/test/templates.py b/test/templates.py deleted file mode 100644 index a30b38bc4..000000000 --- a/test/templates.py +++ /dev/null @@ -1,52 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2021. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -"""Templates for use with unit tests.""" - -RUNTIME_PROGRAM = """ -import random -import time -import warnings -import logging - -from qiskit import transpile -from qiskit.circuit.random import random_circuit - -logger = logging.getLogger("qiskit-test") - -def prepare_circuits(backend): - circuit = random_circuit(num_qubits=5, depth=4, measure=True, - seed=random.randint(0, 1000)) - return transpile(circuit, backend) - -def main(backend, user_messenger, **kwargs): - iterations = kwargs['iterations'] - sleep_per_iteration = kwargs.pop('sleep_per_iteration', 0) - interim_results = kwargs.pop('interim_results', {}) - final_result = kwargs.pop("final_result", {}) - for it in range(iterations): - time.sleep(sleep_per_iteration) - qc = prepare_circuits(backend) - user_messenger.publish({"iteration": it, "interim_results": interim_results}) - backend.run(qc).result() - - user_messenger.publish(final_result, final=True) - print("this is a stdout message") - warnings.warn("this is a stderr message") - logger.info("this is an info log") - """ - -RUNTIME_PROGRAM_METADATA = { - "max_execution_time": 600, - "description": "Qiskit test program", -} -PROGRAM_PREFIX = "qiskit-test" diff --git a/test/unit/mock/fake_runtime_client.py b/test/unit/mock/fake_runtime_client.py index 1f2c16fb8..fb27ffefc 100644 --- a/test/unit/mock/fake_runtime_client.py +++ b/test/unit/mock/fake_runtime_client.py @@ -119,7 +119,7 @@ def __init__( self._backend_name = backend_name self._params = params self._image = image - self._interim_results = json.dumps("foo") + self._interim_results = json.dumps({"quasi_dists": [{0: 0.5, 3: 0.5}], "metadata": []}) self._job_tags = job_tags self.log_level = log_level self._session_id = session_id @@ -130,7 +130,7 @@ def __init__( self._future = self._executor.submit(self._auto_progress) self._result = None elif final_status == "COMPLETED": - self._result = json.dumps("foo") + self._result = json.dumps({"quasi_dists": [{0: 0.5, 3: 0.5}], "metadata": []}) self._final_status = final_status self._channel_strategy = channel_strategy @@ -141,7 +141,7 @@ def _auto_progress(self): self._status = status if self._status == "COMPLETED": - self._result = json.dumps("foo") + self._result = json.dumps({"quasi_dists": [{0: 0.5, 3: 0.5}], "metadata": []}) def to_dict(self): """Convert to dictionary format.""" @@ -246,7 +246,7 @@ def _auto_progress(self): self._status = "COMPLETED" if self._status == "COMPLETED": - self._result = json.dumps("foo") + self._result = json.dumps({"quasi_dists": [{0: 0.5, 3: 0.5}], "metadata": []}) class BaseFakeRuntimeClient: @@ -285,77 +285,14 @@ def set_job_classes(self, classes): classes = [classes] self._job_classes = classes + def is_qctrl_enabled(self): + """Return whether or not channel_strategy q-ctrl is enabled.""" + return False + def set_final_status(self, final_status): """Set job status to passed in final status instantly.""" self._final_status = final_status - def list_programs(self, limit, skip): - """List all programs.""" - programs = [] - for prog in self._programs.values(): - programs.append(prog.to_dict()) - return {"programs": programs[skip : limit + skip], "count": len(self._programs)} - - def program_create( - self, - program_data, - name, - description, - max_execution_time, - spec=None, - is_public=False, - ): - """Create a program.""" - program_id = name - if program_id in self._programs: - raise RequestsApiError("Program already exists.", status_code=409) - backend_requirements = spec.get("backend_requirements", None) - parameters = spec.get("parameters", None) - return_values = spec.get("return_values", None) - interim_results = spec.get("interim_results", None) - self._programs[program_id] = BaseFakeProgram( - program_id=program_id, - name=name, - data=program_data, - cost=max_execution_time, - description=description, - backend_requirements=backend_requirements, - parameters=parameters, - return_values=return_values, - interim_results=interim_results, - is_public=is_public, - ) - return {"id": program_id} - - def program_update( - self, - program_id: str, - program_data: str = None, - name: str = None, - description: str = None, - max_execution_time: int = None, - spec: Optional[Dict] = None, - ) -> None: - """Update a program.""" - program = self._get_program(program_id) - program._data = program_data or program._data - program._name = name or program._name - program._description = description or program._description - program._cost = max_execution_time or program._cost - if spec: - program._backend_requirements = ( - spec.get("backend_requirements") or program._backend_requirements - ) - program._parameters = spec.get("parameters") or program._parameters - program._return_values = spec.get("return_values") or program._return_values - program._interim_results = spec.get("interim_results") or program._interim_results - - def program_get(self, program_id: str) -> Dict[str, Any]: - """Return a specific program.""" - if program_id not in self._programs: - raise RequestsApiError("Program not found", status_code=404) - return self._programs[program_id].to_dict(include_data=True) - def program_run( self, program_id: str, @@ -372,7 +309,6 @@ def program_run( channel_strategy: Optional[str] = None, ) -> Dict[str, Any]: """Run the specified program.""" - _ = self._get_program(program_id) job_id = uuid.uuid4().hex job_cls = self._job_classes.pop(0) if len(self._job_classes) > 0 else BaseFakeRuntimeJob if hgp: @@ -408,11 +344,6 @@ def program_run( self._jobs[job_id] = job return {"id": job_id, "backend": backend_name} - def program_delete(self, program_id: str) -> None: - """Delete the specified program.""" - self._get_program(program_id) - del self._programs[program_id] - def job_get(self, job_id: str, exclude_params: bool = None) -> Any: """Get the specific job.""" return self._get_job(job_id, exclude_params).to_dict() @@ -468,17 +399,6 @@ def jobs_get( return {"jobs": [job.to_dict() for job in jobs], "count": count} - def set_program_visibility(self, program_id: str, public: bool) -> None: - """Sets a program's visibility. - - Args: - program_id: Program ID. - public: If ``True``, make the program visible to all. - If ``False``, make the program visible to just your account. - """ - program = self._get_program(program_id) - program._is_public = public - def job_results(self, job_id): """Get the results of a program job.""" return self._get_job(job_id).result() @@ -503,12 +423,6 @@ def wait_for_final_state(self, job_id): while status not in final_states: status = self._get_job(job_id).status() - def _get_program(self, program_id): - """Get program.""" - if program_id not in self._programs: - raise RequestsApiError("Program not found", status_code=404) - return self._programs[program_id] - # pylint: disable=unused-argument def _get_job(self, job_id: str, exclude_params: bool = None) -> Any: """Get job.""" diff --git a/test/unit/test_job_retrieval.py b/test/unit/test_job_retrieval.py index 4014827df..72e186cf3 100644 --- a/test/unit/test_job_retrieval.py +++ b/test/unit/test_job_retrieval.py @@ -16,7 +16,7 @@ from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase from ..decorators import run_quantum_and_cloud_fake -from ..program import run_program, upload_program +from ..program import run_program from ..utils import mock_wait_for_final_state @@ -31,7 +31,7 @@ def setUp(self): @run_quantum_and_cloud_fake def test_retrieve_job(self, service): """Test retrieving a job.""" - program_id = upload_program(service) + program_id = "sampler" params = {"param1": "foo"} job = run_program(service=service, program_id=program_id, inputs=params) rjob = service.job(job.job_id()) @@ -41,7 +41,7 @@ def test_retrieve_job(self, service): @run_quantum_and_cloud_fake def test_jobs_no_limit(self, service): """Test retrieving jobs without limit.""" - program_id = upload_program(service) + program_id = "sampler" jobs = [] for _ in range(25): @@ -52,7 +52,7 @@ def test_jobs_no_limit(self, service): @run_quantum_and_cloud_fake def test_jobs_limit(self, service): """Test retrieving jobs with limit.""" - program_id = upload_program(service) + program_id = "sampler" jobs = [] job_count = 25 @@ -68,7 +68,7 @@ def test_jobs_limit(self, service): @run_quantum_and_cloud_fake def test_jobs_skip(self, service): """Test retrieving jobs with skip.""" - program_id = upload_program(service) + program_id = "sampler" jobs = [] for _ in range(5): @@ -79,7 +79,7 @@ def test_jobs_skip(self, service): def test_jobs_skip_limit(self): """Test retrieving jobs with skip and limit.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" jobs = [] for _ in range(10): @@ -90,7 +90,7 @@ def test_jobs_skip_limit(self): @run_quantum_and_cloud_fake def test_jobs_pending(self, service): """Test retrieving pending jobs (QUEUED, RUNNING).""" - program_id = upload_program(service) + program_id = "sampler" _, pending_jobs_count, _ = self._populate_jobs_with_all_statuses( service, program_id=program_id @@ -101,7 +101,7 @@ def test_jobs_pending(self, service): def test_jobs_limit_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with limit.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" self._populate_jobs_with_all_statuses(service, program_id=program_id) limit = 4 @@ -111,7 +111,7 @@ def test_jobs_limit_pending(self): def test_jobs_skip_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with skip.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" _, pending_jobs_count, _ = self._populate_jobs_with_all_statuses( service, program_id=program_id @@ -123,7 +123,7 @@ def test_jobs_skip_pending(self): def test_jobs_limit_skip_pending(self): """Test retrieving pending jobs (QUEUED, RUNNING) with limit and skip.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" self._populate_jobs_with_all_statuses(service, program_id=program_id) limit = 2 @@ -134,7 +134,7 @@ def test_jobs_limit_skip_pending(self): def test_jobs_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED).""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" _, _, returned_jobs_count = self._populate_jobs_with_all_statuses( service, program_id=program_id @@ -145,7 +145,7 @@ def test_jobs_returned(self): def test_jobs_limit_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with limit.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" self._populate_jobs_with_all_statuses(service, program_id=program_id) limit = 6 @@ -155,7 +155,7 @@ def test_jobs_limit_returned(self): def test_jobs_skip_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with skip.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" _, _, returned_jobs_count = self._populate_jobs_with_all_statuses( service, program_id=program_id @@ -167,7 +167,7 @@ def test_jobs_skip_returned(self): def test_jobs_limit_skip_returned(self): """Test retrieving returned jobs (COMPLETED, FAILED, CANCELLED) with limit and skip.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" self._populate_jobs_with_all_statuses(service, program_id=program_id) limit = 6 @@ -175,25 +175,10 @@ def test_jobs_limit_skip_returned(self): rjobs = service.jobs(limit=limit, skip=skip, pending=False) self.assertEqual(limit, len(rjobs)) - @run_quantum_and_cloud_fake - def test_jobs_filter_by_program_id(self, service): - """Test retrieving jobs by Program ID.""" - program_id = upload_program(service) - program_id_1 = upload_program(service) - - job = run_program(service=service, program_id=program_id) - job_1 = run_program(service=service, program_id=program_id_1) - with mock_wait_for_final_state(service, job): - job.wait_for_final_state() - job_1.wait_for_final_state() - rjobs = service.jobs(program_id=program_id) - self.assertEqual(program_id, rjobs[0].program_id) - self.assertEqual(1, len(rjobs)) - def test_jobs_filter_by_instance(self): """Test retrieving jobs by instance.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" instance = FakeRuntimeService.DEFAULT_HGPS[1] job = run_program(service=service, program_id=program_id, instance=instance) @@ -209,7 +194,7 @@ def test_jobs_filter_by_instance(self): def test_jobs_filter_by_job_tags(self): """Test retrieving jobs by job tags.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" job_tags = ["test_tag"] job = run_program(service=service, program_id=program_id, job_tags=job_tags) @@ -224,7 +209,7 @@ def test_jobs_filter_by_job_tags(self): def test_jobs_filter_by_session_id(self): """Test retrieving jobs by session id.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" job = run_program(service=service, program_id=program_id) job_2 = run_program(service=service, program_id=program_id, session_id=job.job_id()) @@ -256,7 +241,7 @@ def test_jobs_filter_by_date(self): def test_jobs_sort_by_date(self): """Test retrieving jobs sorted by the date.""" service = self._ibm_quantum_service - program_id = upload_program(service) + program_id = "sampler" job = run_program(service=service, program_id=program_id) job_2 = run_program(service=service, program_id=program_id) @@ -284,7 +269,7 @@ def test_different_hgps(self): token="some_token", instance=FakeRuntimeService.DEFAULT_HGPS[0], ) - program_id = upload_program(service) + program_id = "sampler" # Run with hgp1 backend. backend_name = FakeRuntimeService.DEFAULT_UNIQUE_BACKEND_PREFIX + "1" diff --git a/test/unit/test_jobs.py b/test/unit/test_jobs.py index af28cadfb..9ad78e8a7 100644 --- a/test/unit/test_jobs.py +++ b/test/unit/test_jobs.py @@ -25,7 +25,6 @@ RuntimeJobFailureError, RuntimeJobNotFound, RuntimeJobMaxTimeoutError, - RuntimeProgramNotFound, IBMInputValueError, RuntimeInvalidStateError, ) @@ -33,13 +32,11 @@ FailedRuntimeJob, FailedRanTooLongRuntimeJob, CancelableRuntimeJob, - CustomResultRuntimeJob, ) from .mock.fake_runtime_service import FakeRuntimeService from ..ibm_test_case import IBMTestCase from ..decorators import run_quantum_and_cloud_fake -from ..program import run_program, upload_program -from ..serialization import get_complex_types +from ..program import run_program from ..utils import mock_wait_for_final_state @@ -60,12 +57,6 @@ def test_run_program(self, service): self.assertEqual(job.status(), JobStatus.DONE) self.assertTrue(job.result()) - @run_quantum_and_cloud_fake - def test_run_phantom_program(self, service): - """Test running a phantom program.""" - with self.assertRaises(RuntimeProgramNotFound): - _ = run_program(service=service, program_id="phantom_program") - @run_quantum_and_cloud_fake def test_run_program_phantom_backend(self, service): """Test running on a phantom backend.""" @@ -182,14 +173,6 @@ def test_run_program_failed_ran_too_long(self, service): with self.assertRaises(RuntimeJobMaxTimeoutError): job.result() - @run_quantum_and_cloud_fake - def test_program_params_namespace(self, service): - """Test running a program using parameter namespace.""" - program_id = upload_program(service) - params = service.program(program_id).parameters() - params.param1 = "Hello World" - run_program(service, program_id, inputs=params) - @run_quantum_and_cloud_fake def test_cancel_job(self, service): """Test canceling a job.""" @@ -233,13 +216,6 @@ def test_job_inputs(self, service): job = run_program(service, inputs=inputs) self.assertEqual(inputs, job.inputs) - @run_quantum_and_cloud_fake - def test_job_program_id(self, service): - """Test job program ID.""" - program_id = upload_program(service) - job = run_program(service, program_id=program_id) - self.assertEqual(program_id, job.program_id) - @run_quantum_and_cloud_fake def test_wait_for_final_state(self, service): """Test wait for final state.""" @@ -248,18 +224,6 @@ def test_wait_for_final_state(self, service): job.wait_for_final_state() self.assertEqual(JobStatus.DONE, job.status()) - @run_quantum_and_cloud_fake - def test_get_result_twice(self, service): - """Test getting results multiple times.""" - custom_result = get_complex_types() - job_cls = CustomResultRuntimeJob - job_cls.custom_result = custom_result - - job = run_program(service=service, job_classes=job_cls) - with mock_wait_for_final_state(service, job): - _ = job.result() - _ = job.result() - @run_quantum_and_cloud_fake def test_delete_job(self, service): """Test deleting a job.""" @@ -281,9 +245,6 @@ def test_download_external_job_result(self, service): request_mock.get.return_value = mock_response with mock_wait_for_final_state(service, job): job.wait_for_final_state() - job._api_client.job_results = MagicMock( - return_value='{"url": "https://external-url.com/"}' - ) result = job.result() - self.assertEqual(result, "content-from-external-url") + self.assertTrue(result) diff --git a/test/unit/test_session.py b/test/unit/test_session.py index f796f4b40..ee554909f 100644 --- a/test/unit/test_session.py +++ b/test/unit/test_session.py @@ -12,7 +12,11 @@ """Tests for Session classession.""" -from unittest.mock import MagicMock, patch +import sys +import time +from concurrent.futures import ThreadPoolExecutor, wait + +from unittest.mock import MagicMock, Mock, patch from qiskit_ibm_runtime import Session from qiskit_ibm_runtime.ibm_backend import IBMBackend @@ -113,6 +117,29 @@ def test_run(self): self.assertEqual(session.session_id, job.job_id()) self.assertEqual(session.backend(), backend) + def test_run_is_thread_safe(self): + """Test the session sends a session starter job once, and only once.""" + service = MagicMock() + api = MagicMock() + service._api_client = api + + def _wait_a_bit(*args, **kwargs): + # pylint: disable=unused-argument + switchinterval = sys.getswitchinterval() + time.sleep(switchinterval * 2) + return MagicMock() + + service.run = Mock(side_effect=_wait_a_bit) + + session = Session(service=service, backend="ibm_gotham") + with ThreadPoolExecutor(max_workers=2) as executor: + results = list(map(lambda _: executor.submit(session.run, "", {}), range(5))) + wait(results) + + calls = service.run.call_args_list + session_starters = list(filter(lambda c: c.kwargs["start_session"] is True, calls)) + self.assertEqual(len(session_starters), 1) + def test_close_without_run(self): """Test closing without run.""" service = MagicMock() diff --git a/tools/deploy_translatable_strings.sh b/tools/deploy_translatable_strings.sh deleted file mode 100755 index 1ec9fc496..000000000 --- a/tools/deploy_translatable_strings.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -# This code is part of Qiskit. -# -# (C) Copyright IBM 2018, 2023. -# -# This code is licensed under the Apache License, Version 2.0. You may -# obtain a copy of this license in the LICENSE.txt file in the root directory -# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. -# -# Any modifications or derivative works of this code must retain this -# copyright notice, and modified files need to carry a notice indicating -# that they have been altered from the originals. - -# Script for pushing the translatable strings to qiskit-translations repo. - -# Non-travis variables used by this script. -SOURCE_REPOSITORY="git@github.com:Qiskit/qiskit-ibm-runtime.git" -SOURCE_DIR=`pwd` -SOURCE_LANG='en' - -TARGET_REPOSITORY="git@github.com:qiskit-community/qiskit-translations.git" -TARGET_BRANCH_PO="main" - -DOC_DIR_PO="docs/locale/" - -echo "show current dir: " -pwd - -pushd docs - -# Extract document's translatable messages into pot files -# https://sphinx-intl.readthedocs.io/en/master/quickstart.html -echo "Extract document's translatable messages into pot files and generate po files" -tox -egettext -- -D language=$SOURCE_LANG - -echo "Setup ssh keys" -pwd -set -e -# Add qiskit-translations push key to ssh-agent -openssl enc -aes-256-cbc -d -in ../tools/github_poBranch_update_key.enc -out github_poBranch_deploy_key -K $encrypted_deploy_po_branch_key -iv $encrypted_deploy_po_branch_iv -chmod 600 github_poBranch_deploy_key -eval $(ssh-agent -s) -ssh-add github_poBranch_deploy_key - -# Clone to the working repository for .po and pot files -popd -pwd -echo "git clone for working repo" -git clone --depth 1 $TARGET_REPOSITORY temp --single-branch --branch $TARGET_BRANCH_PO -pushd temp - -git config user.name "Qiskit (IBM Runtime) Autodeploy" -git config user.email "qiskit@qiskit.org" - -echo "git rm -rf for the translation po files" -git rm -rf --ignore-unmatch ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/*.po \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/api \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/apidocs \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/stubs \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/release_notes.po \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/theme \ - qiskit-ibm-runtime/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/_* - -# Remove api/ and apidoc/ to avoid confusion while translating -rm -rf $SOURCE_DIR/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/api/ \ - $SOURCE_DIR/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/apidocs \ - $SOURCE_DIR/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/stubs \ - $SOURCE_DIR/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/release_notes.po \ - $SOURCE_DIR/$DOC_DIR_PO/$SOURCE_LANG/LC_MESSAGES/theme/ - -# Copy the new rendered files and add them to the commit. -echo "copy directory" -cp -r $SOURCE_DIR/$DOC_DIR_PO/ qiskit-ibm-runtime/docs -cp $SOURCE_DIR/setup.py qiskit-ibm-runtime/. -cp $SOURCE_DIR/requirements-dev.txt qiskit-ibm-runtime/. -cp $SOURCE_DIR/requirements.txt qiskit-ibm-runtime/. -cp $SOURCE_DIR/qiskit_ibm_runtime/VERSION.txt qiskit-ibm-runtime/qiskit_ibm_runtime/. - -# git checkout translationDocs -echo "add to po files to target dir" -git add qiskit-ibm-runtime/ - -# Commit and push the changes. -git commit -m "[Qiskit IBM Runtime] Automated documentation update to add .po files" -m "skip ci" -m "Commit: $GITHUB_SHA" -m "Github Actions Run: https://github.com/Qiskit/qiskit/runs/$GITHUB_RUN_NUMBER" -echo "git push" -git push --quiet origin $TARGET_BRANCH_PO -echo "********** End of pushing po to working repo! *************" -popd diff --git a/tools/github_poBranch_update_key.enc b/tools/github_poBranch_update_key.enc deleted file mode 100644 index cbffab9d4..000000000 Binary files a/tools/github_poBranch_update_key.enc and /dev/null differ diff --git a/tox.ini b/tox.ini index 7a30a0d6a..f2662be4b 100644 --- a/tox.ini +++ b/tox.ini @@ -45,15 +45,6 @@ deps = allowlist_externals = rm commands = rm -rf {toxinidir}/docs/stubs/ {toxinidir}/docs/_build -[testenv:gettext] -envdir = .tox/docs -basepython = python3 -deps = - -r requirements-dev.txt -commands = - sphinx-build -W -b gettext docs/ docs/_build/gettext {posargs} - sphinx-intl -c docs/conf.py update -p docs/_build/gettext -l en -d docs/locale - [doc8] max-line-length=100 ignore-path=docs/_build