From c037c4fa4dccd5d409f5d6f08086d97b1e8c208a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 13:29:26 +0900 Subject: [PATCH 01/59] Document usage-based billing and the 5.0.x function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The guide told every reader that use "is limited to problems requiring at most 20 qubits, unless a license is obtained granting a higher limit". For a usage-based user there is no qubit limit at all, and the way past 20 is to pass function_size="l", not to email sales. The tutorial said the same thing about FeP-NO needing a license for 44 qubits. The guide now opens that part with a table a reader can find themselves in: without a token, or with one. Qubits, what you pay, and whether the size is checked differ between the two, and most readers are in the first column. Trial access is a line under the table rather than a third column, because a column nobody is in slows down the one thing the table is for. Two sections follow it, for the first column: the s/m/l sizes with their fees, and estimate_only, which sizes a problem and returns without running it. Licensing becomes Licensed use and speaks to the second column only. Fees are in resource units, with a link for what a resource unit costs. Our rates were derived at $25 per RU, but that figure is the royalty per RU a user spends, not a price anyone is charged, and the model may still be adjusted — one number here would be wrong somewhere, and wrong about money. Also: the request-access form is no longer how anyone starts, so it goes from Get started and Next steps; the main example and all four tutorial runs name their size; the response fields that were never documented (energy_variance, energy_history, function_version and metadata.resource_usage) are described, with a note that everything which grows with the problem is in the results file instead; and failures are documented as carrying a code, a message and a solution, with the seven codes the function returns. The API reference gains estimate_only, a section on function_size as a platform argument, the two missing output rows and the estimate's own output table. Checked with the repository's own spelling, markdown, internal-link and prettier checks, and by rendering all three pages in the local preview. Co-Authored-By: Claude Opus 5 (1M context) --- docs/api/functions/qunova-chemistry.mdx | 47 ++++++- docs/guides/qunova-chemistry.ipynb | 160 ++++++++++++++++++++++-- docs/tutorials/qunova-hivqe.ipynb | 8 +- 3 files changed, 204 insertions(+), 11 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index cf2cc742652e..13e45aac5bf5 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -224,16 +224,59 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` +### `estimate_only` + +Size the problem and return without running it. The response contains an +`"estimate"` dictionary instead of a result, and no QPU time is spent. +- Required: No +- Example: `True` + + +## Function size + +`function_size` is an argument of the platform rather than of this function, +passed to `run()` alongside the arguments above. It selects the resources the +job runs on, and it is what the run is billed at. +| `function_size` | Qubits | Compute profile | License fee per run | +|-----|-----|-----|-----| +| `"s"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU | +| `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | +| `"l"` | No limit | 48 CPUs, 768 GB | 4.0 RU | +Jobs submitted without it run at `"m"`. A size smaller than the problem needs +is rejected before any QPU time is spent, with error code 1221 naming the size +to use. A size larger than it needs runs, and is billed at that larger size. + +Runs made with a license token are not subject to this check, and are instead +bounded by the qubit limit the license grants. ## Outputs -The function returns a dictionary with four keys and values. The keys and values are documented in the following table: +The function returns a dictionary with the following keys and values: | Key | Value Type| Explanation | |-----|---------------|---------------------------------------------------------------------------------------------------------------------------| | `"energy"` | `float` | The approximate ground state energy of the molecule. | | `"results_file_name"` | `string` | The name of the hdf5 results file that can be downloaded using Qiskit Serverless. The file contains `"states"`, `"eigenvector"`, `"energy_history"`, `"final_energy"`, and `"final_energy_variance"`. | | `"energy_variance"` | `float` | The energy variance of the ground state of the subspace composed of the `"states"` saved in the results file, giving an indication of the quality of the solution. This value is non-negative and a lower value means that the ground state of the subspace more closely approximates an eigenstate of the system's Hamiltonian. | -| `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | \ No newline at end of file +| `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | +| `"function_version"` | `string` | The version of the function that ran the job. Quote it in a support request. | +| `"metadata"` | `dict` | Contains `"resource_usage"`, giving the time spent in each stage of the job, including QPU time. | + +### With `estimate_only` + +An estimate returns `"function_version"` and `"metadata"` as above, and in +place of a result an `"estimate"` dictionary: + +| Key | Value Type| Explanation | +|-----|---------------|-----| +| `"num_qubits"` | `int` | The number of qubits the problem needs. | +| `"function_size"` | `string` | The function size to submit it at. | +| `"compute_profile"` | `string` | The CPUs and memory that size provides, such as `"16x128"`. | +| `"license_fee_ru"` | `float` | What a run at that size is billed, in resource units. | +| `"qubit_limit"` | `Optional[int]` | The qubit limit that applies to the caller, or `null` if none does. | +| `"within_qubit_limit"` | `bool` | Whether the problem fits that limit. | + +The qubit limit is reported rather than enforced, so a problem can be sized +before holding a license that permits it. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 3e970ef06f32..37d9fc3c62d1 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -135,8 +135,7 @@ "source": [ "## Get started\n", "\n", - "First, [request access to the function](https://forms.office.com/r/zN3hvMTqJ1).\n", - "Then, authenticate using your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) and, assuming you've already [saved your account](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) to your local environment, select the Qiskit Function as follows:" + "Authenticate using your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) and, assuming you've already [saved your account](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) to your local environment, select the Qiskit Function as follows:" ] }, { @@ -263,6 +262,9 @@ " # `backend_name` is the name of a backend with at least 16 qubits,\n", " # for example, \"ibm_marrakesh\".\n", " backend_name=backend_name,\n", + " # `function_size` sets the resources the job runs on and what it\n", + " # costs. See \"Limits and billing\" below.\n", + " function_size=\"m\",\n", " max_states=2000,\n", " max_expansion_states=10,\n", " molecule_options=molecule_options,\n", @@ -365,7 +367,23 @@ "id": "2b6fb05c", "metadata": {}, "source": [ - "To access the ground state energy, use the `\"energy\"` key. The `\"results_file_name\"` key provides the name of the h5 results file that can be downloaded using `QiskitServerless`.\n", + "To access the ground state energy, use the `\"energy\"` key. The\n", + "`\"results_file_name\"` key provides the name of the h5 results file that can\n", + "be downloaded using `QiskitServerless`.\n", + "\n", + "The response also carries:\n", + "- `\"energy_variance\"`: the energy variance of the final trial state, as a\n", + " single number,\n", + "- `\"energy_history\"`: the energies computed along the way, two per\n", + " iteration,\n", + "- `\"function_version\"`: the version of the function that ran the job, which\n", + " is worth quoting in a support request, and\n", + "- `\"metadata\"`: a `\"resource_usage\"` dictionary giving the time spent in\n", + " each stage of the job, including QPU time.\n", + "\n", + "Everything that grows with the size of the problem is written to the\n", + "results file rather than returned, so the response stays small whatever\n", + "you run.\n", "\n", "This file contains :\n", "- `\"final_energy\"`: the energy of the final trial state,\n", @@ -452,14 +470,118 @@ " final_energy_variance = f[\"final_energy_variance\"][0]" ] }, + { + "cell_type": "markdown", + "id": "77066575-76b0-4416-a033-a33083d418f3", + "metadata": {}, + "source": [ + "## Limits and billing\n", + "\n", + "What applies to your runs depends on whether you hold a license token.\n", + "\n", + "| | Without a token | With a license token |\n", + "| --- | --- | --- |\n", + "| **Qubits** | No limit | What your license grants |\n", + "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", + "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent | Not checked |\n", + "\n", + "Most users are in the first column. If you have not been issued a token, that\n", + "is you, and the two sections that follow are the ones you need. License\n", + "holders can skip to [Licensed use](#licensed-use).\n", + "\n", + "Trial access is limited to 20 qubits. A job that needs more fails with error\n", + "code 4500." + ] + }, + { + "cell_type": "markdown", + "id": "df5164aa-c7ca-438e-a414-f7f5a6795aa5", + "metadata": {}, + "source": [ + "### Function sizes\n", + "\n", + "`function_size` tells the platform what resources to run the job on, and it\n", + "is what the run is billed at. Pass it to `run()` alongside the function's own\n", + "arguments.\n", + "\n", + "| `function_size` | Qubits | License fee per run |\n", + "| --- | --- | --- |\n", + "| `\"s\"` | Up to 10 | 0.4 RU |\n", + "| `\"m\"` | Up to 20 | 1.0 RU |\n", + "| `\"l\"` | No limit | 4.0 RU |\n", + "\n", + "Fees are given in resource units. See [IBM Quantum\n", + "plans](/docs/guides/plans-overview) for what a resource unit costs on your\n", + "plan.\n", + "\n", + "If you leave `function_size` out, the job runs at `\"m\"`.\n", + "\n", + "A size smaller than the problem needs is rejected before any QPU time is\n", + "spent, and the error names the size to use instead. A size larger than it\n", + "needs runs and is billed at that larger size, with a warning telling you\n", + "which size would have been enough." + ] + }, + { + "cell_type": "markdown", + "id": "5569c36e-04c2-453f-a7fd-89b36b9d0d7b", + "metadata": {}, + "source": [ + "### Check the size before you run\n", + "\n", + "Passing `estimate_only=True` sizes the problem and returns without running\n", + "it, so you can find out what a job needs before committing to it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f5924f6-0d35-40d3-95f9-c67374532dff", + "metadata": {}, + "outputs": [], + "source": [ + "estimate_job = function.run(\n", + " geometry=geometry,\n", + " backend_name=backend_name,\n", + " max_states=2000,\n", + " max_expansion_states=10,\n", + " molecule_options=molecule_options,\n", + " hivqe_options=hivqe_options,\n", + " estimate_only=True,\n", + ")\n", + "print(estimate_job.result()[\"estimate\"])" + ] + }, + { + "cell_type": "markdown", + "id": "e08cb40a-174c-4a54-9411-9089c353591b", + "metadata": {}, + "source": [ + "The `\"estimate\"` dictionary reports:\n", + "\n", + "| Key | Meaning |\n", + "| --- | --- |\n", + "| `\"num_qubits\"` | The number of qubits this problem needs |\n", + "| `\"function_size\"` | The size to submit it at |\n", + "| `\"compute_profile\"` | The CPU and memory that size provides |\n", + "| `\"license_fee_ru\"` | What a run at that size is billed |\n", + "| `\"qubit_limit\"` | The limit that applies to you, or `None` if there is none |\n", + "| `\"within_qubit_limit\"` | Whether this problem fits that limit |\n", + "\n", + "An estimate reports your qubit limit rather than enforcing it, so you can\n", + "find out what a problem needs before you hold a license that allows it." + ] + }, { "cell_type": "markdown", "id": "5f252348-720f-47c0-9e7f-ae5e5512b8d1", "metadata": {}, "source": [ - "## Licensing\n", + "## Licensed use\n", "\n", - "Note that use of this Qiskit Function is limited to problems requiring at most 20 qubits, unless a license is obtained granting a higher limit.\n", + "A license grants a qubit limit of its own, and runs made with a license\n", + "token are not subject to the function size check. If you do not hold a\n", + "token, see [Limits and billing](#limits-and-billing) instead.\n", "\n", "Email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with license inquiries.\n", "\n", @@ -644,7 +766,8 @@ "source": [ "## Fetch error messages\n", "\n", - "If your workload fails, the status will be `ERROR` and calling `job.result()` will raise an exception:" + "If your workload fails, the status will be `ERROR` and calling\n", + "`job.result()` will raise an exception:" ] }, { @@ -708,6 +831,30 @@ "job.status()" ] }, + { + "cell_type": "markdown", + "id": "e86cab2f-11ab-4647-b785-9091c014034c", + "metadata": {}, + "source": [ + "Every failure reports an error code, a message describing what went wrong,\n", + "and a solution saying what to do about it. The codes follow [IBM's error\n", + "code registry](/docs/errors), and the ones this function returns are:\n", + "\n", + "| Code | What happened |\n", + "| --- | --- |\n", + "| 1007 | The `backend_name` you gave does not exist, or is not available to you |\n", + "| 1201 | A license token was supplied but no matching license was found |\n", + "| 1219 | A license token was found but could not be read |\n", + "| 1221 | An argument did not validate, or `function_size` was too small for the problem. The message names the size to use |\n", + "| 1500 | Something unexpected went wrong. Quote the job ID when you report it |\n", + "| 2409 | The license has expired, has been revoked, or was used from an instance it was not issued for |\n", + "| 4500 | The problem needs more qubits than your license or trial access allows |\n", + "\n", + "Several codes cover more than one cause, so read the message as well as the\n", + "code. If you need help with a failure, send the Function job ID to\n", + "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com)." + ] + }, { "cell_type": "markdown", "id": "7c1e4a2b", @@ -741,7 +888,6 @@ "## Next steps\n", "\n", "\n", - "- Request access to the function by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Try the [Compute dissociation PES curve for FeP-NO with HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index da02a45ce223..908d0a17a4b5 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -207,7 +207,7 @@ "source": [ "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HiVQE Chemistry function\n", "\n", - "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut." + "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut. You also set `function_size`, which selects the resources the job runs on and what it is billed; these geometries need 20 qubits, which `\"m\"` covers. See [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide." ] }, { @@ -230,6 +230,7 @@ " hivqe_run = hivqe.run(\n", " geometry=geom,\n", " backend_name=\"\",\n", + " function_size=\"m\",\n", " max_states=40000,\n", " max_expansion_states=100,\n", " molecule_options=molecule_options,\n", @@ -591,7 +592,7 @@ "source": [ "## Part 2: FeP-NO (44Q)\n", "\n", - "Note that to run the function on the FeP-NO system with the settings shown in this example, you need a license that permits using the function with at least 44 qubits. Email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about obtaining a license.\n", + "The settings shown in this example need 44 qubits, so the runs below are submitted at `function_size=\"l\"`, the size that has no qubit limit. If you hold a license instead, it must permit at least 44 qubits; email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about one. Either way, see [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide.\n", "\n", "### Step 1: Map classical inputs to a quantum problem\n", "\n", @@ -964,6 +965,7 @@ "hivqe_run_1_75 = hivqe.run(\n", " geometry=str_geometries[\"1.75\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", " molecule_options=molecule_options,\n", @@ -1014,6 +1016,7 @@ "hivqe_run_2_00 = hivqe.run(\n", " geometry=str_geometries[\"2.00\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", " molecule_options=molecule_options,\n", @@ -1064,6 +1067,7 @@ "hivqe_run_5_00 = hivqe.run(\n", " geometry=str_geometries[\"5.00\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", " molecule_options=molecule_options,\n", From 1e981546015d160fd927a2f79a40712ced4f1e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 13:43:16 +0900 Subject: [PATCH 02/59] Keep the request form on the license path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dropping it from Get started was right: requesting access was the first instruction a usage-based reader got, for something they never need. But a license still has to be asked for, and the form is how, so it belongs in Licensed use rather than gone. In Next steps it reads "if you need one" — in a list of recommendations an unqualified link reads as something everyone has to do. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 37d9fc3c62d1..29a3800ceef4 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -583,7 +583,8 @@ "token are not subject to the function size check. If you do not hold a\n", "token, see [Limits and billing](#limits-and-billing) instead.\n", "\n", - "Email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with license inquiries.\n", + "To request a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1) or email\n", + "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with your inquiry.\n", "\n", "### Example of licensed function use\n", "\n", @@ -888,6 +889,7 @@ "## Next steps\n", "\n", "\n", + "- Request a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Try the [Compute dissociation PES curve for FeP-NO with HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", From 7326366bc6753a4af983e586a4083a3021d73b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 13:52:13 +0900 Subject: [PATCH 03/59] Say what to do with the API key, in that order The sentence told the reader to authenticate and then, mid-clause, assumed they already had, which sends them back through it. The code below takes no token, so saving the key is the step that matters, and saying so is both shorter and the thing the reader actually does. The key is still required either way. Both links are kept; the one that hung on "saved your account" now hangs on "to your local environment". Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 29a3800ceef4..93f77a4d0ac3 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -135,7 +135,7 @@ "source": [ "## Get started\n", "\n", - "Authenticate using your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) and, assuming you've already [saved your account](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) to your local environment, select the Qiskit Function as follows:" + "Save your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) [to your local environment](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) if you have not already, then select the Qiskit Function as follows:" ] }, { From 3a1351dee96353d941ef3186ca29ce647d77e83f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 13:55:20 +0900 Subject: [PATCH 04/59] Call the form what the form calls itself The form is titled "request access to the function", so a link labelled "request a license" makes the reader stop and check they clicked the right thing. It now reads "request access and a license", which covers both what they are asking for and what they will see. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 93f77a4d0ac3..5704637f4534 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -583,7 +583,7 @@ "token are not subject to the function size check. If you do not hold a\n", "token, see [Limits and billing](#limits-and-billing) instead.\n", "\n", - "To request a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1) or email\n", + "To request access and a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with your inquiry.\n", "\n", "### Example of licensed function use\n", @@ -889,7 +889,7 @@ "## Next steps\n", "\n", "\n", - "- Request a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", + "- Request access and a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Try the [Compute dissociation PES curve for FeP-NO with HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", From 4162fca0141e0e1ea94fbb5dd316dccba17f7d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:00:57 +0900 Subject: [PATCH 05/59] Point both kinds of reader somewhere from Get started Moving the request form out of Get started put it 68% down the page, so someone who needs a license had to read most of a guide written for people who do not. Get started now says in one line how runs are billed and links the two sections, before the step that sets up the key. The signpost goes above that step, not below it: the sentence ends in "as follows:" and the code cell has to be what follows. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 5704637f4534..cc980514d220 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -135,6 +135,8 @@ "source": [ "## Get started\n", "\n", + "Runs are billed per execution at the function size you choose, with no qubit limit; see [Limits and billing](#limits-and-billing). If you hold or need a license, see [Licensed use](#licensed-use).\n", + "\n", "Save your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) [to your local environment](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) if you have not already, then select the Qiskit Function as follows:" ] }, From 16608962fe5c9f5a3528afff5e5090d3d0b3ac7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:02:21 +0900 Subject: [PATCH 06/59] Drop the note about the response staying small It answered a question from our own review of the 4.0.0 docs, where the reviewer asked how putting results_file_name inside job.result() helps when job.result() was the thing returning an empty dictionary. That is worth knowing internally; a reader of the guide only needs to know where the data is, which the two lists already say. It also sat between the h5 file and "This file contains", leaving the reference three paragraphs from what it referred to. That list now names the results file itself. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index cc980514d220..2c0be0e4a5d5 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -383,11 +383,7 @@ "- `\"metadata\"`: a `\"resource_usage\"` dictionary giving the time spent in\n", " each stage of the job, including QPU time.\n", "\n", - "Everything that grows with the size of the problem is written to the\n", - "results file rather than returned, so the response stays small whatever\n", - "you run.\n", - "\n", - "This file contains :\n", + "The results file contains:\n", "- `\"final_energy\"`: the energy of the final trial state,\n", "- `\"final_energy_variance\"`: the energy variance of the final trial state,\n", "- `\"energy_history\"`: the energy history over HI-VQE's training,\n", From cd2ce1a7d22e26a054f327ef6db33aa664311565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:11:04 +0900 Subject: [PATCH 07/59] Answer the row's question in the license column "Not checked" described what our code does, not what the reader has to do, and it did not pair with "Required" in the other column. The two cells now answer the same question. The clause about CPU and memory stays: a license run skips the size check entirely, so nothing tells a reader their 44-qubit job is running on the resources for 20. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 2c0be0e4a5d5..b83bf70ffcd0 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -481,7 +481,7 @@ "| --- | --- | --- |\n", "| **Qubits** | No limit | What your license grants |\n", "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", - "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent | Not checked |\n", + "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent | Not required, though the size still sets the CPU and memory the job gets |\n", "\n", "Most users are in the first column. If you have not been issued a token, that\n", "is you, and the two sections that follow are the ones you need. License\n", From 72380724853196d953f47a5019f8779864cd02cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:38:41 +0900 Subject: [PATCH 08/59] Split the two kinds of reader once, in Setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tutorial was written when a license was the only way to run the function, and Setup still said you needed one. Adding the size argument to the four run() calls did not fix that: it left notes about sizes and licenses bolted onto Part 1 and Part 2, saying the same thing late and twice. The wrapper library forwards everything except the token, and routes every other attribute to the function it wraps, so a licensed run differs from a usage-based one in the two lines that load the function and nowhere else. Setup now shows both and gives a four-row table of what actually differs, including that running the whole tutorial is six runs at "m" and three at "l" — 18 resource units, which the tutorial never mentioned while asking the reader to execute it. The licensed variant is a fenced block rather than a code cell: this notebook is run top to bottom, and a second load cell would replace hivqe with a wrapper around a token the reader does not have. Part 1 and Part 2 now state their size and leave the explaining to Setup. Also removes a duplicated cell: the 5,110-character geometry_1_75 block appeared twice in a row. That duplicate is in the published tutorial upstream too, so a reader today sees the same block twice and cannot tell whether the two differ. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 195 ++++++------------------------ 1 file changed, 39 insertions(+), 156 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 908d0a17a4b5..22a8b8db8490 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -73,7 +73,9 @@ "source": [ "## Setup\n", "\n", - "To run this tutorial, import `qunova/hivqe-chemistry` function via `QiskitFunctionCatalog`. You need an IBM Quantum Premium Plan, Flex Plan, or On-Prem (IBM Quantum Platform API) Plan account with a license from Qunova to run this function." + "To run this tutorial, load the `qunova/hivqe-chemistry` function through\n", + "`QiskitFunctionsCatalog`. You need an IBM Quantum Premium Plan, Flex Plan, or\n", + "On-Prem (IBM Quantum Platform API) Plan account." ] }, { @@ -99,6 +101,40 @@ "hivqe = catalog.load(\"qunova/hivqe-chemistry\")" ] }, + { + "cell_type": "markdown", + "id": "659d5a25-7fd6-41b2-a657-5bfe1d8c713d", + "metadata": {}, + "source": [ + "### If you have a license\n", + "\n", + "The cell above loads the function for use without a license, which is how most\n", + "readers will run this tutorial. A license is loaded through a wrapper library\n", + "instead, which takes your license token and otherwise behaves identically:\n", + "\n", + "```python\n", + "# pip install hivqe-qiskit-function-utils\n", + "from hivqe_qiskit_function_utils import FunctionWrapper\n", + "\n", + "hivqe = FunctionWrapper(\n", + " token=\"YOUR_HIVQE_LICENSE_TOKEN\",\n", + " function=catalog.load(\"qunova/hivqe-chemistry\"),\n", + ")\n", + "```\n", + "\n", + "Every `hivqe.run(...)` below is the same either way. What differs is this:\n", + "\n", + "| | Without a license | With a license |\n", + "| --- | --- | --- |\n", + "| **Loading** | `catalog.load(...)` | through `FunctionWrapper` |\n", + "| **`function_size`** | Sets the resources and the fee. Too small and the run is rejected | Passed through, not checked |\n", + "| **Running Part 2** | Submit it at `\"l\"` | Your license must permit 44 qubits |\n", + "| **What this tutorial costs** | Six runs at `\"m\"` and three at `\"l\"`: 6.0 and 12.0 resource units | Per your license agreement |\n", + "\n", + "See [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in\n", + "the guide for what the sizes mean." + ] + }, { "cell_type": "markdown", "id": "00c68174", @@ -207,7 +243,7 @@ "source": [ "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HiVQE Chemistry function\n", "\n", - "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut. You also set `function_size`, which selects the resources the job runs on and what it is billed; these geometries need 20 qubits, which `\"m\"` covers. See [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide." + "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut. These geometries need 20 qubits, so the runs are submitted at `function_size=\"m\"`." ] }, { @@ -592,7 +628,7 @@ "source": [ "## Part 2: FeP-NO (44Q)\n", "\n", - "The settings shown in this example need 44 qubits, so the runs below are submitted at `function_size=\"l\"`, the size that has no qubit limit. If you hold a license instead, it must permit at least 44 qubits; email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about one. Either way, see [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide.\n", + "The settings shown in this example need 44 qubits, so the runs below are submitted at `function_size=\"l\"`. On a license, it must permit at least 44 qubits; email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about one.\n", "\n", "### Step 1: Map classical inputs to a quantum problem\n", "\n", @@ -784,159 +820,6 @@ "hivqe_result = {}" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "52b55a07", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'5.0': '\\nFe 9.918629 31.289202 1.717339\\nN 10.542914 31.832173 -0.080685\\nN 11.795572 31.199413 2.341831\\nN 9.294593 30.741247 3.513929\\nN 8.042689 31.359481 1.087282\\nC 9.775254 32.111817 -1.200449\\nC 10.600219 32.479101 -2.319680\\nC 11.891090 32.425876 -1.887580\\nC 11.847694 32.024341 -0.507342\\nC 12.945734 31.464689 1.611366\\nC 14.116395 31.289997 2.423572\\nC 13.685777 30.915122 3.663719\\nC 12.252381 30.861042 3.608186\\nC 10.062170 30.463021 4.634102\\nC 9.236749 30.104333 5.755782\\nC 7.945687 30.161198 5.324720\\nC 7.989641 30.552269 3.941498\\nC 6.892881 31.087489 1.815829\\nC 5.722676 31.253502 1.001149\\nC 6.153153 31.631057 -0.238233\\nC 7.586010 31.695401 -0.179773\\nC 8.390724 32.047572 -1.247553\\nH 7.903308 32.291586 -2.187969\\nC 12.973334 31.849872 0.283741\\nH 13.944682 32.031190 -0.169145\\nC 11.447158 30.518591 4.678739\\nH 11.934423 30.277429 5.619969\\nC 6.864795 30.711643 3.146118\\nH 5.893357 30.532078 3.599511\\nH 12.800139 32.636412 -2.439296\\nH 10.224017 32.743662 -3.301293\\nH 15.131785 31.441247 2.076257\\nH 14.273933 30.694315 4.546802\\nH 9.612512 29.848040 6.739754\\nH 7.036117 29.960530 5.879248\\nH 4.707408 31.099933 1.347803\\nH 5.564992 31.851940 -1.121294\\nN 9.666041 36.091609 3.085945\\nO 9.598728 37.226756 3.411299\\n'}" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "geometry_1_75 = \"\"\"\n", - "Fe 9.910596 31.534095 1.798088\n", - "N 10.557481 31.888419 -0.055204\n", - "N 11.823496 31.255002 2.384659\n", - "N 9.292831 30.783362 3.568730\n", - "N 8.036805 31.418327 1.124265\n", - "C 9.784765 32.177349 -1.158798\n", - "C 10.612656 32.501029 -2.296868\n", - "C 11.903375 32.404043 -1.876832\n", - "C 11.859093 32.028943 -0.483750\n", - "C 12.965737 31.464698 1.641427\n", - "C 14.146517 31.236323 2.440231\n", - "C 13.713061 30.885870 3.681911\n", - "C 12.268752 30.896411 3.634891\n", - "C 10.067717 30.486167 4.664747\n", - "C 9.246224 30.053411 5.772052\n", - "C 7.957075 30.082846 5.336488\n", - "C 7.995710 30.538421 3.967046\n", - "C 6.900258 31.104497 1.836595\n", - "C 5.722470 31.251707 1.015333\n", - "C 6.148430 31.668586 -0.207993\n", - "C 7.587039 31.767438 -0.130483\n", - "C 8.399453 32.134197 -1.192329\n", - "H 7.912872 32.388031 -2.131079\n", - "C 12.984883 31.836053 0.306093\n", - "H 13.955948 31.977044 -0.162626\n", - "C 11.453768 30.560663 4.708020\n", - "H 11.940677 30.298823 5.644352\n", - "C 6.877071 30.697580 3.164102\n", - "H 5.907240 30.476797 3.603674\n", - "H 12.813946 32.569160 -2.441577\n", - "H 10.236332 32.758110 -3.280309\n", - "H 15.164312 31.335191 2.080201\n", - "H 14.299625 30.629109 4.556760\n", - "H 9.626524 29.758225 6.743433\n", - "H 7.053076 29.823583 5.875809\n", - "H 4.709768 31.058315 1.350561\n", - "H 5.561898 31.886355 -1.093106\n", - "N 9.832739 33.209042 2.298783\n", - "O 9.346337 34.075996 1.606023\n", - "\"\"\"\n", - "\n", - "geometry_2_00 = \"\"\"\n", - "Fe 9.917990 31.445558 1.778346\n", - "N 10.556809 31.866188 -0.055498\n", - "N 11.814089 31.227003 2.372666\n", - "N 9.297875 30.758246 3.550104\n", - "N 8.043584 31.397768 1.120485\n", - "C 9.784831 32.164652 -1.160219\n", - "C 10.611624 32.501801 -2.293514\n", - "C 11.902858 32.406547 -1.875160\n", - "C 11.859552 32.017818 -0.486307\n", - "C 12.960503 31.454432 1.636717\n", - "C 14.140770 31.242960 2.439615\n", - "C 13.708543 30.884151 3.678983\n", - "C 12.266351 30.874173 3.627468\n", - "C 10.070264 30.465070 4.655102\n", - "C 9.247247 30.053101 5.766681\n", - "C 7.958085 30.091201 5.332866\n", - "C 7.998432 30.529979 3.958727\n", - "C 6.901428 31.093932 1.833807\n", - "C 5.723289 31.255057 1.016540\n", - "C 6.151314 31.670649 -0.206350\n", - "C 7.589736 31.755538 -0.133074\n", - "C 8.400230 32.124963 -1.194447\n", - "H 7.913264 32.386655 -2.130914\n", - "C 12.983905 31.827747 0.302415\n", - "H 13.955696 31.979687 -0.161365\n", - "C 11.454251 30.533644 4.698234\n", - "H 11.941002 30.276716 5.636156\n", - "C 6.877444 30.689985 3.159940\n", - "H 5.907605 30.480118 3.604825\n", - "H 12.813105 32.581608 -2.437367\n", - "H 10.233725 32.768337 -3.273979\n", - "H 15.157796 31.357524 2.082132\n", - "H 14.295001 30.638320 4.557047\n", - "H 9.626721 29.768762 6.741623\n", - "H 7.051752 29.847502 5.875478\n", - "H 4.709710 31.071712 1.354640\n", - "H 5.565103 31.898376 -1.089333\n", - "N 9.840508 33.353531 2.373019\n", - "O 9.344561 34.158205 1.637232\n", - "\"\"\"\n", - "\n", - "geometry_5_00 = \"\"\"\n", - "Fe 9.918629 31.289202 1.717339\n", - "N 10.542914 31.832173 -0.080685\n", - "N 11.795572 31.199413 2.341831\n", - "N 9.294593 30.741247 3.513929\n", - "N 8.042689 31.359481 1.087282\n", - "C 9.775254 32.111817 -1.200449\n", - "C 10.600219 32.479101 -2.319680\n", - "C 11.891090 32.425876 -1.887580\n", - "C 11.847694 32.024341 -0.507342\n", - "C 12.945734 31.464689 1.611366\n", - "C 14.116395 31.289997 2.423572\n", - "C 13.685777 30.915122 3.663719\n", - "C 12.252381 30.861042 3.608186\n", - "C 10.062170 30.463021 4.634102\n", - "C 9.236749 30.104333 5.755782\n", - "C 7.945687 30.161198 5.324720\n", - "C 7.989641 30.552269 3.941498\n", - "C 6.892881 31.087489 1.815829\n", - "C 5.722676 31.253502 1.001149\n", - "C 6.153153 31.631057 -0.238233\n", - "C 7.586010 31.695401 -0.179773\n", - "C 8.390724 32.047572 -1.247553\n", - "H 7.903308 32.291586 -2.187969\n", - "C 12.973334 31.849872 0.283741\n", - "H 13.944682 32.031190 -0.169145\n", - "C 11.447158 30.518591 4.678739\n", - "H 11.934423 30.277429 5.619969\n", - "C 6.864795 30.711643 3.146118\n", - "H 5.893357 30.532078 3.599511\n", - "H 12.800139 32.636412 -2.439296\n", - "H 10.224017 32.743662 -3.301293\n", - "H 15.131785 31.441247 2.076257\n", - "H 14.273933 30.694315 4.546802\n", - "H 9.612512 29.848040 6.739754\n", - "H 7.036117 29.960530 5.879248\n", - "H 4.707408 31.099933 1.347803\n", - "H 5.564992 31.851940 -1.121294\n", - "N 9.666041 36.091609 3.085945\n", - "O 9.598728 37.226756 3.411299\n", - "\"\"\"\n", - "\n", - "str_geometries = {\n", - " \"1.75\": geometry_1_75,\n", - " \"2.00\": geometry_2_00,\n", - " \"5.00\": geometry_5_00,\n", - "}\n", - "\n", - "\n", - "hivqe_result = {}" - ] - }, { "cell_type": "markdown", "id": "5ed92d44", From 71e429604a6e654f3798a2d001e10549c6dad621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:43:16 +0900 Subject: [PATCH 09/59] Give each reader their own instructions, not a comparison A reader at this point is about to execute cells and already knows whether they hold a license. The table made them find their column, read four rows across and assemble their own instructions out of it. Two blocks, each complete, let them read only theirs and stop. The comparison table in the guide stays: there the reader's job is to work out which kind of user they are, and comparing the two is how they find out. Here the job is to run the thing. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 22a8b8db8490..91268e4bf27b 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -106,11 +106,18 @@ "id": "659d5a25-7fd6-41b2-a657-5bfe1d8c713d", "metadata": {}, "source": [ - "### If you have a license\n", + "### Before you run\n", "\n", - "The cell above loads the function for use without a license, which is how most\n", - "readers will run this tutorial. A license is loaded through a wrapper library\n", - "instead, which takes your license token and otherwise behaves identically:\n", + "**Without a license.** The cell above is all the setup you need. Every run\n", + "below names a `function_size`, which sets the resources it gets and what it is\n", + "billed: `\"m\"` for Part 1, and `\"l\"` for Part 2, which needs 44 qubits. Running\n", + "the whole tutorial is six runs at `\"m\"` and three at `\"l\"`, or 18.0 resource\n", + "units. See [Limits and\n", + "billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide for\n", + "what the sizes cost.\n", + "\n", + "**With a license.** Load the function through the wrapper library instead of\n", + "the cell above, then run everything below unchanged:\n", "\n", "```python\n", "# pip install hivqe-qiskit-function-utils\n", @@ -122,17 +129,8 @@ ")\n", "```\n", "\n", - "Every `hivqe.run(...)` below is the same either way. What differs is this:\n", - "\n", - "| | Without a license | With a license |\n", - "| --- | --- | --- |\n", - "| **Loading** | `catalog.load(...)` | through `FunctionWrapper` |\n", - "| **`function_size`** | Sets the resources and the fee. Too small and the run is rejected | Passed through, not checked |\n", - "| **Running Part 2** | Submit it at `\"l\"` | Your license must permit 44 qubits |\n", - "| **What this tutorial costs** | Six runs at `\"m\"` and three at `\"l\"`: 6.0 and 12.0 resource units | Per your license agreement |\n", - "\n", - "See [Limits and billing](/docs/guides/qunova-chemistry#limits-and-billing) in\n", - "the guide for what the sizes mean." + "Your license sets the qubit limit, so it has to permit at least 44 qubits for\n", + "Part 2. The `function_size` in each run is passed through and not checked." ] }, { From 8924b2549bd3f67cee0dddac4d9b9f9ee95a9666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 14:50:43 +0900 Subject: [PATCH 10/59] Put the duplicated geometry cell back for now The 5,110-character geometry_1_75 block appears twice in a row, upstream as well as here, so a reader of the published tutorial sees the same block twice. Removing it is right but it is not part of documenting usage-based billing, and it is being discussed separately. Restored from main unchanged, cell id included, so this part of the file does not appear in the diff at all. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 153 ++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 91268e4bf27b..4b7ddf5ff8c2 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -818,6 +818,159 @@ "hivqe_result = {}" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "52b55a07", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'5.0': '\\nFe 9.918629 31.289202 1.717339\\nN 10.542914 31.832173 -0.080685\\nN 11.795572 31.199413 2.341831\\nN 9.294593 30.741247 3.513929\\nN 8.042689 31.359481 1.087282\\nC 9.775254 32.111817 -1.200449\\nC 10.600219 32.479101 -2.319680\\nC 11.891090 32.425876 -1.887580\\nC 11.847694 32.024341 -0.507342\\nC 12.945734 31.464689 1.611366\\nC 14.116395 31.289997 2.423572\\nC 13.685777 30.915122 3.663719\\nC 12.252381 30.861042 3.608186\\nC 10.062170 30.463021 4.634102\\nC 9.236749 30.104333 5.755782\\nC 7.945687 30.161198 5.324720\\nC 7.989641 30.552269 3.941498\\nC 6.892881 31.087489 1.815829\\nC 5.722676 31.253502 1.001149\\nC 6.153153 31.631057 -0.238233\\nC 7.586010 31.695401 -0.179773\\nC 8.390724 32.047572 -1.247553\\nH 7.903308 32.291586 -2.187969\\nC 12.973334 31.849872 0.283741\\nH 13.944682 32.031190 -0.169145\\nC 11.447158 30.518591 4.678739\\nH 11.934423 30.277429 5.619969\\nC 6.864795 30.711643 3.146118\\nH 5.893357 30.532078 3.599511\\nH 12.800139 32.636412 -2.439296\\nH 10.224017 32.743662 -3.301293\\nH 15.131785 31.441247 2.076257\\nH 14.273933 30.694315 4.546802\\nH 9.612512 29.848040 6.739754\\nH 7.036117 29.960530 5.879248\\nH 4.707408 31.099933 1.347803\\nH 5.564992 31.851940 -1.121294\\nN 9.666041 36.091609 3.085945\\nO 9.598728 37.226756 3.411299\\n'}" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "geometry_1_75 = \"\"\"\n", + "Fe 9.910596 31.534095 1.798088\n", + "N 10.557481 31.888419 -0.055204\n", + "N 11.823496 31.255002 2.384659\n", + "N 9.292831 30.783362 3.568730\n", + "N 8.036805 31.418327 1.124265\n", + "C 9.784765 32.177349 -1.158798\n", + "C 10.612656 32.501029 -2.296868\n", + "C 11.903375 32.404043 -1.876832\n", + "C 11.859093 32.028943 -0.483750\n", + "C 12.965737 31.464698 1.641427\n", + "C 14.146517 31.236323 2.440231\n", + "C 13.713061 30.885870 3.681911\n", + "C 12.268752 30.896411 3.634891\n", + "C 10.067717 30.486167 4.664747\n", + "C 9.246224 30.053411 5.772052\n", + "C 7.957075 30.082846 5.336488\n", + "C 7.995710 30.538421 3.967046\n", + "C 6.900258 31.104497 1.836595\n", + "C 5.722470 31.251707 1.015333\n", + "C 6.148430 31.668586 -0.207993\n", + "C 7.587039 31.767438 -0.130483\n", + "C 8.399453 32.134197 -1.192329\n", + "H 7.912872 32.388031 -2.131079\n", + "C 12.984883 31.836053 0.306093\n", + "H 13.955948 31.977044 -0.162626\n", + "C 11.453768 30.560663 4.708020\n", + "H 11.940677 30.298823 5.644352\n", + "C 6.877071 30.697580 3.164102\n", + "H 5.907240 30.476797 3.603674\n", + "H 12.813946 32.569160 -2.441577\n", + "H 10.236332 32.758110 -3.280309\n", + "H 15.164312 31.335191 2.080201\n", + "H 14.299625 30.629109 4.556760\n", + "H 9.626524 29.758225 6.743433\n", + "H 7.053076 29.823583 5.875809\n", + "H 4.709768 31.058315 1.350561\n", + "H 5.561898 31.886355 -1.093106\n", + "N 9.832739 33.209042 2.298783\n", + "O 9.346337 34.075996 1.606023\n", + "\"\"\"\n", + "\n", + "geometry_2_00 = \"\"\"\n", + "Fe 9.917990 31.445558 1.778346\n", + "N 10.556809 31.866188 -0.055498\n", + "N 11.814089 31.227003 2.372666\n", + "N 9.297875 30.758246 3.550104\n", + "N 8.043584 31.397768 1.120485\n", + "C 9.784831 32.164652 -1.160219\n", + "C 10.611624 32.501801 -2.293514\n", + "C 11.902858 32.406547 -1.875160\n", + "C 11.859552 32.017818 -0.486307\n", + "C 12.960503 31.454432 1.636717\n", + "C 14.140770 31.242960 2.439615\n", + "C 13.708543 30.884151 3.678983\n", + "C 12.266351 30.874173 3.627468\n", + "C 10.070264 30.465070 4.655102\n", + "C 9.247247 30.053101 5.766681\n", + "C 7.958085 30.091201 5.332866\n", + "C 7.998432 30.529979 3.958727\n", + "C 6.901428 31.093932 1.833807\n", + "C 5.723289 31.255057 1.016540\n", + "C 6.151314 31.670649 -0.206350\n", + "C 7.589736 31.755538 -0.133074\n", + "C 8.400230 32.124963 -1.194447\n", + "H 7.913264 32.386655 -2.130914\n", + "C 12.983905 31.827747 0.302415\n", + "H 13.955696 31.979687 -0.161365\n", + "C 11.454251 30.533644 4.698234\n", + "H 11.941002 30.276716 5.636156\n", + "C 6.877444 30.689985 3.159940\n", + "H 5.907605 30.480118 3.604825\n", + "H 12.813105 32.581608 -2.437367\n", + "H 10.233725 32.768337 -3.273979\n", + "H 15.157796 31.357524 2.082132\n", + "H 14.295001 30.638320 4.557047\n", + "H 9.626721 29.768762 6.741623\n", + "H 7.051752 29.847502 5.875478\n", + "H 4.709710 31.071712 1.354640\n", + "H 5.565103 31.898376 -1.089333\n", + "N 9.840508 33.353531 2.373019\n", + "O 9.344561 34.158205 1.637232\n", + "\"\"\"\n", + "\n", + "geometry_5_00 = \"\"\"\n", + "Fe 9.918629 31.289202 1.717339\n", + "N 10.542914 31.832173 -0.080685\n", + "N 11.795572 31.199413 2.341831\n", + "N 9.294593 30.741247 3.513929\n", + "N 8.042689 31.359481 1.087282\n", + "C 9.775254 32.111817 -1.200449\n", + "C 10.600219 32.479101 -2.319680\n", + "C 11.891090 32.425876 -1.887580\n", + "C 11.847694 32.024341 -0.507342\n", + "C 12.945734 31.464689 1.611366\n", + "C 14.116395 31.289997 2.423572\n", + "C 13.685777 30.915122 3.663719\n", + "C 12.252381 30.861042 3.608186\n", + "C 10.062170 30.463021 4.634102\n", + "C 9.236749 30.104333 5.755782\n", + "C 7.945687 30.161198 5.324720\n", + "C 7.989641 30.552269 3.941498\n", + "C 6.892881 31.087489 1.815829\n", + "C 5.722676 31.253502 1.001149\n", + "C 6.153153 31.631057 -0.238233\n", + "C 7.586010 31.695401 -0.179773\n", + "C 8.390724 32.047572 -1.247553\n", + "H 7.903308 32.291586 -2.187969\n", + "C 12.973334 31.849872 0.283741\n", + "H 13.944682 32.031190 -0.169145\n", + "C 11.447158 30.518591 4.678739\n", + "H 11.934423 30.277429 5.619969\n", + "C 6.864795 30.711643 3.146118\n", + "H 5.893357 30.532078 3.599511\n", + "H 12.800139 32.636412 -2.439296\n", + "H 10.224017 32.743662 -3.301293\n", + "H 15.131785 31.441247 2.076257\n", + "H 14.273933 30.694315 4.546802\n", + "H 9.612512 29.848040 6.739754\n", + "H 7.036117 29.960530 5.879248\n", + "H 4.707408 31.099933 1.347803\n", + "H 5.564992 31.851940 -1.121294\n", + "N 9.666041 36.091609 3.085945\n", + "O 9.598728 37.226756 3.411299\n", + "\"\"\"\n", + "\n", + "str_geometries = {\n", + " \"1.75\": geometry_1_75,\n", + " \"2.00\": geometry_2_00,\n", + " \"5.00\": geometry_5_00,\n", + "}\n", + "\n", + "\n", + "hivqe_result = {}" + ] + }, { "cell_type": "markdown", "id": "5ed92d44", From f1708c4fdc1b64c7a3c3113c9169df955445cbeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:06:03 +0900 Subject: [PATCH 11/59] Remove the geometry cell that appears twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 134-line geometry_1_75 block is defined twice in a row in Part 2, byte for byte identical, differing only in cell id. Running the notebook is unaffected — the second assignment just repeats the first — so the cost falls entirely on whoever reads it and has to work out whether the two blocks differ. It has been there since the tutorial was added to this repository in cc50fd0782 (2025-04-15), where the file arrives as a single addition with no prior history, so it came in with the notebook rather than from any edit here. Twenty-five commits have passed over it since, including our own tutorial fix in 326fbbea51. The copy kept is the first, which is the one the markdown above it introduces. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 153 ------------------------------ 1 file changed, 153 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 4b7ddf5ff8c2..91268e4bf27b 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -818,159 +818,6 @@ "hivqe_result = {}" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "52b55a07", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'5.0': '\\nFe 9.918629 31.289202 1.717339\\nN 10.542914 31.832173 -0.080685\\nN 11.795572 31.199413 2.341831\\nN 9.294593 30.741247 3.513929\\nN 8.042689 31.359481 1.087282\\nC 9.775254 32.111817 -1.200449\\nC 10.600219 32.479101 -2.319680\\nC 11.891090 32.425876 -1.887580\\nC 11.847694 32.024341 -0.507342\\nC 12.945734 31.464689 1.611366\\nC 14.116395 31.289997 2.423572\\nC 13.685777 30.915122 3.663719\\nC 12.252381 30.861042 3.608186\\nC 10.062170 30.463021 4.634102\\nC 9.236749 30.104333 5.755782\\nC 7.945687 30.161198 5.324720\\nC 7.989641 30.552269 3.941498\\nC 6.892881 31.087489 1.815829\\nC 5.722676 31.253502 1.001149\\nC 6.153153 31.631057 -0.238233\\nC 7.586010 31.695401 -0.179773\\nC 8.390724 32.047572 -1.247553\\nH 7.903308 32.291586 -2.187969\\nC 12.973334 31.849872 0.283741\\nH 13.944682 32.031190 -0.169145\\nC 11.447158 30.518591 4.678739\\nH 11.934423 30.277429 5.619969\\nC 6.864795 30.711643 3.146118\\nH 5.893357 30.532078 3.599511\\nH 12.800139 32.636412 -2.439296\\nH 10.224017 32.743662 -3.301293\\nH 15.131785 31.441247 2.076257\\nH 14.273933 30.694315 4.546802\\nH 9.612512 29.848040 6.739754\\nH 7.036117 29.960530 5.879248\\nH 4.707408 31.099933 1.347803\\nH 5.564992 31.851940 -1.121294\\nN 9.666041 36.091609 3.085945\\nO 9.598728 37.226756 3.411299\\n'}" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "geometry_1_75 = \"\"\"\n", - "Fe 9.910596 31.534095 1.798088\n", - "N 10.557481 31.888419 -0.055204\n", - "N 11.823496 31.255002 2.384659\n", - "N 9.292831 30.783362 3.568730\n", - "N 8.036805 31.418327 1.124265\n", - "C 9.784765 32.177349 -1.158798\n", - "C 10.612656 32.501029 -2.296868\n", - "C 11.903375 32.404043 -1.876832\n", - "C 11.859093 32.028943 -0.483750\n", - "C 12.965737 31.464698 1.641427\n", - "C 14.146517 31.236323 2.440231\n", - "C 13.713061 30.885870 3.681911\n", - "C 12.268752 30.896411 3.634891\n", - "C 10.067717 30.486167 4.664747\n", - "C 9.246224 30.053411 5.772052\n", - "C 7.957075 30.082846 5.336488\n", - "C 7.995710 30.538421 3.967046\n", - "C 6.900258 31.104497 1.836595\n", - "C 5.722470 31.251707 1.015333\n", - "C 6.148430 31.668586 -0.207993\n", - "C 7.587039 31.767438 -0.130483\n", - "C 8.399453 32.134197 -1.192329\n", - "H 7.912872 32.388031 -2.131079\n", - "C 12.984883 31.836053 0.306093\n", - "H 13.955948 31.977044 -0.162626\n", - "C 11.453768 30.560663 4.708020\n", - "H 11.940677 30.298823 5.644352\n", - "C 6.877071 30.697580 3.164102\n", - "H 5.907240 30.476797 3.603674\n", - "H 12.813946 32.569160 -2.441577\n", - "H 10.236332 32.758110 -3.280309\n", - "H 15.164312 31.335191 2.080201\n", - "H 14.299625 30.629109 4.556760\n", - "H 9.626524 29.758225 6.743433\n", - "H 7.053076 29.823583 5.875809\n", - "H 4.709768 31.058315 1.350561\n", - "H 5.561898 31.886355 -1.093106\n", - "N 9.832739 33.209042 2.298783\n", - "O 9.346337 34.075996 1.606023\n", - "\"\"\"\n", - "\n", - "geometry_2_00 = \"\"\"\n", - "Fe 9.917990 31.445558 1.778346\n", - "N 10.556809 31.866188 -0.055498\n", - "N 11.814089 31.227003 2.372666\n", - "N 9.297875 30.758246 3.550104\n", - "N 8.043584 31.397768 1.120485\n", - "C 9.784831 32.164652 -1.160219\n", - "C 10.611624 32.501801 -2.293514\n", - "C 11.902858 32.406547 -1.875160\n", - "C 11.859552 32.017818 -0.486307\n", - "C 12.960503 31.454432 1.636717\n", - "C 14.140770 31.242960 2.439615\n", - "C 13.708543 30.884151 3.678983\n", - "C 12.266351 30.874173 3.627468\n", - "C 10.070264 30.465070 4.655102\n", - "C 9.247247 30.053101 5.766681\n", - "C 7.958085 30.091201 5.332866\n", - "C 7.998432 30.529979 3.958727\n", - "C 6.901428 31.093932 1.833807\n", - "C 5.723289 31.255057 1.016540\n", - "C 6.151314 31.670649 -0.206350\n", - "C 7.589736 31.755538 -0.133074\n", - "C 8.400230 32.124963 -1.194447\n", - "H 7.913264 32.386655 -2.130914\n", - "C 12.983905 31.827747 0.302415\n", - "H 13.955696 31.979687 -0.161365\n", - "C 11.454251 30.533644 4.698234\n", - "H 11.941002 30.276716 5.636156\n", - "C 6.877444 30.689985 3.159940\n", - "H 5.907605 30.480118 3.604825\n", - "H 12.813105 32.581608 -2.437367\n", - "H 10.233725 32.768337 -3.273979\n", - "H 15.157796 31.357524 2.082132\n", - "H 14.295001 30.638320 4.557047\n", - "H 9.626721 29.768762 6.741623\n", - "H 7.051752 29.847502 5.875478\n", - "H 4.709710 31.071712 1.354640\n", - "H 5.565103 31.898376 -1.089333\n", - "N 9.840508 33.353531 2.373019\n", - "O 9.344561 34.158205 1.637232\n", - "\"\"\"\n", - "\n", - "geometry_5_00 = \"\"\"\n", - "Fe 9.918629 31.289202 1.717339\n", - "N 10.542914 31.832173 -0.080685\n", - "N 11.795572 31.199413 2.341831\n", - "N 9.294593 30.741247 3.513929\n", - "N 8.042689 31.359481 1.087282\n", - "C 9.775254 32.111817 -1.200449\n", - "C 10.600219 32.479101 -2.319680\n", - "C 11.891090 32.425876 -1.887580\n", - "C 11.847694 32.024341 -0.507342\n", - "C 12.945734 31.464689 1.611366\n", - "C 14.116395 31.289997 2.423572\n", - "C 13.685777 30.915122 3.663719\n", - "C 12.252381 30.861042 3.608186\n", - "C 10.062170 30.463021 4.634102\n", - "C 9.236749 30.104333 5.755782\n", - "C 7.945687 30.161198 5.324720\n", - "C 7.989641 30.552269 3.941498\n", - "C 6.892881 31.087489 1.815829\n", - "C 5.722676 31.253502 1.001149\n", - "C 6.153153 31.631057 -0.238233\n", - "C 7.586010 31.695401 -0.179773\n", - "C 8.390724 32.047572 -1.247553\n", - "H 7.903308 32.291586 -2.187969\n", - "C 12.973334 31.849872 0.283741\n", - "H 13.944682 32.031190 -0.169145\n", - "C 11.447158 30.518591 4.678739\n", - "H 11.934423 30.277429 5.619969\n", - "C 6.864795 30.711643 3.146118\n", - "H 5.893357 30.532078 3.599511\n", - "H 12.800139 32.636412 -2.439296\n", - "H 10.224017 32.743662 -3.301293\n", - "H 15.131785 31.441247 2.076257\n", - "H 14.273933 30.694315 4.546802\n", - "H 9.612512 29.848040 6.739754\n", - "H 7.036117 29.960530 5.879248\n", - "H 4.707408 31.099933 1.347803\n", - "H 5.564992 31.851940 -1.121294\n", - "N 9.666041 36.091609 3.085945\n", - "O 9.598728 37.226756 3.411299\n", - "\"\"\"\n", - "\n", - "str_geometries = {\n", - " \"1.75\": geometry_1_75,\n", - " \"2.00\": geometry_2_00,\n", - " \"5.00\": geometry_5_00,\n", - "}\n", - "\n", - "\n", - "hivqe_result = {}" - ] - }, { "cell_type": "markdown", "id": "5ed92d44", From b4e5a464387a104e67f89cf5e0684e7e30d42bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:16:31 +0900 Subject: [PATCH 12/59] Give each part its own names for its own data str_geometries meant three different things, hivqe_result three, and rhf_result, casci_result, molecule_options and hivqe_options two each. Run top to bottom the notebook is correct, but notebooks are not read or run that way: going back to Part 1's plotting cell after Part 2 draws Part 1's classical reference against Part 2's HI-VQE energies, about a thousand hartree apart, with no error to say so. Going back to Part 1's submission loop would submit Li2S geometries with Part 2's 631g* basis and 22 active orbitals, which costs money. Part 1 keeps the plain names. The 34-geometry grid in its Step 4 becomes ref_geometries, since only the classical reference uses it. Everything Part 2 owns takes a _fepno suffix. Renames were applied per cell rather than globally, and checked by walking the code cells in order and resolving every name each one reads against what earlier cells define: no name is undefined before or after, so nothing lost its reference. The plotting cells' own temporaries (hf_energy, distance and the rest) are recomputed from the dictionaries in each cell and are left alone. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 52 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 91268e4bf27b..8a009e21e61e 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -461,7 +461,7 @@ "metadata": {}, "outputs": [], "source": [ - "str_geometries = {\n", + "ref_geometries = {\n", " \"1.31\": \"S -1.250686 0.660708 -0.095168; Li -1.482812 0.453464 -1.369406; Li -0.911870 0.962810 1.762020\",\n", " \"1.41\": \"S -1.244856 0.665971 -0.062773; Li -1.494574 0.442933 -1.434177; Li -0.905937 0.968078 1.794395\",\n", " \"1.51\": \"S -1.239044 0.671232 -0.030374; Li -1.506327 0.432403 -1.498949; Li -0.899996 0.973348 1.826768\",\n", @@ -552,7 +552,7 @@ "\n", "cas_list = molecule_options[\"active_orbitals\"]\n", "distance_ref = []\n", - "for dis, geom in str_geometries.items():\n", + "for dis, geom in ref_geometries.items():\n", " distance_ref.append(dis)\n", " mole = gto.M(atom=geom, basis=molecule_options[\"basis\"])\n", " mole.verbose = 0\n", @@ -640,14 +640,14 @@ "metadata": {}, "outputs": [], "source": [ - "molecule_options = {\n", + "molecule_options_fepno = {\n", " \"basis\": \"631g*\",\n", " \"active_orbitals\": list(range(90, 112, 1)),\n", " \"frozen_orbitals\": list(range(0, 90, 1)),\n", " \"charge\": -1,\n", "}\n", "\n", - "hivqe_options = {\n", + "hivqe_options_fepno = {\n", " \"shots\": 2000,\n", " \"max_iter\": 40,\n", " \"ansatz\": \"epa\",\n", @@ -808,14 +808,14 @@ "O 9.598728 37.226756 3.411299\n", "\"\"\"\n", "\n", - "str_geometries = {\n", + "fepno_geometries = {\n", " \"1.75\": geometry_1_75,\n", " \"2.00\": geometry_2_00,\n", " \"5.00\": geometry_5_00,\n", "}\n", "\n", "\n", - "hivqe_result = {}" + "hivqe_result_fepno = {}" ] }, { @@ -844,13 +844,13 @@ "outputs": [], "source": [ "hivqe_run_1_75 = hivqe.run(\n", - " geometry=str_geometries[\"1.75\"],\n", + " geometry=fepno_geometries[\"1.75\"],\n", " backend_name=\"\",\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options_fepno=molecule_options_fepno,\n", + " hivqe_options_fepno=hivqe_options_fepno,\n", ")\n", "info_jobid_1_75 = hivqe_run_1_75.job_id" ] @@ -876,7 +876,7 @@ "if stat == \"DONE\":\n", " hivqe_run_1_75_energy = submitted_job_1_75.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_1_75_energy}\")\n", - " hivqe_result[\"1.75\"] = hivqe_run_1_75_energy" + " hivqe_result_fepno[\"1.75\"] = hivqe_run_1_75_energy" ] }, { @@ -895,13 +895,13 @@ "outputs": [], "source": [ "hivqe_run_2_00 = hivqe.run(\n", - " geometry=str_geometries[\"2.00\"],\n", + " geometry=fepno_geometries[\"2.00\"],\n", " backend_name=\"\",\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options_fepno=molecule_options_fepno,\n", + " hivqe_options_fepno=hivqe_options_fepno,\n", ")\n", "info_jobid_2_00 = hivqe_run_2_00.job_id" ] @@ -927,7 +927,7 @@ "if stat == \"DONE\":\n", " hivqe_run_2_00_energy = submitted_job_2_00.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_2_00_energy}\")\n", - " hivqe_result[\"2.00\"] = hivqe_run_2_00_energy" + " hivqe_result_fepno[\"2.00\"] = hivqe_run_2_00_energy" ] }, { @@ -946,13 +946,13 @@ "outputs": [], "source": [ "hivqe_run_5_00 = hivqe.run(\n", - " geometry=str_geometries[\"5.00\"],\n", + " geometry=fepno_geometries[\"5.00\"],\n", " backend_name=\"\",\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options_fepno=molecule_options_fepno,\n", + " hivqe_options_fepno=hivqe_options_fepno,\n", ")\n", "info_jobid_5_00 = hivqe_run_5_00.job_id" ] @@ -978,7 +978,7 @@ "if stat == \"DONE\":\n", " hivqe_run_5_00_energy = submitted_job_5_00.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_5_00_energy}\")\n", - " hivqe_result[\"5.00\"] = hivqe_run_5_00_energy" + " hivqe_result_fepno[\"5.00\"] = hivqe_run_5_00_energy" ] }, { @@ -988,7 +988,7 @@ "metadata": {}, "outputs": [], "source": [ - "hivqe_result = {\n", + "hivqe_result_fepno = {\n", " \"1.75\": -2373.681781,\n", " \"2.00\": -2373.694128,\n", " \"5.00\": -2373.637807,\n", @@ -1012,12 +1012,12 @@ "metadata": {}, "outputs": [], "source": [ - "rhf_result = {\n", + "rhf_result_fepno = {\n", " \"1.75\": -2373.59331683504,\n", " \"2.00\": -2373.60640773065,\n", " \"5.00\": -2373.50214278007,\n", "}\n", - "casci_result = {\"1.75\": -2373.6827, \"2.00\": -2373.6948, \"5.00\": -2373.6393}" + "casci_result_fepno = {\"1.75\": -2373.6827, \"2.00\": -2373.6948, \"5.00\": -2373.6393}" ] }, { @@ -1043,11 +1043,11 @@ ], "source": [ "fig, ax = plt.subplots(1, 1)\n", - "hf_energy = [v for key, v in rhf_result.items()]\n", - "casci_energy = [v for key, v in casci_result.items()]\n", - "hivqe_energy = [v for key, v in hivqe_result.items()]\n", - "distance_ref = [float(key) for key, v in rhf_result.items()]\n", - "distance = [float(key) for key, v in hivqe_result.items()]\n", + "hf_energy = [v for key, v in rhf_result_fepno.items()]\n", + "casci_energy = [v for key, v in casci_result_fepno.items()]\n", + "hivqe_energy = [v for key, v in hivqe_result_fepno.items()]\n", + "distance_ref = [float(key) for key, v in rhf_result_fepno.items()]\n", + "distance = [float(key) for key, v in hivqe_result_fepno.items()]\n", "\n", "ax.plot(distance_ref, hf_energy, \"-o\", label=\"RHF\", c=\"blue\")\n", "ax.plot(distance_ref, casci_energy, \"-o\", label=\"CASCI\", c=\"green\")\n", From cb6b97856425cd4e17bc96f8b5a27195d466671f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:19:26 +0900 Subject: [PATCH 13/59] Say what the hardcoded energies are for Part 2's results cell assigns three literal energies with no cell above it to say why, right after three cells that collect the real ones. A reader who waited for their own jobs sees their values replaced and no reason given. They are there so Step 4 works without waiting, which is also why the classical reference in Step 4 is provided rather than computed. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 8a009e21e61e..244a442f2db3 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -981,6 +981,15 @@ " hivqe_result_fepno[\"5.00\"] = hivqe_run_5_00_energy" ] }, + { + "cell_type": "markdown", + "id": "1c0606d4-088a-4999-bf16-cb6b87637652", + "metadata": {}, + "source": [ + "The energies from these three runs, so that the comparison below works\n", + "without waiting for your own jobs. Skip this cell to use your own." + ] + }, { "cell_type": "code", "execution_count": null, From c90b5287785990c585963039fb0c60aead77d1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:30:43 +0900 Subject: [PATCH 14/59] List function_size where the arguments are listed It had a top-level section of its own between Inputs and Outputs, which no reader scanning Inputs for what they can pass would find: they would conclude the argument does not exist. Every other function API reference in this repository is Inputs and Outputs, with one exception that adds Error handling, so a third section is also not the shape of these pages. It is now an Attribute among the others, with "m" as its documented default the way the other arguments carry theirs. Whose argument it is survives as a clause; it changes nothing about how a reader passes it. Co-Authored-By: Claude Opus 5 (1M context) --- docs/api/functions/qunova-chemistry.mdx | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 13e45aac5bf5..f7f117339496 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -232,11 +232,11 @@ Size the problem and return without running it. The response contains an - Example: `True` -## Function size - -`function_size` is an argument of the platform rather than of this function, -passed to `run()` alongside the arguments above. It selects the resources the -job runs on, and it is what the run is billed at. +### `function_size` + +Which resources the job runs on, and what the run is billed. It is passed to +`run()` like the arguments above, though it belongs to the platform rather than +to this function. | `function_size` | Qubits | Compute profile | License fee per run | |-----|-----|-----|-----| @@ -244,12 +244,14 @@ job runs on, and it is what the run is billed at. | `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | | `"l"` | No limit | 48 CPUs, 768 GB | 4.0 RU | -Jobs submitted without it run at `"m"`. A size smaller than the problem needs -is rejected before any QPU time is spent, with error code 1221 naming the size -to use. A size larger than it needs runs, and is billed at that larger size. - -Runs made with a license token are not subject to this check, and are instead -bounded by the qubit limit the license grants. +A size smaller than the problem needs is rejected before any QPU time is +spent, with error code 1221 naming the size to use. A size larger than it +needs runs, and is billed at that larger size. Runs made with a license token +are not checked against the problem, and are bounded by the qubit limit the +license grants instead. +- Required: No +- Example: `"l"` + ## Outputs From 40eda6489af9c714db6b5787b2970fe8c352d606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:51:05 +0900 Subject: [PATCH 15/59] Say what to do when the function is not in the catalog The next cell tells the reader to check they have access to the function, and until now the answer to "I don't" was the request-access form, which is for licenses. What they actually need is Qiskit Functions access enabled on their instance, which they do themselves when they create it, and which IBM's own guide documents. The sentence goes before the step that saves the key, so the paragraph ending in "as follows:" is still the one the code cell follows. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index b83bf70ffcd0..5e50e7da28a2 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -137,6 +137,8 @@ "\n", "Runs are billed per execution at the function size you choose, with no qubit limit; see [Limits and billing](#limits-and-billing). If you hold or need a license, see [Licensed use](#licensed-use).\n", "\n", + "The instance you authenticate with needs [Qiskit Functions access enabled](/docs/guides/access-instances-platform-apis#configure-qiskit-functions-access-on-an-instance), or the function will not appear in the catalog.\n", + "\n", "Save your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) [to your local environment](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) if you have not already, then select the Qiskit Function as follows:" ] }, From bcce1835b22c46e67ab1f535c83141216ee83191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:54:16 +0900 Subject: [PATCH 16/59] Give both parts the same steps Part 1 had a fourth heading, "Plotting the dissociation curve", that Part 2 does not: its plot sits inside Step 4, where it belongs, since Step 4 is already "post-process and compare with classical methods" and the plot is that comparison. In the contents the two parts looked like different procedures. Only the heading line is gone; the two sentences under it say what the plot shows and stay where they were. The "Step 2 and 3" numbering stays. Other tutorials in this repository number the four pattern steps separately because their reader optimizes a circuit and then executes it; here one function call does both, so splitting it would leave an empty step. Co-Authored-By: Claude Opus 5 (1M context) --- docs/tutorials/qunova-hivqe.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 244a442f2db3..5766e0057dc0 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -578,8 +578,6 @@ "id": "e1900a94", "metadata": {}, "source": [ - "### Plotting the dissociation curve for Li\\_2S\n", - "\n", "Let's plot and compare HiVQE results with HF and CASCI.\n", "You can observe that all HiVQE calculations are well-matched with the classical reference result (CASCI)." ] From 7c013ffbde952b6ca40bc7d6c2f5806cdddb6de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 15:59:38 +0900 Subject: [PATCH 17/59] Build the catalog the same way in both examples MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first example read a saved API key; the licensed example passed the key and the instance inline. Both work, and which you use has nothing to do with holding a license — but having one shape in the usage-based example and the other in the licensed one made it look as though it did, and left a reader wondering whether a license needs an explicit token or instance. Now the only difference between the two examples is the line that wraps the function, which is the only difference there is. It also leaves one meaning of "token" in that cell: the HI-VQE license token, rather than that and the IBM API key together. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 5e50e7da28a2..792a1a0fe62d 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -604,11 +604,7 @@ "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n", "from hivqe_qiskit_function_utils import FunctionWrapper\n", "\n", - "catalog = QiskitFunctionsCatalog(\n", - " token=\"your_qiskit_functions_catalog_token\",\n", - " channel=\"ibm_quantum_platform\",\n", - " instance=\"your_ibm_instance\",\n", - ")\n", + "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n", "\n", "molecule_geometry = f\"\"\"\n", "O 0 0 0;\n", From 454169f4454057cf0e05d3e7fe1b7dd446c205ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84/Seihyun=20Jeong/qunova?= Date: Tue, 6 Oct 2026 17:40:31 +0900 Subject: [PATCH 18/59] Report a license we cannot read as 4630 IBM reserved 4630-4639 for this function. The four failures that used to report 1219 are not about the reader's IBM credentials, which is what 1219 says, and not about their license token being wrong either: we cannot read it at our end. The table now says so, and says the reader did nothing wrong. Co-Authored-By: Claude Opus 5 (1M context) --- docs/guides/qunova-chemistry.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 792a1a0fe62d..c04d53f4f750 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -841,11 +841,11 @@ "| --- | --- |\n", "| 1007 | The `backend_name` you gave does not exist, or is not available to you |\n", "| 1201 | A license token was supplied but no matching license was found |\n", - "| 1219 | A license token was found but could not be read |\n", "| 1221 | An argument did not validate, or `function_size` was too small for the problem. The message names the size to use |\n", "| 1500 | Something unexpected went wrong. Quote the job ID when you report it |\n", "| 2409 | The license has expired, has been revoked, or was used from an instance it was not issued for |\n", "| 4500 | The problem needs more qubits than your license or trial access allows |\n", + "| 4630 | Your license could not be read. Nothing is wrong with what you submitted; contact us with the job ID |\n", "\n", "Several codes cover more than one cause, so read the message as well as the\n", "code. If you need help with a failure, send the Function job ID to\n", From afbedf0e61139070de526c11a231a036e3f99351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 10:54:01 +0900 Subject: [PATCH 19/59] Update the HI-VQE docs for the 4.0.0 function In 4.0.0 the result no longer carries "states" or "eigenvector". They are written to an HDF5 results file instead, alongside "final_energy", "final_energy_variance" and "energy_history". The result names that file in "results_file_name". - API reference: drop "states" and "eigenvector" from the result table, add "results_file_name", and point "energy_variance" at the states in the results file. - Guide: show the 4.0.0 result, list what the results file holds, and add examples that create a QiskitServerless client, download the file and read it with h5py. Add a Changelog section that starts at 4.0.0. - Tutorial: install h5py, and download and read the results file for each calculation. Co-authored-by: Shane McFarthing Co-authored-by: Rowan Pellow-Jarman Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 5 +- docs/guides/qunova-chemistry.ipynb | 86 +++++++++++++++++++++++-- docs/tutorials/qunova-hivqe.ipynb | 79 ++++++++++++++++++++++- 3 files changed, 158 insertions(+), 12 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 773d70af0260..cf2cc742652e 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -234,7 +234,6 @@ The function returns a dictionary with four keys and values. The keys and values | Key | Value Type| Explanation | |-----|---------------|---------------------------------------------------------------------------------------------------------------------------| | `"energy"` | `float` | The approximate ground state energy of the molecule. | -| `"states"` | `List[str]` | The selected determinants that form the subspace used to solve for the energy. They are in alternating alpha-beta format. | -| `"eigenvector"` | `List[float]` | The eigenvector corresponding to the ground state of the subspace composed of `"states"`.| -| `"energy_variance"` | `float` | The energy variance of the ground state of the subspace composed of `"states"`, giving an indication of the quality of the solution. This value is non-negative and a lower value means that the ground state of the subspace more closely approximates an eigenstate of the system's Hamiltonian. | +| `"results_file_name"` | `string` | The name of the hdf5 results file that can be downloaded using Qiskit Serverless. The file contains `"states"`, `"eigenvector"`, `"energy_history"`, `"final_energy"`, and `"final_energy_variance"`. | +| `"energy_variance"` | `float` | The energy variance of the ground state of the subspace composed of the `"states"` saved in the results file, giving an indication of the quality of the solution. This value is non-negative and a lower value means that the ground state of the subspace more closely approximates an eigenstate of the system's Hamiltonian. | | `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | \ No newline at end of file diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 1807b90fe9e0..3e970ef06f32 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -11,7 +11,7 @@ "---\n", "\n", "\n", - "{/* cspell:ignore lumo hivqe DMRG ccsd, ffsim, pvdz, Qunova, HI-VQE, AVAS, Dooh, pyscf, nucmod, GTO's, lucj, pseudopotential, pseudopotentials, magmom, Jastrow, multireference, Pellow, Jarman */}" + "{/* cspell:ignore asstr lumo hivqe DMRG ccsd, ffsim, pvdz, Qunova, HI-VQE, AVAS, Dooh, pyscf, nucmod, GTO's, lucj, pseudopotential, pseudopotentials, magmom, Jastrow, multireference, Pellow, Jarman */}" ] }, { @@ -348,7 +348,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'eigenvector': [0.9824448589364075, 0.009527106392132133, 6.854074372058527e-08, 3.591500190038039e-07, 0.0012975231577544268, 2.310159709002111e-05, ...], 'energy': -55.52108557170985, 'energy_history': [-55.51901898989887, -55.52056881448526, -55.52065046778772, -55.520690696813716, -55.520691108428, -55.520708448092634, ...], 'energy_variance': 3.066239097617371e-10, ...}\n" + "{'energy': -55.52108557170985, 'energy_history': [-55.51901898989887, -55.52056881448526, -55.52065046778772, -55.520690696813716, -55.520691108428, -55.520708448092634, ...], 'energy_variance': 3.066239097617371e-10, 'results_file_name': '20260914_105...vqe_result.h5'}\n" ] } ], @@ -365,7 +365,14 @@ "id": "2b6fb05c", "metadata": {}, "source": [ - "To access the ground state energy, use the \"energy\" key. The \"eigenvector\" key provides the CI coefficients with corresponding bitstring notation of electron configuration stored with \"states\" of the results." + "To access the ground state energy, use the `\"energy\"` key. The `\"results_file_name\"` key provides the name of the h5 results file that can be downloaded using `QiskitServerless`.\n", + "\n", + "This file contains :\n", + "- `\"final_energy\"`: the energy of the final trial state,\n", + "- `\"final_energy_variance\"`: the energy variance of the final trial state,\n", + "- `\"energy_history\"`: the energy history over HI-VQE's training,\n", + "- `\"eigenvector\"`: the CI coefficients of the final trial state's wave function, and\n", + "- `\"states\"`: the corresponding electron configurations comprising the final trial state wave function." ] }, { @@ -378,8 +385,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "|Exact Energy - HI-VQE Energy|: 0.06246299427914437 mHa\n", - "Sampled Number of States: 1936\n" + "|Exact Energy - HI-VQE Energy|: 0.06246299427914437 mHa\n" ] } ], @@ -389,8 +395,61 @@ "print(\n", " f\"|Exact Energy - HI-VQE Energy|: \"\n", " f\"{abs(fci_energy - hivqe_energy) * 1000} mHa\"\n", - ")\n", - "print(f\"Sampled Number of States: {len(result['states'])}\")" + ")" + ] + }, + { + "cell_type": "markdown", + "id": "03b51be7", + "metadata": {}, + "source": [ + "To download the results file for the calculation, you will need to create a `QiskitServerless` instance using the same credentials as `QiskitFunctionCatalog`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fbe0d8f6", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit_ibm_catalog import QiskitServerless\n", + "\n", + "serverless = QiskitServerless(\n", + " channel=\"ibm_quantum_platform\",\n", + " instance=\"INSTANCE_CRN\",\n", + " token=\"YOUR_API_KEY\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0a081159", + "metadata": {}, + "source": [ + "The file can then be downloaded to the current directory and opened as shown below. Reading it requires the `h5py` package, which you can install with `pip install h5py`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ea7cacc", + "metadata": {}, + "outputs": [], + "source": [ + "import h5py\n", + "\n", + "# The file is saved in the current directory under the same name\n", + "results_file_name = result[\"results_file_name\"]\n", + "serverless.file_download(results_file_name, function)\n", + "\n", + "# Read data from the results file for a single calculation\n", + "with h5py.File(results_file_name, \"r\") as f:\n", + " states = f[\"states\"].asstr()[:]\n", + " eigenvector = f[\"eigenvector\"][:]\n", + " energy_history = f[\"energy_history\"][:]\n", + " final_energy = f[\"final_energy\"][0]\n", + " final_energy_variance = f[\"final_energy_variance\"][0]" ] }, { @@ -649,6 +708,19 @@ "job.status()" ] }, + { + "cell_type": "markdown", + "id": "7c1e4a2b", + "metadata": {}, + "source": [ + "## Changelog\n", + "\n", + "### 4.0.0\n", + "\n", + "- The result no longer includes `\"states\"` or `\"eigenvector\"`. They are now saved in an HDF5 results file, together with `\"final_energy\"`, `\"final_energy_variance\"`, and `\"energy_history\"`.\n", + "- Added `\"results_file_name\"` to the result. It gives the name of the results file, which you can download with `serverless.file_download()`. Reading the file requires the `h5py` package. See the [Example](#example) section for how to download and read it." + ] + }, { "cell_type": "markdown", "id": "e9ec2e67", diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 76a0638d1faa..da02a45ce223 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -11,7 +11,7 @@ "---\n", "\n", "\n", - "{/* cspell:ignore fontsize labelsize DMRG hivqe mcscf CASCI */}\n", + "{/* cspell:ignore asstr fontsize labelsize DMRG hivqe mcscf CASCI */}\n", "\n", "# Dissociation PES curves with Qunova HiVQE" ] @@ -62,7 +62,7 @@ "outputs": [], "source": [ "!pip install --upgrade pip\n", - "!pip install -U qiskit-ibm-catalog \"qiskit_ibm_runtime<0.42.0\" pyscf numpy matplotlib typing_extensions" + "!pip install -U qiskit-ibm-catalog \"qiskit_ibm_runtime<0.42.0\" pyscf numpy matplotlib typing_extensions h5py" ] }, { @@ -99,6 +99,30 @@ "hivqe = catalog.load(\"qunova/hivqe-chemistry\")" ] }, + { + "cell_type": "markdown", + "id": "00c68174", + "metadata": {}, + "source": [ + "You will also need to create a `QiskitServerless` instance to download the results file for the calculation. This uses the same credentials as `QiskitFunctionCatalog`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a0687f2", + "metadata": {}, + "outputs": [], + "source": [ + "from qiskit_ibm_catalog import QiskitServerless\n", + "\n", + "serverless = QiskitServerless(\n", + " channel=\"ibm_quantum_platform\",\n", + " instance=\"INSTANCE_CRN\",\n", + " token=\"YOUR_API_KEY\",\n", + ")" + ] + }, { "attachments": {}, "cell_type": "markdown", @@ -326,6 +350,57 @@ "pprint.pprint(hivqe_result)" ] }, + { + "cell_type": "markdown", + "id": "51a9e47b", + "metadata": {}, + "source": [ + "The results file for each of the calculations can be downloaded into the current directory using `QiskitServerless`. These files contain `\"states\"`, `\"eigenvector\"`, `\"energy_history\"`, `\"final_energy\"`, and `\"final_energy_variance\"`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "025c97ce", + "metadata": {}, + "outputs": [], + "source": [ + "if len(info_jobid) == completed_jobs_num:\n", + " print(\"All jobs are completed\")\n", + " for i, job in enumerate(completed_jobs.items()):\n", + " dis, cal = job\n", + " print(dis, cal.result()[\"results_file_name\"])\n", + " serverless.file_download(cal.result()[\"results_file_name\"], hivqe)" + ] + }, + { + "cell_type": "markdown", + "id": "7aee79ec", + "metadata": {}, + "source": [ + "The results can be read from the h5 file as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "058f92b1", + "metadata": {}, + "outputs": [], + "source": [ + "import h5py\n", + "\n", + "results_file_name = \"PATH_TO_DOWNLOADED_RESULTS_FILE\"\n", + "\n", + "# Read data from the results file for a single calculation\n", + "with h5py.File(results_file_name, \"r\") as f:\n", + " states = f[\"states\"].asstr()[:]\n", + " eigenvector = f[\"eigenvector\"][:]\n", + " energy_history = f[\"energy_history\"][:]\n", + " final_energy = f[\"final_energy\"][0]\n", + " final_energy_variance = f[\"final_energy_variance\"][0]" + ] + }, { "cell_type": "markdown", "id": "cc7c2793", From 28ae7f2cc8c8bfa50934983ac7eec85acc6b8383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 11:51:45 +0900 Subject: [PATCH 20/59] Pass FeP-NO's options to run() under the names it accepts b4e5a46438 renamed Part 2's option dictionaries to molecule_options_fepno and hivqe_options_fepno. The rename also changed the keyword names in the three FeP-NO run() calls, so they passed molecule_options_fepno= and hivqe_options_fepno=. The function does not accept those names. Its input check (qiskit_functions/ runner.py, "Check that all arguments the user supplied are recognized") rejects any unknown argument with InputValidationError, code 1221, in every released version from 4.0.1 to 5.0.2. All of Part 2 would therefore fail before anything ran. The keywords are back to molecule_options= and hivqe_options=. The values keep Part 2's own dictionaries. Checked every run() call in the tutorial and the guide against the function's accepted arguments and option names. All nine match. Co-Authored-By: Claude Opus 5.5 --- docs/tutorials/qunova-hivqe.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 5766e0057dc0..4fe53cc24601 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -847,8 +847,8 @@ " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options_fepno=molecule_options_fepno,\n", - " hivqe_options_fepno=hivqe_options_fepno,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_1_75 = hivqe_run_1_75.job_id" ] @@ -898,8 +898,8 @@ " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options_fepno=molecule_options_fepno,\n", - " hivqe_options_fepno=hivqe_options_fepno,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_2_00 = hivqe_run_2_00.job_id" ] @@ -949,8 +949,8 @@ " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options_fepno=molecule_options_fepno,\n", - " hivqe_options_fepno=hivqe_options_fepno,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_5_00 = hivqe_run_5_00.job_id" ] From e20928ac4d358d505f30d6006e6dd03fdc4249d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 12:03:51 +0900 Subject: [PATCH 21/59] Save the HI-VQE results file under its own name before opening it The guide downloaded the results file with serverless.file_download(results_file_name, function) and then opened results_file_name. That fails with FileNotFoundError: without target_name, qiskit-serverless saves the file as downloaded_<8 hex>_ (qiskit_serverless/core/files.py, 0.36.0). The comment above the call, "saved ... under the same name", was wrong for the same reason. Pass target_name=results_file_name so the file lands under the name the next line opens, and make the comment say what the call does. The tutorial still asks for the path by hand and is left alone for now. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 3e970ef06f32..8a6a4b59c27d 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -439,9 +439,11 @@ "source": [ "import h5py\n", "\n", - "# The file is saved in the current directory under the same name\n", + "# Save the file in the current directory under its own name\n", "results_file_name = result[\"results_file_name\"]\n", - "serverless.file_download(results_file_name, function)\n", + "serverless.file_download(\n", + " results_file_name, function, target_name=results_file_name\n", + ")\n", "\n", "# Read data from the results file for a single calculation\n", "with h5py.File(results_file_name, \"r\") as f:\n", From e55a44a1f0194085e478ff7e2b13f17d746a7038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 12:03:51 +0900 Subject: [PATCH 22/59] Save the HI-VQE results file under its own name before opening it The guide downloaded the results file with serverless.file_download(results_file_name, function) and then opened results_file_name. That fails with FileNotFoundError: without target_name, qiskit-serverless saves the file as downloaded_<8 hex>_ (qiskit_serverless/core/files.py, 0.36.0). The comment above the call, "saved ... under the same name", was wrong for the same reason. Pass target_name=results_file_name so the file lands under the name the next line opens, and make the comment say what the call does. The tutorial still asks for the path by hand and is left alone for now. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index c04d53f4f750..b07c9bcabe20 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -457,9 +457,11 @@ "source": [ "import h5py\n", "\n", - "# The file is saved in the current directory under the same name\n", + "# Save the file in the current directory under its own name\n", "results_file_name = result[\"results_file_name\"]\n", - "serverless.file_download(results_file_name, function)\n", + "serverless.file_download(\n", + " results_file_name, function, target_name=results_file_name\n", + ")\n", "\n", "# Read data from the results file for a single calculation\n", "with h5py.File(results_file_name, \"r\") as f:\n", From de8f74b79a67a5a887b15af50aa3136fbf031593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 13:54:29 +0900 Subject: [PATCH 23/59] Let the HI-VQE licence example run on the reader's own backend The licensed-use example passed backend_name="ibm_torino". Current qiskit-ibm-catalog checks backend access before it submits a job, so on an instance without ibm_torino the example stops with "Backend 'ibm_torino' is not available or you do not have access to it". It now passes backend_name, as the rest of the guide does, with a comment giving the 14 qubits that H2O in STO-3G needs (7 orbitals). The example also built its catalog from token and instance placeholders, unlike "Get started", which uses the saved account. It now does the same: QiskitFunctionsCatalog(channel="ibm_quantum_platform"). Checked against production 4.0.0 from a test instance. With a placeholder licence token, the job reaches the function and is refused with TokenNotFoundError (1201), as expected. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 8a6a4b59c27d..11f3dc2dcda4 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -483,11 +483,7 @@ "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n", "from hivqe_qiskit_function_utils import FunctionWrapper\n", "\n", - "catalog = QiskitFunctionsCatalog(\n", - " token=\"your_qiskit_functions_catalog_token\",\n", - " channel=\"ibm_quantum_platform\",\n", - " instance=\"your_ibm_instance\",\n", - ")\n", + "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n", "\n", "molecule_geometry = f\"\"\"\n", "O 0 0 0;\n", @@ -501,7 +497,7 @@ ")\n", "job = hivqe.run(\n", " geometry=molecule_geometry,\n", - " backend_name=\"ibm_torino\",\n", + " backend_name=backend_name, # can use any device with at least 14 qubits\n", " max_states=10000,\n", " max_expansion_states=1000,\n", " hivqe_options={\"ansatz\": \"epa\", \"max_iter\": 10},\n", From a7918bb00bc46c34c0db592c2567464d31c53133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 13:54:50 +0900 Subject: [PATCH 24/59] Let the HI-VQE licence example run on the reader's own backend The licensed-use example passed backend_name="ibm_torino". Current qiskit-ibm-catalog checks backend access before it submits a job, so on an instance without ibm_torino the example stops with "Backend 'ibm_torino' is not available or you do not have access to it". It now passes backend_name, as the rest of the guide does, with a comment giving the 14 qubits that H2O in STO-3G needs (7 orbitals). Same change as de8f74b79a on hivqe-4.0.0. This branch already builds the catalog from the saved account, so only the backend changes here. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index b07c9bcabe20..d8bc7e897061 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -620,7 +620,7 @@ ")\n", "job = hivqe.run(\n", " geometry=molecule_geometry,\n", - " backend_name=\"ibm_torino\",\n", + " backend_name=backend_name, # can use any device with at least 14 qubits\n", " max_states=10000,\n", " max_expansion_states=1000,\n", " hivqe_options={\"ansatz\": \"epa\", \"max_iter\": 10},\n", From a639813fb57a9683f5b0dac3a86d3aefb8449c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 14:52:31 +0900 Subject: [PATCH 25/59] Document usage-based billing and the 5.0.x function The guide, tutorial and API reference described the 4.0.0 function. None of them mentioned function_size, estimate_only or resource_usage, and the guide told every reader that runs were limited to 20 qubits unless they held a license. Under 5.0.x, someone without a token has no qubit limit: they pick a function size and are billed per run. - API reference: document function_size (sizes, fees, and the fail-fast check), estimate_only and its response, and the function_version and metadata.resource_usage keys in the result. - Guide: add "Limits and billing", covering sizes, estimating before running, and resource usage, ahead of a "Licensed use" section. Pass function_size in the examples, and list the error codes the function returns. - Tutorial: submit at the size each part needs instead of describing FeP-NO as needing a license. Give each part its own variable names, so re-running cells out of order cannot mix Li2S and FeP-NO data. This is fork PR #3, moved onto hivqe-4.0.0 as one commit so that it reaches IBM as its own change after 4.0.0. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 53 ++++- docs/guides/qunova-chemistry.ipynb | 166 ++++++++++++++- docs/tutorials/qunova-hivqe.ipynb | 260 +++++++----------------- 3 files changed, 282 insertions(+), 197 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index cf2cc742652e..f7f117339496 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -224,16 +224,61 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` - - +### `estimate_only` + +Size the problem and return without running it. The response contains an +`"estimate"` dictionary instead of a result, and no QPU time is spent. +- Required: No +- Example: `True` + + +### `function_size` + +Which resources the job runs on, and what the run is billed. It is passed to +`run()` like the arguments above, though it belongs to the platform rather than +to this function. + +| `function_size` | Qubits | Compute profile | License fee per run | +|-----|-----|-----|-----| +| `"s"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU | +| `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | +| `"l"` | No limit | 48 CPUs, 768 GB | 4.0 RU | + +A size smaller than the problem needs is rejected before any QPU time is +spent, with error code 1221 naming the size to use. A size larger than it +needs runs, and is billed at that larger size. Runs made with a license token +are not checked against the problem, and are bounded by the qubit limit the +license grants instead. +- Required: No +- Example: `"l"` + ## Outputs -The function returns a dictionary with four keys and values. The keys and values are documented in the following table: +The function returns a dictionary with the following keys and values: | Key | Value Type| Explanation | |-----|---------------|---------------------------------------------------------------------------------------------------------------------------| | `"energy"` | `float` | The approximate ground state energy of the molecule. | | `"results_file_name"` | `string` | The name of the hdf5 results file that can be downloaded using Qiskit Serverless. The file contains `"states"`, `"eigenvector"`, `"energy_history"`, `"final_energy"`, and `"final_energy_variance"`. | | `"energy_variance"` | `float` | The energy variance of the ground state of the subspace composed of the `"states"` saved in the results file, giving an indication of the quality of the solution. This value is non-negative and a lower value means that the ground state of the subspace more closely approximates an eigenstate of the system's Hamiltonian. | -| `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | \ No newline at end of file +| `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | +| `"function_version"` | `string` | The version of the function that ran the job. Quote it in a support request. | +| `"metadata"` | `dict` | Contains `"resource_usage"`, giving the time spent in each stage of the job, including QPU time. | + +### With `estimate_only` + +An estimate returns `"function_version"` and `"metadata"` as above, and in +place of a result an `"estimate"` dictionary: + +| Key | Value Type| Explanation | +|-----|---------------|-----| +| `"num_qubits"` | `int` | The number of qubits the problem needs. | +| `"function_size"` | `string` | The function size to submit it at. | +| `"compute_profile"` | `string` | The CPUs and memory that size provides, such as `"16x128"`. | +| `"license_fee_ru"` | `float` | What a run at that size is billed, in resource units. | +| `"qubit_limit"` | `Optional[int]` | The qubit limit that applies to the caller, or `null` if none does. | +| `"within_qubit_limit"` | `bool` | Whether the problem fits that limit. | + +The qubit limit is reported rather than enforced, so a problem can be sized +before holding a license that permits it. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 11f3dc2dcda4..d8bc7e897061 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -135,8 +135,11 @@ "source": [ "## Get started\n", "\n", - "First, [request access to the function](https://forms.office.com/r/zN3hvMTqJ1).\n", - "Then, authenticate using your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) and, assuming you've already [saved your account](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) to your local environment, select the Qiskit Function as follows:" + "Runs are billed per execution at the function size you choose, with no qubit limit; see [Limits and billing](#limits-and-billing). If you hold or need a license, see [Licensed use](#licensed-use).\n", + "\n", + "The instance you authenticate with needs [Qiskit Functions access enabled](/docs/guides/access-instances-platform-apis#configure-qiskit-functions-access-on-an-instance), or the function will not appear in the catalog.\n", + "\n", + "Save your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) [to your local environment](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) if you have not already, then select the Qiskit Function as follows:" ] }, { @@ -263,6 +266,9 @@ " # `backend_name` is the name of a backend with at least 16 qubits,\n", " # for example, \"ibm_marrakesh\".\n", " backend_name=backend_name,\n", + " # `function_size` sets the resources the job runs on and what it\n", + " # costs. See \"Limits and billing\" below.\n", + " function_size=\"m\",\n", " max_states=2000,\n", " max_expansion_states=10,\n", " molecule_options=molecule_options,\n", @@ -365,9 +371,21 @@ "id": "2b6fb05c", "metadata": {}, "source": [ - "To access the ground state energy, use the `\"energy\"` key. The `\"results_file_name\"` key provides the name of the h5 results file that can be downloaded using `QiskitServerless`.\n", + "To access the ground state energy, use the `\"energy\"` key. The\n", + "`\"results_file_name\"` key provides the name of the h5 results file that can\n", + "be downloaded using `QiskitServerless`.\n", "\n", - "This file contains :\n", + "The response also carries:\n", + "- `\"energy_variance\"`: the energy variance of the final trial state, as a\n", + " single number,\n", + "- `\"energy_history\"`: the energies computed along the way, two per\n", + " iteration,\n", + "- `\"function_version\"`: the version of the function that ran the job, which\n", + " is worth quoting in a support request, and\n", + "- `\"metadata\"`: a `\"resource_usage\"` dictionary giving the time spent in\n", + " each stage of the job, including QPU time.\n", + "\n", + "The results file contains:\n", "- `\"final_energy\"`: the energy of the final trial state,\n", "- `\"final_energy_variance\"`: the energy variance of the final trial state,\n", "- `\"energy_history\"`: the energy history over HI-VQE's training,\n", @@ -454,16 +472,121 @@ " final_energy_variance = f[\"final_energy_variance\"][0]" ] }, + { + "cell_type": "markdown", + "id": "77066575-76b0-4416-a033-a33083d418f3", + "metadata": {}, + "source": [ + "## Limits and billing\n", + "\n", + "What applies to your runs depends on whether you hold a license token.\n", + "\n", + "| | Without a token | With a license token |\n", + "| --- | --- | --- |\n", + "| **Qubits** | No limit | What your license grants |\n", + "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", + "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent | Not required, though the size still sets the CPU and memory the job gets |\n", + "\n", + "Most users are in the first column. If you have not been issued a token, that\n", + "is you, and the two sections that follow are the ones you need. License\n", + "holders can skip to [Licensed use](#licensed-use).\n", + "\n", + "Trial access is limited to 20 qubits. A job that needs more fails with error\n", + "code 4500." + ] + }, + { + "cell_type": "markdown", + "id": "df5164aa-c7ca-438e-a414-f7f5a6795aa5", + "metadata": {}, + "source": [ + "### Function sizes\n", + "\n", + "`function_size` tells the platform what resources to run the job on, and it\n", + "is what the run is billed at. Pass it to `run()` alongside the function's own\n", + "arguments.\n", + "\n", + "| `function_size` | Qubits | License fee per run |\n", + "| --- | --- | --- |\n", + "| `\"s\"` | Up to 10 | 0.4 RU |\n", + "| `\"m\"` | Up to 20 | 1.0 RU |\n", + "| `\"l\"` | No limit | 4.0 RU |\n", + "\n", + "Fees are given in resource units. See [IBM Quantum\n", + "plans](/docs/guides/plans-overview) for what a resource unit costs on your\n", + "plan.\n", + "\n", + "If you leave `function_size` out, the job runs at `\"m\"`.\n", + "\n", + "A size smaller than the problem needs is rejected before any QPU time is\n", + "spent, and the error names the size to use instead. A size larger than it\n", + "needs runs and is billed at that larger size, with a warning telling you\n", + "which size would have been enough." + ] + }, + { + "cell_type": "markdown", + "id": "5569c36e-04c2-453f-a7fd-89b36b9d0d7b", + "metadata": {}, + "source": [ + "### Check the size before you run\n", + "\n", + "Passing `estimate_only=True` sizes the problem and returns without running\n", + "it, so you can find out what a job needs before committing to it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f5924f6-0d35-40d3-95f9-c67374532dff", + "metadata": {}, + "outputs": [], + "source": [ + "estimate_job = function.run(\n", + " geometry=geometry,\n", + " backend_name=backend_name,\n", + " max_states=2000,\n", + " max_expansion_states=10,\n", + " molecule_options=molecule_options,\n", + " hivqe_options=hivqe_options,\n", + " estimate_only=True,\n", + ")\n", + "print(estimate_job.result()[\"estimate\"])" + ] + }, + { + "cell_type": "markdown", + "id": "e08cb40a-174c-4a54-9411-9089c353591b", + "metadata": {}, + "source": [ + "The `\"estimate\"` dictionary reports:\n", + "\n", + "| Key | Meaning |\n", + "| --- | --- |\n", + "| `\"num_qubits\"` | The number of qubits this problem needs |\n", + "| `\"function_size\"` | The size to submit it at |\n", + "| `\"compute_profile\"` | The CPU and memory that size provides |\n", + "| `\"license_fee_ru\"` | What a run at that size is billed |\n", + "| `\"qubit_limit\"` | The limit that applies to you, or `None` if there is none |\n", + "| `\"within_qubit_limit\"` | Whether this problem fits that limit |\n", + "\n", + "An estimate reports your qubit limit rather than enforcing it, so you can\n", + "find out what a problem needs before you hold a license that allows it." + ] + }, { "cell_type": "markdown", "id": "5f252348-720f-47c0-9e7f-ae5e5512b8d1", "metadata": {}, "source": [ - "## Licensing\n", + "## Licensed use\n", "\n", - "Note that use of this Qiskit Function is limited to problems requiring at most 20 qubits, unless a license is obtained granting a higher limit.\n", + "A license grants a qubit limit of its own, and runs made with a license\n", + "token are not subject to the function size check. If you do not hold a\n", + "token, see [Limits and billing](#limits-and-billing) instead.\n", "\n", - "Email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with license inquiries.\n", + "To request access and a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", + "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with your inquiry.\n", "\n", "### Example of licensed function use\n", "\n", @@ -642,7 +765,8 @@ "source": [ "## Fetch error messages\n", "\n", - "If your workload fails, the status will be `ERROR` and calling `job.result()` will raise an exception:" + "If your workload fails, the status will be `ERROR` and calling\n", + "`job.result()` will raise an exception:" ] }, { @@ -706,6 +830,30 @@ "job.status()" ] }, + { + "cell_type": "markdown", + "id": "e86cab2f-11ab-4647-b785-9091c014034c", + "metadata": {}, + "source": [ + "Every failure reports an error code, a message describing what went wrong,\n", + "and a solution saying what to do about it. The codes follow [IBM's error\n", + "code registry](/docs/errors), and the ones this function returns are:\n", + "\n", + "| Code | What happened |\n", + "| --- | --- |\n", + "| 1007 | The `backend_name` you gave does not exist, or is not available to you |\n", + "| 1201 | A license token was supplied but no matching license was found |\n", + "| 1221 | An argument did not validate, or `function_size` was too small for the problem. The message names the size to use |\n", + "| 1500 | Something unexpected went wrong. Quote the job ID when you report it |\n", + "| 2409 | The license has expired, has been revoked, or was used from an instance it was not issued for |\n", + "| 4500 | The problem needs more qubits than your license or trial access allows |\n", + "| 4630 | Your license could not be read. Nothing is wrong with what you submitted; contact us with the job ID |\n", + "\n", + "Several codes cover more than one cause, so read the message as well as the\n", + "code. If you need help with a failure, send the Function job ID to\n", + "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com)." + ] + }, { "cell_type": "markdown", "id": "7c1e4a2b", @@ -739,7 +887,7 @@ "## Next steps\n", "\n", "\n", - "- Request access to the function by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", + "- Request access and a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Try the [Compute dissociation PES curve for FeP-NO with HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index da02a45ce223..4fe53cc24601 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -73,7 +73,9 @@ "source": [ "## Setup\n", "\n", - "To run this tutorial, import `qunova/hivqe-chemistry` function via `QiskitFunctionCatalog`. You need an IBM Quantum Premium Plan, Flex Plan, or On-Prem (IBM Quantum Platform API) Plan account with a license from Qunova to run this function." + "To run this tutorial, load the `qunova/hivqe-chemistry` function through\n", + "`QiskitFunctionsCatalog`. You need an IBM Quantum Premium Plan, Flex Plan, or\n", + "On-Prem (IBM Quantum Platform API) Plan account." ] }, { @@ -99,6 +101,38 @@ "hivqe = catalog.load(\"qunova/hivqe-chemistry\")" ] }, + { + "cell_type": "markdown", + "id": "659d5a25-7fd6-41b2-a657-5bfe1d8c713d", + "metadata": {}, + "source": [ + "### Before you run\n", + "\n", + "**Without a license.** The cell above is all the setup you need. Every run\n", + "below names a `function_size`, which sets the resources it gets and what it is\n", + "billed: `\"m\"` for Part 1, and `\"l\"` for Part 2, which needs 44 qubits. Running\n", + "the whole tutorial is six runs at `\"m\"` and three at `\"l\"`, or 18.0 resource\n", + "units. See [Limits and\n", + "billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide for\n", + "what the sizes cost.\n", + "\n", + "**With a license.** Load the function through the wrapper library instead of\n", + "the cell above, then run everything below unchanged:\n", + "\n", + "```python\n", + "# pip install hivqe-qiskit-function-utils\n", + "from hivqe_qiskit_function_utils import FunctionWrapper\n", + "\n", + "hivqe = FunctionWrapper(\n", + " token=\"YOUR_HIVQE_LICENSE_TOKEN\",\n", + " function=catalog.load(\"qunova/hivqe-chemistry\"),\n", + ")\n", + "```\n", + "\n", + "Your license sets the qubit limit, so it has to permit at least 44 qubits for\n", + "Part 2. The `function_size` in each run is passed through and not checked." + ] + }, { "cell_type": "markdown", "id": "00c68174", @@ -207,7 +241,7 @@ "source": [ "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HiVQE Chemistry function\n", "\n", - "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut." + "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut. These geometries need 20 qubits, so the runs are submitted at `function_size=\"m\"`." ] }, { @@ -230,6 +264,7 @@ " hivqe_run = hivqe.run(\n", " geometry=geom,\n", " backend_name=\"\",\n", + " function_size=\"m\",\n", " max_states=40000,\n", " max_expansion_states=100,\n", " molecule_options=molecule_options,\n", @@ -426,7 +461,7 @@ "metadata": {}, "outputs": [], "source": [ - "str_geometries = {\n", + "ref_geometries = {\n", " \"1.31\": \"S -1.250686 0.660708 -0.095168; Li -1.482812 0.453464 -1.369406; Li -0.911870 0.962810 1.762020\",\n", " \"1.41\": \"S -1.244856 0.665971 -0.062773; Li -1.494574 0.442933 -1.434177; Li -0.905937 0.968078 1.794395\",\n", " \"1.51\": \"S -1.239044 0.671232 -0.030374; Li -1.506327 0.432403 -1.498949; Li -0.899996 0.973348 1.826768\",\n", @@ -517,7 +552,7 @@ "\n", "cas_list = molecule_options[\"active_orbitals\"]\n", "distance_ref = []\n", - "for dis, geom in str_geometries.items():\n", + "for dis, geom in ref_geometries.items():\n", " distance_ref.append(dis)\n", " mole = gto.M(atom=geom, basis=molecule_options[\"basis\"])\n", " mole.verbose = 0\n", @@ -543,8 +578,6 @@ "id": "e1900a94", "metadata": {}, "source": [ - "### Plotting the dissociation curve for Li\\_2S\n", - "\n", "Let's plot and compare HiVQE results with HF and CASCI.\n", "You can observe that all HiVQE calculations are well-matched with the classical reference result (CASCI)." ] @@ -591,7 +624,7 @@ "source": [ "## Part 2: FeP-NO (44Q)\n", "\n", - "Note that to run the function on the FeP-NO system with the settings shown in this example, you need a license that permits using the function with at least 44 qubits. Email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about obtaining a license.\n", + "The settings shown in this example need 44 qubits, so the runs below are submitted at `function_size=\"l\"`. On a license, it must permit at least 44 qubits; email [qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) to inquire about one.\n", "\n", "### Step 1: Map classical inputs to a quantum problem\n", "\n", @@ -605,14 +638,14 @@ "metadata": {}, "outputs": [], "source": [ - "molecule_options = {\n", + "molecule_options_fepno = {\n", " \"basis\": \"631g*\",\n", " \"active_orbitals\": list(range(90, 112, 1)),\n", " \"frozen_orbitals\": list(range(0, 90, 1)),\n", " \"charge\": -1,\n", "}\n", "\n", - "hivqe_options = {\n", + "hivqe_options_fepno = {\n", " \"shots\": 2000,\n", " \"max_iter\": 40,\n", " \"ansatz\": \"epa\",\n", @@ -773,167 +806,14 @@ "O 9.598728 37.226756 3.411299\n", "\"\"\"\n", "\n", - "str_geometries = {\n", - " \"1.75\": geometry_1_75,\n", - " \"2.00\": geometry_2_00,\n", - " \"5.00\": geometry_5_00,\n", - "}\n", - "\n", - "\n", - "hivqe_result = {}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52b55a07", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'5.0': '\\nFe 9.918629 31.289202 1.717339\\nN 10.542914 31.832173 -0.080685\\nN 11.795572 31.199413 2.341831\\nN 9.294593 30.741247 3.513929\\nN 8.042689 31.359481 1.087282\\nC 9.775254 32.111817 -1.200449\\nC 10.600219 32.479101 -2.319680\\nC 11.891090 32.425876 -1.887580\\nC 11.847694 32.024341 -0.507342\\nC 12.945734 31.464689 1.611366\\nC 14.116395 31.289997 2.423572\\nC 13.685777 30.915122 3.663719\\nC 12.252381 30.861042 3.608186\\nC 10.062170 30.463021 4.634102\\nC 9.236749 30.104333 5.755782\\nC 7.945687 30.161198 5.324720\\nC 7.989641 30.552269 3.941498\\nC 6.892881 31.087489 1.815829\\nC 5.722676 31.253502 1.001149\\nC 6.153153 31.631057 -0.238233\\nC 7.586010 31.695401 -0.179773\\nC 8.390724 32.047572 -1.247553\\nH 7.903308 32.291586 -2.187969\\nC 12.973334 31.849872 0.283741\\nH 13.944682 32.031190 -0.169145\\nC 11.447158 30.518591 4.678739\\nH 11.934423 30.277429 5.619969\\nC 6.864795 30.711643 3.146118\\nH 5.893357 30.532078 3.599511\\nH 12.800139 32.636412 -2.439296\\nH 10.224017 32.743662 -3.301293\\nH 15.131785 31.441247 2.076257\\nH 14.273933 30.694315 4.546802\\nH 9.612512 29.848040 6.739754\\nH 7.036117 29.960530 5.879248\\nH 4.707408 31.099933 1.347803\\nH 5.564992 31.851940 -1.121294\\nN 9.666041 36.091609 3.085945\\nO 9.598728 37.226756 3.411299\\n'}" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "geometry_1_75 = \"\"\"\n", - "Fe 9.910596 31.534095 1.798088\n", - "N 10.557481 31.888419 -0.055204\n", - "N 11.823496 31.255002 2.384659\n", - "N 9.292831 30.783362 3.568730\n", - "N 8.036805 31.418327 1.124265\n", - "C 9.784765 32.177349 -1.158798\n", - "C 10.612656 32.501029 -2.296868\n", - "C 11.903375 32.404043 -1.876832\n", - "C 11.859093 32.028943 -0.483750\n", - "C 12.965737 31.464698 1.641427\n", - "C 14.146517 31.236323 2.440231\n", - "C 13.713061 30.885870 3.681911\n", - "C 12.268752 30.896411 3.634891\n", - "C 10.067717 30.486167 4.664747\n", - "C 9.246224 30.053411 5.772052\n", - "C 7.957075 30.082846 5.336488\n", - "C 7.995710 30.538421 3.967046\n", - "C 6.900258 31.104497 1.836595\n", - "C 5.722470 31.251707 1.015333\n", - "C 6.148430 31.668586 -0.207993\n", - "C 7.587039 31.767438 -0.130483\n", - "C 8.399453 32.134197 -1.192329\n", - "H 7.912872 32.388031 -2.131079\n", - "C 12.984883 31.836053 0.306093\n", - "H 13.955948 31.977044 -0.162626\n", - "C 11.453768 30.560663 4.708020\n", - "H 11.940677 30.298823 5.644352\n", - "C 6.877071 30.697580 3.164102\n", - "H 5.907240 30.476797 3.603674\n", - "H 12.813946 32.569160 -2.441577\n", - "H 10.236332 32.758110 -3.280309\n", - "H 15.164312 31.335191 2.080201\n", - "H 14.299625 30.629109 4.556760\n", - "H 9.626524 29.758225 6.743433\n", - "H 7.053076 29.823583 5.875809\n", - "H 4.709768 31.058315 1.350561\n", - "H 5.561898 31.886355 -1.093106\n", - "N 9.832739 33.209042 2.298783\n", - "O 9.346337 34.075996 1.606023\n", - "\"\"\"\n", - "\n", - "geometry_2_00 = \"\"\"\n", - "Fe 9.917990 31.445558 1.778346\n", - "N 10.556809 31.866188 -0.055498\n", - "N 11.814089 31.227003 2.372666\n", - "N 9.297875 30.758246 3.550104\n", - "N 8.043584 31.397768 1.120485\n", - "C 9.784831 32.164652 -1.160219\n", - "C 10.611624 32.501801 -2.293514\n", - "C 11.902858 32.406547 -1.875160\n", - "C 11.859552 32.017818 -0.486307\n", - "C 12.960503 31.454432 1.636717\n", - "C 14.140770 31.242960 2.439615\n", - "C 13.708543 30.884151 3.678983\n", - "C 12.266351 30.874173 3.627468\n", - "C 10.070264 30.465070 4.655102\n", - "C 9.247247 30.053101 5.766681\n", - "C 7.958085 30.091201 5.332866\n", - "C 7.998432 30.529979 3.958727\n", - "C 6.901428 31.093932 1.833807\n", - "C 5.723289 31.255057 1.016540\n", - "C 6.151314 31.670649 -0.206350\n", - "C 7.589736 31.755538 -0.133074\n", - "C 8.400230 32.124963 -1.194447\n", - "H 7.913264 32.386655 -2.130914\n", - "C 12.983905 31.827747 0.302415\n", - "H 13.955696 31.979687 -0.161365\n", - "C 11.454251 30.533644 4.698234\n", - "H 11.941002 30.276716 5.636156\n", - "C 6.877444 30.689985 3.159940\n", - "H 5.907605 30.480118 3.604825\n", - "H 12.813105 32.581608 -2.437367\n", - "H 10.233725 32.768337 -3.273979\n", - "H 15.157796 31.357524 2.082132\n", - "H 14.295001 30.638320 4.557047\n", - "H 9.626721 29.768762 6.741623\n", - "H 7.051752 29.847502 5.875478\n", - "H 4.709710 31.071712 1.354640\n", - "H 5.565103 31.898376 -1.089333\n", - "N 9.840508 33.353531 2.373019\n", - "O 9.344561 34.158205 1.637232\n", - "\"\"\"\n", - "\n", - "geometry_5_00 = \"\"\"\n", - "Fe 9.918629 31.289202 1.717339\n", - "N 10.542914 31.832173 -0.080685\n", - "N 11.795572 31.199413 2.341831\n", - "N 9.294593 30.741247 3.513929\n", - "N 8.042689 31.359481 1.087282\n", - "C 9.775254 32.111817 -1.200449\n", - "C 10.600219 32.479101 -2.319680\n", - "C 11.891090 32.425876 -1.887580\n", - "C 11.847694 32.024341 -0.507342\n", - "C 12.945734 31.464689 1.611366\n", - "C 14.116395 31.289997 2.423572\n", - "C 13.685777 30.915122 3.663719\n", - "C 12.252381 30.861042 3.608186\n", - "C 10.062170 30.463021 4.634102\n", - "C 9.236749 30.104333 5.755782\n", - "C 7.945687 30.161198 5.324720\n", - "C 7.989641 30.552269 3.941498\n", - "C 6.892881 31.087489 1.815829\n", - "C 5.722676 31.253502 1.001149\n", - "C 6.153153 31.631057 -0.238233\n", - "C 7.586010 31.695401 -0.179773\n", - "C 8.390724 32.047572 -1.247553\n", - "H 7.903308 32.291586 -2.187969\n", - "C 12.973334 31.849872 0.283741\n", - "H 13.944682 32.031190 -0.169145\n", - "C 11.447158 30.518591 4.678739\n", - "H 11.934423 30.277429 5.619969\n", - "C 6.864795 30.711643 3.146118\n", - "H 5.893357 30.532078 3.599511\n", - "H 12.800139 32.636412 -2.439296\n", - "H 10.224017 32.743662 -3.301293\n", - "H 15.131785 31.441247 2.076257\n", - "H 14.273933 30.694315 4.546802\n", - "H 9.612512 29.848040 6.739754\n", - "H 7.036117 29.960530 5.879248\n", - "H 4.707408 31.099933 1.347803\n", - "H 5.564992 31.851940 -1.121294\n", - "N 9.666041 36.091609 3.085945\n", - "O 9.598728 37.226756 3.411299\n", - "\"\"\"\n", - "\n", - "str_geometries = {\n", + "fepno_geometries = {\n", " \"1.75\": geometry_1_75,\n", " \"2.00\": geometry_2_00,\n", " \"5.00\": geometry_5_00,\n", "}\n", "\n", "\n", - "hivqe_result = {}" + "hivqe_result_fepno = {}" ] }, { @@ -962,12 +842,13 @@ "outputs": [], "source": [ "hivqe_run_1_75 = hivqe.run(\n", - " geometry=str_geometries[\"1.75\"],\n", + " geometry=fepno_geometries[\"1.75\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_1_75 = hivqe_run_1_75.job_id" ] @@ -993,7 +874,7 @@ "if stat == \"DONE\":\n", " hivqe_run_1_75_energy = submitted_job_1_75.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_1_75_energy}\")\n", - " hivqe_result[\"1.75\"] = hivqe_run_1_75_energy" + " hivqe_result_fepno[\"1.75\"] = hivqe_run_1_75_energy" ] }, { @@ -1012,12 +893,13 @@ "outputs": [], "source": [ "hivqe_run_2_00 = hivqe.run(\n", - " geometry=str_geometries[\"2.00\"],\n", + " geometry=fepno_geometries[\"2.00\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_2_00 = hivqe_run_2_00.job_id" ] @@ -1043,7 +925,7 @@ "if stat == \"DONE\":\n", " hivqe_run_2_00_energy = submitted_job_2_00.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_2_00_energy}\")\n", - " hivqe_result[\"2.00\"] = hivqe_run_2_00_energy" + " hivqe_result_fepno[\"2.00\"] = hivqe_run_2_00_energy" ] }, { @@ -1062,12 +944,13 @@ "outputs": [], "source": [ "hivqe_run_5_00 = hivqe.run(\n", - " geometry=str_geometries[\"5.00\"],\n", + " geometry=fepno_geometries[\"5.00\"],\n", " backend_name=\"\",\n", + " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", + " molecule_options=molecule_options_fepno,\n", + " hivqe_options=hivqe_options_fepno,\n", ")\n", "info_jobid_5_00 = hivqe_run_5_00.job_id" ] @@ -1093,7 +976,16 @@ "if stat == \"DONE\":\n", " hivqe_run_5_00_energy = submitted_job_5_00.result()[\"energy\"]\n", " print(f\"Completed HiVQE calculation, Energy {hivqe_run_5_00_energy}\")\n", - " hivqe_result[\"5.00\"] = hivqe_run_5_00_energy" + " hivqe_result_fepno[\"5.00\"] = hivqe_run_5_00_energy" + ] + }, + { + "cell_type": "markdown", + "id": "1c0606d4-088a-4999-bf16-cb6b87637652", + "metadata": {}, + "source": [ + "The energies from these three runs, so that the comparison below works\n", + "without waiting for your own jobs. Skip this cell to use your own." ] }, { @@ -1103,7 +995,7 @@ "metadata": {}, "outputs": [], "source": [ - "hivqe_result = {\n", + "hivqe_result_fepno = {\n", " \"1.75\": -2373.681781,\n", " \"2.00\": -2373.694128,\n", " \"5.00\": -2373.637807,\n", @@ -1127,12 +1019,12 @@ "metadata": {}, "outputs": [], "source": [ - "rhf_result = {\n", + "rhf_result_fepno = {\n", " \"1.75\": -2373.59331683504,\n", " \"2.00\": -2373.60640773065,\n", " \"5.00\": -2373.50214278007,\n", "}\n", - "casci_result = {\"1.75\": -2373.6827, \"2.00\": -2373.6948, \"5.00\": -2373.6393}" + "casci_result_fepno = {\"1.75\": -2373.6827, \"2.00\": -2373.6948, \"5.00\": -2373.6393}" ] }, { @@ -1158,11 +1050,11 @@ ], "source": [ "fig, ax = plt.subplots(1, 1)\n", - "hf_energy = [v for key, v in rhf_result.items()]\n", - "casci_energy = [v for key, v in casci_result.items()]\n", - "hivqe_energy = [v for key, v in hivqe_result.items()]\n", - "distance_ref = [float(key) for key, v in rhf_result.items()]\n", - "distance = [float(key) for key, v in hivqe_result.items()]\n", + "hf_energy = [v for key, v in rhf_result_fepno.items()]\n", + "casci_energy = [v for key, v in casci_result_fepno.items()]\n", + "hivqe_energy = [v for key, v in hivqe_result_fepno.items()]\n", + "distance_ref = [float(key) for key, v in rhf_result_fepno.items()]\n", + "distance = [float(key) for key, v in hivqe_result_fepno.items()]\n", "\n", "ax.plot(distance_ref, hf_energy, \"-o\", label=\"RHF\", c=\"blue\")\n", "ax.plot(distance_ref, casci_energy, \"-o\", label=\"CASCI\", c=\"green\")\n", From a1174a799440b27f4eb6ebe64d91144242b4bdd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 14:53:30 +0900 Subject: [PATCH 26/59] Format the FeP-NO CASCI reference the way ruff wants it Renaming it to casci_result_fepno took the line past 88 characters, so ruff format --check, run by IBM's lint (tox -e lint), would fail. Co-Authored-By: Claude Opus 5.5 --- docs/tutorials/qunova-hivqe.ipynb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 4fe53cc24601..d5d6a11f8587 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -1024,7 +1024,11 @@ " \"2.00\": -2373.60640773065,\n", " \"5.00\": -2373.50214278007,\n", "}\n", - "casci_result_fepno = {\"1.75\": -2373.6827, \"2.00\": -2373.6948, \"5.00\": -2373.6393}" + "casci_result_fepno = {\n", + " \"1.75\": -2373.6827,\n", + " \"2.00\": -2373.6948,\n", + " \"5.00\": -2373.6393,\n", + "}" ] }, { @@ -1081,6 +1085,7 @@ } ], "metadata": { + "hours": 1.5, "kernelspec": { "display_name": "Python 3", "language": "python", @@ -1098,7 +1103,6 @@ "pygments_lexer": "ipython3", "version": "3" }, - "hours": 1.5, "qpuSeconds": 300 }, "nbformat": 4, From e2e2367eedcc1f7d73b2502d3d4a264701ef8ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 14:53:44 +0900 Subject: [PATCH 27/59] Add a 5.0.0 entry to the HI-VQE Changelog 5.0.0 is what changes for a user who has no licence token. They are no longer capped at 20 qubits. Instead they choose a function_size and are billed per run at it, and a size too small for the problem is rejected with 1221 before any QPU time is spent. The entry also covers estimate_only, the function_version and metadata.resource_usage keys, and the error codes. Checked against the qiskit-functions-hivqe-v5.0.2 tag in QunovaPulsar: the size table and the default "m" (function_size.py), FunctionSizeTooSmall raising 1221 (errors.py), and the result keys (runner.py). Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index d8bc7e897061..ef3538738dd0 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -861,6 +861,13 @@ "source": [ "## Changelog\n", "\n", + "### 5.0.0\n", + "\n", + "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent. See [Limits and billing](#limits-and-billing).\n", + "- Added `estimate_only=True`, which sizes a problem and returns the function size it needs and its fee, without running it. See [Check the size before you run](#check-the-size-before-you-run).\n", + "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", + "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", + "\n", "### 4.0.0\n", "\n", "- The result no longer includes `\"states\"` or `\"eigenvector\"`. They are now saved in an HDF5 results file, together with `\"final_energy\"`, `\"final_energy_variance\"`, and `\"energy_history\"`.\n", From cd030139b0452986ef3d0f9d4a7ce8a90cab0fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 15:02:21 +0900 Subject: [PATCH 28/59] Submit the guide's Li2S example at the size it needs The Performance section's Li2S loop passed no function_size, so under 5.0.x it runs at the default "m", which allows 20 qubits. Li2S in STO-3G with no active space needs 38. A reader without a licence token would get error 1221 on the first geometry, before any QPU time was spent. It now passes function_size="l". Sized with the function's own problem_size.estimate_problem_size at qiskit-functions-hivqe-v5.0.2, with its default options. That check gives NH3 16 qubits ("m", as the guide passes), H2O 14 (licensed, so not size-checked), and Li2S 38 ("l"). The tutorial's runs already pass the sizes they need: Li2S 20 qubits at "m", FeP-NO 44 at "l". Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index ef3538738dd0..407deababb51 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -696,6 +696,7 @@ " job = function.run(\n", " geometry=Li2S_geoms[geom],\n", " backend_name=backend_name, # can use any device with at least 38 qubits\n", + " function_size=\"l\", # 38 qubits, more than \"m\" allows\n", " max_states=2000,\n", " max_expansion_states=10,\n", " molecule_options=molecule_options,\n", From df6d375f1b7cb73c6220db8926cf9f26e5817354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 15:44:22 +0900 Subject: [PATCH 29/59] Size HI-VQE runs locally instead of with estimate_only estimate_only runs inside the function, so the platform treats it as an execution: the job starts a container at the submitted size (it ran on general_m in a test on -dev) and, under usage-based billing, owes that size's licence fee. IBM's gateway emits the fee for any Fleets job that reaches RUNNING (qiskit-serverless gateway/core/services/job_transitions.py, specs/OUTBOX.md). It also took about two minutes, of which 0.003 s was the sizing. IBM's launch item 4 asked for an estimator users run before submitting, not an execution. The qubit count follows a simple rule that PySCF can apply on the reader's machine: 2 x AVAS's active space when avas_aolabels is set, else 2 x len(active_orbitals), else 2 x the basis size. The guide now gives that rule and a short function. On 11 cases it matches the function's own problem_size.estimate_problem_size at qiskit-functions-hivqe-v5.0.2, including AVAS at the default and zero thresholds and AVAS together with an active list. - Guide: replace the estimate_only cell and its result table with the rule and the function (NH3 gives 16 qubits, so "m"). Say that a run rejected for being too small is still billed at the size chosen; the 5.0.0 EULA (5.4.4) says the same. - API reference: drop estimate_only and its output section, add the billing note to function_size, and link to the guide's section. - Changelog: point to the local check instead of estimate_only. The function still accepts estimate_only; it is just no longer the documented way to size a run. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 31 ++------- docs/guides/qunova-chemistry.ipynb | 92 ++++++++++++++++--------- 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index f7f117339496..f8fff284f816 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -224,14 +224,6 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` -### `estimate_only` - -Size the problem and return without running it. The response contains an -`"estimate"` dictionary instead of a result, and no QPU time is spent. -- Required: No -- Example: `True` - - ### `function_size` Which resources the job runs on, and what the run is billed. It is passed to @@ -245,8 +237,10 @@ to this function. | `"l"` | No limit | 48 CPUs, 768 GB | 4.0 RU | A size smaller than the problem needs is rejected before any QPU time is -spent, with error code 1221 naming the size to use. A size larger than it -needs runs, and is billed at that larger size. Runs made with a license token +spent, with error code 1221 naming the size to use; the rejected run is still +billed at the size it was submitted at. A size larger than it needs runs, and +is billed at that larger size. To work out the size before submitting, see +[Check the size before you run](/docs/guides/qunova-chemistry#check-the-size-before-you-run). Runs made with a license token are not checked against the problem, and are bounded by the qubit limit the license grants instead. - Required: No @@ -265,20 +259,3 @@ The function returns a dictionary with the following keys and values: | `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | | `"function_version"` | `string` | The version of the function that ran the job. Quote it in a support request. | | `"metadata"` | `dict` | Contains `"resource_usage"`, giving the time spent in each stage of the job, including QPU time. | - -### With `estimate_only` - -An estimate returns `"function_version"` and `"metadata"` as above, and in -place of a result an `"estimate"` dictionary: - -| Key | Value Type| Explanation | -|-----|---------------|-----| -| `"num_qubits"` | `int` | The number of qubits the problem needs. | -| `"function_size"` | `string` | The function size to submit it at. | -| `"compute_profile"` | `string` | The CPUs and memory that size provides, such as `"16x128"`. | -| `"license_fee_ru"` | `float` | What a run at that size is billed, in resource units. | -| `"qubit_limit"` | `Optional[int]` | The qubit limit that applies to the caller, or `null` if none does. | -| `"within_qubit_limit"` | `bool` | Whether the problem fits that limit. | - -The qubit limit is reported rather than enforced, so a problem can be sized -before holding a license that permits it. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 407deababb51..e6e761b08331 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -485,7 +485,7 @@ "| --- | --- | --- |\n", "| **Qubits** | No limit | What your license grants |\n", "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", - "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent | Not required, though the size still sets the CPU and memory the job gets |\n", + "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent, though it is still billed at the size you chose | Not required, though the size still sets the CPU and memory the job gets |\n", "\n", "Most users are in the first column. If you have not been issued a token, that\n", "is you, and the two sections that follow are the ones you need. License\n", @@ -519,9 +519,11 @@ "If you leave `function_size` out, the job runs at `\"m\"`.\n", "\n", "A size smaller than the problem needs is rejected before any QPU time is\n", - "spent, and the error names the size to use instead. A size larger than it\n", - "needs runs and is billed at that larger size, with a warning telling you\n", - "which size would have been enough." + "spent, and the error names the size to use instead. The rejected run is still\n", + "billed at the size you chose, because a run is billed once it starts. A size\n", + "larger than it needs runs and is billed at that larger size, with a warning\n", + "telling you which size would have been enough. To get the size right the\n", + "first time, work it out before you submit, as the next section shows." ] }, { @@ -531,8 +533,19 @@ "source": [ "### Check the size before you run\n", "\n", - "Passing `estimate_only=True` sizes the problem and returns without running\n", - "it, so you can find out what a job needs before committing to it." + "The size a run needs depends only on how many qubits the problem uses, and you\n", + "can work that out with PySCF on your own machine, without submitting anything\n", + "or spending any resource units:\n", + "\n", + "| Your `molecule_options` | Qubits |\n", + "| --- | --- |\n", + "| `avas_aolabels` set | 2 × the number of orbitals AVAS selects |\n", + "| `active_orbitals` set | 2 × the number of active orbitals |\n", + "| Neither | 2 × the number of atomic orbitals in the basis |\n", + "\n", + "The function below applies the same rule the function does. If you set other\n", + "molecule options that change the basis, such as `pseudo` or `cart`, pass them\n", + "to `gto.M` as well." ] }, { @@ -540,18 +553,43 @@ "execution_count": null, "id": "3f5924f6-0d35-40d3-95f9-c67374532dff", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16\n" + ] + } + ], "source": [ - "estimate_job = function.run(\n", - " geometry=geometry,\n", - " backend_name=backend_name,\n", - " max_states=2000,\n", - " max_expansion_states=10,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", - " estimate_only=True,\n", - ")\n", - "print(estimate_job.result()[\"estimate\"])" + "from pyscf import gto, scf\n", + "from pyscf.mcscf import avas\n", + "\n", + "\n", + "def hivqe_num_qubits(geometry, molecule_options):\n", + " \"\"\"The number of qubits HI-VQE uses for this problem.\"\"\"\n", + " mol = gto.M(\n", + " atom=geometry,\n", + " basis=molecule_options.get(\"basis\", \"sto-3g\"),\n", + " charge=molecule_options.get(\"charge\", 0),\n", + " unit=molecule_options.get(\"unit\", \"angstrom\"),\n", + " verbose=0,\n", + " )\n", + " if molecule_options.get(\"avas_aolabels\"):\n", + " # AVAS picks the active space after an RHF, as the function does\n", + " mf = scf.RHF(mol).run()\n", + " threshold = max(molecule_options.get(\"avas_threshold\", 0.2), 1e-10)\n", + " ncas, _, _ = avas.avas(\n", + " mf, molecule_options[\"avas_aolabels\"], threshold=threshold\n", + " )\n", + " return 2 * ncas\n", + " if molecule_options.get(\"active_orbitals\"):\n", + " return 2 * len(molecule_options[\"active_orbitals\"])\n", + " return 2 * mol.nao_nr()\n", + "\n", + "\n", + "print(hivqe_num_qubits(geometry, molecule_options))" ] }, { @@ -559,19 +597,9 @@ "id": "e08cb40a-174c-4a54-9411-9089c353591b", "metadata": {}, "source": [ - "The `\"estimate\"` dictionary reports:\n", - "\n", - "| Key | Meaning |\n", - "| --- | --- |\n", - "| `\"num_qubits\"` | The number of qubits this problem needs |\n", - "| `\"function_size\"` | The size to submit it at |\n", - "| `\"compute_profile\"` | The CPU and memory that size provides |\n", - "| `\"license_fee_ru\"` | What a run at that size is billed |\n", - "| `\"qubit_limit\"` | The limit that applies to you, or `None` if there is none |\n", - "| `\"within_qubit_limit\"` | Whether this problem fits that limit |\n", - "\n", - "An estimate reports your qubit limit rather than enforcing it, so you can\n", - "find out what a problem needs before you hold a license that allows it." + "Then submit at the smallest size that fits: up to 10 qubits is `\"s\"`, up to\n", + "20 is `\"m\"`, and anything larger is `\"l\"`. The NH3 example needs 16 qubits, so\n", + "it runs at `\"m\"`, as in the [Example](#example) above." ] }, { @@ -864,8 +892,8 @@ "\n", "### 5.0.0\n", "\n", - "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent. See [Limits and billing](#limits-and-billing).\n", - "- Added `estimate_only=True`, which sizes a problem and returns the function size it needs and its fee, without running it. See [Check the size before you run](#check-the-size-before-you-run).\n", + "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Limits and billing](#limits-and-billing).\n", + "- The number of qubits, and so the function size, can be worked out with PySCF before submitting anything. See [Check the size before you run](#check-the-size-before-you-run).\n", "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", "\n", From 9dc44c3b1c328496b096382afed2d6223f23cb71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 16:05:59 +0900 Subject: [PATCH 30/59] Pass every basis option to PySCF in the guide's qubit count The function passed only basis, charge and unit to gto.M, and the text asked readers to add any other option themselves. Options such as cart change the basis size, so a reader who missed that got the wrong count: H2O in 6-31G* with cart=True is 38 qubits, not 36. The function now passes the same molecule options the function does (basis, charge, unit, symmetry, symmetry_subgroup, nucmod, pseudo, cart, magmom) and defaults the basis to sto-3g, as the function does. The text says to install PySCF with pip. Compared on 15 cases against the function's own sizing at qiskit-functions-hivqe-v5.0.2, now including cart, Bohr units and a charged molecule. All match. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index e6e761b08331..7ed0be7733ad 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -543,9 +543,10 @@ "| `active_orbitals` set | 2 × the number of active orbitals |\n", "| Neither | 2 × the number of atomic orbitals in the basis |\n", "\n", - "The function below applies the same rule the function does. If you set other\n", - "molecule options that change the basis, such as `pseudo` or `cart`, pass them\n", - "to `gto.M` as well." + "The function below applies the same rule the function does, with the same\n", + "defaults, and passes your other molecule options (such as `charge`, `pseudo`\n", + "or `cart`) to PySCF so the basis matches. It needs PySCF, which you can install\n", + "with `pip install pyscf`." ] }, { @@ -566,16 +567,18 @@ "from pyscf import gto, scf\n", "from pyscf.mcscf import avas\n", "\n", + "# The molecule_options that shape the basis, passed through to PySCF\n", + "MOLECULE_KEYS = {\"basis\", \"charge\", \"unit\", \"symmetry\", \"symmetry_subgroup\"}\n", + "MOLECULE_KEYS |= {\"nucmod\", \"pseudo\", \"cart\", \"magmom\"}\n", + "\n", "\n", "def hivqe_num_qubits(geometry, molecule_options):\n", " \"\"\"The number of qubits HI-VQE uses for this problem.\"\"\"\n", - " mol = gto.M(\n", - " atom=geometry,\n", - " basis=molecule_options.get(\"basis\", \"sto-3g\"),\n", - " charge=molecule_options.get(\"charge\", 0),\n", - " unit=molecule_options.get(\"unit\", \"angstrom\"),\n", - " verbose=0,\n", + " options = {\"basis\": \"sto-3g\"}\n", + " options.update(\n", + " {k: v for k, v in molecule_options.items() if k in MOLECULE_KEYS}\n", " )\n", + " mol = gto.M(atom=geometry, verbose=0, **options)\n", " if molecule_options.get(\"avas_aolabels\"):\n", " # AVAS picks the active space after an RHF, as the function does\n", " mf = scf.RHF(mol).run()\n", From 84afc09df34676bc984e33f0e5432eadcf5236fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 7 Oct 2026 16:31:20 +0900 Subject: [PATCH 31/59] Document sizing as a rule plus a billed estimate_only, as Qedma does Earlier commits on this branch replaced estimate_only with a PySCF function, hivqe_num_qubits(), that readers could run on their own machine. That put our sizing implementation in the public guide. Other partners document the rule and offer an in-function estimate: Qedma's guide gives its QPU-time formula and an estimate_time_only run. The guide now follows that pattern: - The qubit rule is a table: 2 x the orbitals AVAS selects, else 2 x len(active_orbitals), else 2 x the basis size. The NH3 example is worked through (8 orbitals, 16 qubits, "m"). - estimate_only=True is back, with the call, its output (taken from a real -dev run) and its fields. The text says it is billed as a run at the size it is submitted at, is never rejected for being too small, and so should go at "s". The call passes function_size="s". - The API reference gets estimate_only and its output section back, with the same billing note. The Changelog entry says the same. Kept from the earlier commits: rejected runs are billed at the size chosen, and the Li2S example passes function_size="l". Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 29 ++++++++- docs/guides/qunova-chemistry.ipynb | 83 ++++++++++++------------- 2 files changed, 68 insertions(+), 44 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index f8fff284f816..568b396be1af 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -224,6 +224,16 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` +### `estimate_only` + +Size the problem and return without running HI-VQE. The response contains an +`"estimate"` dictionary instead of a result, and no QPU time is spent. The +estimate is still a run, billed at the `function_size` it is submitted at. It +is never rejected for being too small, so submit it at `"s"`. +- Required: No +- Example: `True` + + ### `function_size` Which resources the job runs on, and what the run is billed. It is passed to @@ -239,7 +249,7 @@ to this function. A size smaller than the problem needs is rejected before any QPU time is spent, with error code 1221 naming the size to use; the rejected run is still billed at the size it was submitted at. A size larger than it needs runs, and -is billed at that larger size. To work out the size before submitting, see +is billed at that larger size. To check the size before submitting, see [Check the size before you run](/docs/guides/qunova-chemistry#check-the-size-before-you-run). Runs made with a license token are not checked against the problem, and are bounded by the qubit limit the license grants instead. @@ -259,3 +269,20 @@ The function returns a dictionary with the following keys and values: | `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | | `"function_version"` | `string` | The version of the function that ran the job. Quote it in a support request. | | `"metadata"` | `dict` | Contains `"resource_usage"`, giving the time spent in each stage of the job, including QPU time. | + +### With `estimate_only` + +An estimate returns `"function_version"` and `"metadata"` as above, and in +place of a result an `"estimate"` dictionary: + +| Key | Value Type| Explanation | +|-----|---------------|-----| +| `"num_qubits"` | `int` | The number of qubits the problem needs. | +| `"function_size"` | `string` | The function size to submit it at. | +| `"compute_profile"` | `string` | The CPUs and memory that size provides, such as `"16x128"`. | +| `"license_fee_ru"` | `float` | What a run at that size is billed, in resource units. | +| `"qubit_limit"` | `Optional[int]` | The qubit limit that applies to the caller, or `null` if none does. | +| `"within_qubit_limit"` | `bool` | Whether the problem fits that limit. | + +The qubit limit is reported rather than enforced, so a problem can be sized +before holding a license that permits it. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 7ed0be7733ad..92f15f2eb05a 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -523,7 +523,7 @@ "billed at the size you chose, because a run is billed once it starts. A size\n", "larger than it needs runs and is billed at that larger size, with a warning\n", "telling you which size would have been enough. To get the size right the\n", - "first time, work it out before you submit, as the next section shows." + "first time, check it before you submit, as the next section shows." ] }, { @@ -533,20 +533,25 @@ "source": [ "### Check the size before you run\n", "\n", - "The size a run needs depends only on how many qubits the problem uses, and you\n", - "can work that out with PySCF on your own machine, without submitting anything\n", - "or spending any resource units:\n", + "The size a run needs depends only on how many qubits the problem uses, which\n", + "follows from your `molecule_options`:\n", "\n", "| Your `molecule_options` | Qubits |\n", "| --- | --- |\n", - "| `avas_aolabels` set | 2 × the number of orbitals AVAS selects |\n", + "| `avas_aolabels` set | 2 × the number of orbitals AVAS selects (threshold `avas_threshold`, default 0.2) |\n", "| `active_orbitals` set | 2 × the number of active orbitals |\n", "| Neither | 2 × the number of atomic orbitals in the basis |\n", "\n", - "The function below applies the same rule the function does, with the same\n", - "defaults, and passes your other molecule options (such as `charge`, `pseudo`\n", - "or `cart`) to PySCF so the basis matches. It needs PySCF, which you can install\n", - "with `pip install pyscf`." + "Submit at the smallest size that fits: up to 10 qubits is `\"s\"`, up to 20 is\n", + "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", + "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", + "\n", + "To have the function size the problem for you, pass `estimate_only=True`. The\n", + "function then works out the qubits and the size and returns them without\n", + "running HI-VQE, so no QPU time is spent. It is still a run, though, and it is\n", + "billed at the size you submit it at. An estimate is never rejected for being\n", + "too small, so submit it at `\"s\"`, the cheapest size. It takes about as long to\n", + "start as any other run, typically a minute or two." ] }, { @@ -559,40 +564,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "16\n" + "{'num_qubits': 16, 'function_size': 'm', 'compute_profile': '16x128', 'license_fee_ru': 1.0, 'qubit_limit': None, 'within_qubit_limit': True}\n" ] } ], "source": [ - "from pyscf import gto, scf\n", - "from pyscf.mcscf import avas\n", - "\n", - "# The molecule_options that shape the basis, passed through to PySCF\n", - "MOLECULE_KEYS = {\"basis\", \"charge\", \"unit\", \"symmetry\", \"symmetry_subgroup\"}\n", - "MOLECULE_KEYS |= {\"nucmod\", \"pseudo\", \"cart\", \"magmom\"}\n", - "\n", - "\n", - "def hivqe_num_qubits(geometry, molecule_options):\n", - " \"\"\"The number of qubits HI-VQE uses for this problem.\"\"\"\n", - " options = {\"basis\": \"sto-3g\"}\n", - " options.update(\n", - " {k: v for k, v in molecule_options.items() if k in MOLECULE_KEYS}\n", - " )\n", - " mol = gto.M(atom=geometry, verbose=0, **options)\n", - " if molecule_options.get(\"avas_aolabels\"):\n", - " # AVAS picks the active space after an RHF, as the function does\n", - " mf = scf.RHF(mol).run()\n", - " threshold = max(molecule_options.get(\"avas_threshold\", 0.2), 1e-10)\n", - " ncas, _, _ = avas.avas(\n", - " mf, molecule_options[\"avas_aolabels\"], threshold=threshold\n", - " )\n", - " return 2 * ncas\n", - " if molecule_options.get(\"active_orbitals\"):\n", - " return 2 * len(molecule_options[\"active_orbitals\"])\n", - " return 2 * mol.nao_nr()\n", - "\n", - "\n", - "print(hivqe_num_qubits(geometry, molecule_options))" + "estimate_job = function.run(\n", + " geometry=geometry,\n", + " backend_name=backend_name,\n", + " function_size=\"s\", # an estimate fits any size, so use the cheapest\n", + " max_states=2000,\n", + " max_expansion_states=10,\n", + " molecule_options=molecule_options,\n", + " hivqe_options=hivqe_options,\n", + " estimate_only=True,\n", + ")\n", + "print(estimate_job.result()[\"estimate\"])" ] }, { @@ -600,9 +587,19 @@ "id": "e08cb40a-174c-4a54-9411-9089c353591b", "metadata": {}, "source": [ - "Then submit at the smallest size that fits: up to 10 qubits is `\"s\"`, up to\n", - "20 is `\"m\"`, and anything larger is `\"l\"`. The NH3 example needs 16 qubits, so\n", - "it runs at `\"m\"`, as in the [Example](#example) above." + "The `\"estimate\"` dictionary reports:\n", + "\n", + "| Key | Meaning |\n", + "| --- | --- |\n", + "| `\"num_qubits\"` | The number of qubits this problem needs |\n", + "| `\"function_size\"` | The size to submit it at |\n", + "| `\"compute_profile\"` | The CPU and memory that size provides |\n", + "| `\"license_fee_ru\"` | What a run at that size is billed |\n", + "| `\"qubit_limit\"` | The limit that applies to you, or `None` if there is none |\n", + "| `\"within_qubit_limit\"` | Whether this problem fits that limit |\n", + "\n", + "An estimate reports your qubit limit rather than enforcing it, so you can\n", + "find out what a problem needs before you hold a license that allows it." ] }, { @@ -896,7 +893,7 @@ "### 5.0.0\n", "\n", "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Limits and billing](#limits-and-billing).\n", - "- The number of qubits, and so the function size, can be worked out with PySCF before submitting anything. See [Check the size before you run](#check-the-size-before-you-run).\n", + "- Added `estimate_only=True`, which returns the qubits and function size a problem needs without running HI-VQE. It is billed as a run at the size it is submitted at, so submit it at `\"s\"`. See [Check the size before you run](#check-the-size-before-you-run).\n", "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", "\n", From a018b600ae3a7fbfd377be7af2039731915cbbaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 11:47:44 +0900 Subject: [PATCH 32/59] Document HI-VQE 5.0.3: argument checking and the fixed options Arguments are now checked against the function's argument schema when run() is called, so describe validate_arguments() and arguments_schema in the guide and the API reference. Add a 5.0.3 changelog entry: orbital_coeffs works and takes a NumPy array, ansatz_entanglement accepts any case, avas_threshold takes a whole number, and the orbital lists must not repeat an entry. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 16 ++++++++---- docs/guides/qunova-chemistry.ipynb | 33 ++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 568b396be1af..9045fd2d31bc 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -16,6 +16,12 @@ description: API reference for HI-VQE Chemistry, a Qiskit Function by Qunova Com ## Inputs +Arguments are checked when you call `run()`, before a job is created: one with +the wrong name, type or range raises an exception naming it, and nothing is +billed. `function.validate_arguments({...})` runs the same check without +running anything, and `function.arguments_schema` lists every argument with its +type, range and default. + ### `geometry` This can be either a string or structured lists containing atom and coordinate pairs. If this is given as a string, it must be a molecule geometry in Cartesian Coordinate Format. If this is given as a list, it should be given as a list of lists that each contain an atom string and coordinate tuple. @@ -64,18 +70,18 @@ A string specifying the basis type; these are passed to pyscf. For example: `"st #### `active_orbitals` A list of active orbital indices in the interval [0, n) where n is the number of qubits used in the problem. If this is specified, then the frozen_orbitals argument must also be specified. -- Valid range: The spatial orbital indices valid for the problem +- Valid range: The spatial orbital indices valid for the problem, each at most once #### `frozen_orbitals` A list of frozen orbital indices in the same range as active_orbitals. If specified, then active_orbitals must also be specified. Note that only occupied orbitals should be frozen as the number of active electrons is reduced by 2 for every occupied orbital that is frozen. -- Valid range: The spatial orbital indices valid for the problem, excluding active orbitals +- Valid range: The spatial orbital indices valid for the problem, excluding active orbitals, each at most once #### `orbital_coeffs` - -The coefficients for the spatial orbitals used in the calculation of the electronic repulsion integrals for the system. Some valid examples are Hartree-Fock molecular orbitals, natural orbitals, and AVAS orbitals. + +The coefficients for the spatial orbitals used in the calculation of the electronic repulsion integrals for the system. Some valid examples are Hartree-Fock molecular orbitals, natural orbitals, and AVAS orbitals. Give a matrix as a list of equal-length rows or as a 2-D NumPy array, such as PySCF's `mo_coeff`. - Valid range: Various @@ -124,7 +130,7 @@ Sets the colinear spin magnetic moment of each atom. By default, this is None an #### `avas_aolabels` This defines Atomic Orbital to be included in AVAS scheme. See [AVAS documentation](https://arxiv.org/abs/1701.07862). -- Valid range: i.e., ["H 1s", "O 2p"] for H$_2$O +- Valid range: i.e., ["H 1s", "O 2p"] for H$_2$O, each label at most once #### `avas_threshold` diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 92f15f2eb05a..e9f301deadaf 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -880,7 +880,30 @@ "\n", "Several codes cover more than one cause, so read the message as well as the\n", "code. If you need help with a failure, send the Function job ID to\n", - "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com)." + "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com).\n", + "\n", + "Arguments are also checked when you call `run()`, before a job is created. An\n", + "argument with the wrong name, type or range is refused straight away: `run()`\n", + "raises an exception naming the argument, no job is created and nothing is\n", + "billed. To check arguments without running anything, use\n", + "`validate_arguments()`, which returns `{\"valid\": True}` or raises the same\n", + "exception:\n", + "\n", + "```python\n", + "function.validate_arguments(\n", + " {\n", + " \"geometry\": geometry,\n", + " \"backend_name\": backend_name,\n", + " \"max_states\": 2000,\n", + " \"max_expansion_states\": 10,\n", + " \"molecule_options\": molecule_options,\n", + " \"hivqe_options\": hivqe_options,\n", + " }\n", + ")\n", + "```\n", + "\n", + "`function.arguments_schema` shows every argument the function accepts, with\n", + "its type, range and default." ] }, { @@ -890,6 +913,14 @@ "source": [ "## Changelog\n", "\n", + "### 5.0.3\n", + "\n", + "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Fetch error messages](#fetch-error-messages).\n", + "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", + "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", + "- `avas_threshold` accepts a whole number, such as `0`.\n", + "- `active_orbitals`, `frozen_orbitals` and `avas_aolabels` must not repeat an entry.\n", + "\n", "### 5.0.0\n", "\n", "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Limits and billing](#limits-and-billing).\n", From b00e33e3ea3179653525e9621ffcdd2ec12d44f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 12:40:01 +0900 Subject: [PATCH 33/59] Publish the HI-VQE size estimator in the guide IBM asks every function for a size estimator that users can run before they submit, and wants its code public. Put hivqe_chemistry_size_estimator.py, the file IBM and the function size a job with, word for word under "Check the size before you run", with a call on the guide's NH3 example ("m"). It needs only PySCF, submits nothing and costs nothing; estimate_only stays as the in-function alternative, billed as a run. Add it to the 5.0.3 changelog. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 160 ++++++++++++++++++++++++++++- 1 file changed, 159 insertions(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index e9f301deadaf..24742275912e 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -546,7 +546,164 @@ "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", "\n", - "To have the function size the problem for you, pass `estimate_only=True`. The\n", + "To find the size on your own machine, use the size estimator below. It is the\n", + "same code IBM and the function use to size a job, so the size it gives is the\n", + "one your run is placed and checked at. It needs only PySCF\n", + "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell, or\n", + "save it as `hivqe_chemistry_size_estimator.py`. Call `estimate_size`; the rest\n", + "of the file is how the size is worked out." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a88635c-b4c0-4b8c-b1dd-faf369836b5c", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "Size estimator for Qunova HI-VQE Chemistry -- a function that is neither a circuit function\n", + "nor an optimization function, so it follows ``size_estimator_template.py``.\n", + "\n", + "Input: the \"problem\" the function accepts -- ``geometry``, as passed to ``function.run()`` --\n", + " plus the other function inputs as ``**kwargs``. Only ``molecule_options`` is read;\n", + " everything else is accepted and ignored.\n", + "Output: ``\"s\"``, ``\"m\"`` or ``\"l\"``.\n", + "\n", + "What drives the resource usage is the number of qubits the problem needs, two per active\n", + "orbital, so that is what ``_measure`` returns. The active space is the one the function\n", + "builds from ``molecule_options``:\n", + "\n", + "- ``avas_aolabels`` set: the orbitals AVAS selects, at ``avas_threshold`` (default 0.2)\n", + "- ``active_orbitals`` set: those orbitals\n", + "- neither: every orbital in the basis\n", + "\n", + "Only AVAS needs a calculation (one RHF); the other two only build the molecule. The result\n", + "depends on nothing but the input, so the same call always gives the same size.\n", + "\n", + "Requires ``pyscf``. Self-contained: it imports nothing from the function.\n", + "\"\"\"\n", + "from __future__ import annotations\n", + "\n", + "from typing import Any, Literal\n", + "\n", + "from pyscf import gto, scf\n", + "from pyscf.mcscf import avas\n", + "\n", + "Size = Literal[\"s\", \"m\", \"l\"]\n", + "_ORDER = {\"s\": 0, \"m\": 1, \"l\": 2}\n", + "\n", + "# Upper bounds (inclusive) on the number of qubits for each size.\n", + "_SMALL = 10\n", + "_MEDIUM = 20\n", + "\n", + "# The function's defaults for the molecule_options that decide the active space.\n", + "_DEFAULTS = {\n", + " \"active_orbitals\": None,\n", + " \"avas_aolabels\": None,\n", + " \"avas_threshold\": 0.2,\n", + " \"basis\": \"sto-3g\",\n", + " \"charge\": 0,\n", + " \"symmetry\": False,\n", + " \"symmetry_subgroup\": None,\n", + " \"unit\": \"angstrom\",\n", + " \"nucmod\": None,\n", + " \"pseudo\": None,\n", + " \"cart\": False,\n", + " \"magmom\": None,\n", + "}\n", + "\n", + "# AVAS weights below this are numerical noise; counting them would make the size vary\n", + "# from one call to the next.\n", + "_AVAS_WEIGHT_TOLERANCE = 1e-10\n", + "\n", + "\n", + "def estimate_size(problem: Any, **kwargs: Any) -> Size:\n", + " \"\"\"Return the size (\"s\", \"m\" or \"l\") required to run the function.\"\"\"\n", + " metrics = _measure(problem, **kwargs)\n", + " if _is_small(metrics):\n", + " return \"s\"\n", + " if _is_medium(metrics):\n", + " return \"m\"\n", + " return \"l\"\n", + "\n", + "\n", + "def _measure(problem: Any, **kwargs: Any) -> dict:\n", + " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", + " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", + " mol = gto.M(\n", + " atom=problem,\n", + " basis=options[\"basis\"],\n", + " spin=0, # the function runs singlets only\n", + " charge=options[\"charge\"],\n", + " symmetry=options[\"symmetry\"],\n", + " symmetry_subgroup=options[\"symmetry_subgroup\"],\n", + " unit=options[\"unit\"],\n", + " nucmod=options[\"nucmod\"],\n", + " pseudo=options[\"pseudo\"],\n", + " cart=options[\"cart\"],\n", + " magmom=options[\"magmom\"],\n", + " verbose=0,\n", + " )\n", + "\n", + " if options[\"avas_aolabels\"] is None:\n", + " # The active space is the orbitals given, or the whole basis; building the molecule\n", + " # is enough to know it.\n", + " if options[\"active_orbitals\"]:\n", + " return {\"num_qubits\": 2 * len(options[\"active_orbitals\"])}\n", + " return {\"num_qubits\": 2 * mol.nao_nr()}\n", + "\n", + " # AVAS picks the active space from an RHF, so it has to run one.\n", + " rhf = scf.RHF(mol)\n", + " rhf.verbose = 0\n", + " rhf.kernel()\n", + " selection = avas.AVAS(\n", + " mf=rhf,\n", + " aolabels=options[\"avas_aolabels\"],\n", + " threshold=max(options[\"avas_threshold\"], _AVAS_WEIGHT_TOLERANCE),\n", + " )\n", + " selection.verbose = 0\n", + " selection.kernel()\n", + " return {\"num_qubits\": 2 * selection.ncas}\n", + "\n", + "\n", + "def _is_small(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _SMALL\n", + "\n", + "\n", + "def _is_medium(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 'm'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _MEDIUM\n", + "\n", + "\n", + "def validate_size(provided_size: Size, problem: Any, **kwargs: Any) -> None:\n", + " \"\"\"Call at the start of the function. Raise if ``provided_size`` is smaller than\n", + " the estimated size; the estimated size or a larger one is accepted.\"\"\"\n", + " expected = estimate_size(problem, **kwargs)\n", + " if _ORDER[provided_size] < _ORDER[expected]:\n", + " raise ValueError(\n", + " f\"Size '{provided_size}' is too small for this problem; expected '{expected}' or larger.\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "216827a3-35e1-4499-b924-6ec5b6b7af92", + "metadata": {}, + "outputs": [], + "source": [ + "# NH3 in STO-3G has 8 orbitals, so 16 qubits: \"m\"\n", + "print(estimate_size(geometry, molecule_options=molecule_options))" + ] + }, + { + "cell_type": "markdown", + "id": "f8b9f7cd-c369-4555-8ab9-514ccbf21780", + "metadata": {}, + "source": [ + "The function can also size the problem for you: pass `estimate_only=True`. The\n", "function then works out the qubits and the size and returns them without\n", "running HI-VQE, so no QPU time is spent. It is still a run, though, and it is\n", "billed at the size you submit it at. An estimate is never rejected for being\n", @@ -915,6 +1072,7 @@ "\n", "### 5.0.3\n", "\n", + "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Check the size before you run](#check-the-size-before-you-run).\n", "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Fetch error messages](#fetch-error-messages).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", From 7f9c4276334e8f6f54a62384360967fec1031c0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 13:28:06 +0900 Subject: [PATCH 34/59] Hold licensed runs to the size, and size with the estimator alone From 5.0.3 the function refuses any run submitted at a size too small for its problem, licensed and trial runs included, since the size is also the machine the job runs on. Say so under Limits and billing, Licensed use and the function_size reference, give the licensed example a function_size, and add it to the 5.0.3 changelog. estimate_only is gone from the function: the size estimator answers the same question on the reader's own machine, free. Remove its guide cells, its input and output sections in the API reference, and its 5.0.0 changelog line; 5.x has not been published, so no one has relied on it. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 33 +---------- docs/guides/qunova-chemistry.ipynb | 74 +++---------------------- 2 files changed, 12 insertions(+), 95 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 9045fd2d31bc..1124472631a8 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -230,16 +230,6 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` -### `estimate_only` - -Size the problem and return without running HI-VQE. The response contains an -`"estimate"` dictionary instead of a result, and no QPU time is spent. The -estimate is still a run, billed at the `function_size` it is submitted at. It -is never rejected for being too small, so submit it at `"s"`. -- Required: No -- Example: `True` - - ### `function_size` Which resources the job runs on, and what the run is billed. It is passed to @@ -256,9 +246,9 @@ A size smaller than the problem needs is rejected before any QPU time is spent, with error code 1221 naming the size to use; the rejected run is still billed at the size it was submitted at. A size larger than it needs runs, and is billed at that larger size. To check the size before submitting, see -[Check the size before you run](/docs/guides/qunova-chemistry#check-the-size-before-you-run). Runs made with a license token -are not checked against the problem, and are bounded by the qubit limit the -license grants instead. +[Check the size before you run](/docs/guides/qunova-chemistry#check-the-size-before-you-run). This applies to runs made +with a license token and to trial runs too, since the size is the machine the +job runs on; a license token also sets its own qubit limit. - Required: No - Example: `"l"` @@ -275,20 +265,3 @@ The function returns a dictionary with the following keys and values: | `"energy_history"` | `List[float]` | The energies computed each iteration during the hybrid optimization process, in the same order that they were computed. Two energies are computed per iteration as part of the SPSA optimization process. | | `"function_version"` | `string` | The version of the function that ran the job. Quote it in a support request. | | `"metadata"` | `dict` | Contains `"resource_usage"`, giving the time spent in each stage of the job, including QPU time. | - -### With `estimate_only` - -An estimate returns `"function_version"` and `"metadata"` as above, and in -place of a result an `"estimate"` dictionary: - -| Key | Value Type| Explanation | -|-----|---------------|-----| -| `"num_qubits"` | `int` | The number of qubits the problem needs. | -| `"function_size"` | `string` | The function size to submit it at. | -| `"compute_profile"` | `string` | The CPUs and memory that size provides, such as `"16x128"`. | -| `"license_fee_ru"` | `float` | What a run at that size is billed, in resource units. | -| `"qubit_limit"` | `Optional[int]` | The qubit limit that applies to the caller, or `null` if none does. | -| `"within_qubit_limit"` | `bool` | Whether the problem fits that limit. | - -The qubit limit is reported rather than enforced, so a problem can be sized -before holding a license that permits it. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 24742275912e..a335d25abb2e 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -485,7 +485,7 @@ "| --- | --- | --- |\n", "| **Qubits** | No limit | What your license grants |\n", "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", - "| **Choosing a size** | Required. Too small and the run is rejected before any QPU time is spent, though it is still billed at the size you chose | Not required, though the size still sets the CPU and memory the job gets |\n", + "| **Choosing a size** | The default `\"m\"` fits up to 20 qubits. Too small and the run is rejected before any QPU time is spent, though it is still billed at the size you chose | The same check: the default `\"m\"` fits up to 20 qubits, and a run submitted too small is rejected. The size sets the CPU and memory the job gets |\n", "\n", "Most users are in the first column. If you have not been issued a token, that\n", "is you, and the two sections that follow are the ones you need. License\n", @@ -698,67 +698,6 @@ "print(estimate_size(geometry, molecule_options=molecule_options))" ] }, - { - "cell_type": "markdown", - "id": "f8b9f7cd-c369-4555-8ab9-514ccbf21780", - "metadata": {}, - "source": [ - "The function can also size the problem for you: pass `estimate_only=True`. The\n", - "function then works out the qubits and the size and returns them without\n", - "running HI-VQE, so no QPU time is spent. It is still a run, though, and it is\n", - "billed at the size you submit it at. An estimate is never rejected for being\n", - "too small, so submit it at `\"s\"`, the cheapest size. It takes about as long to\n", - "start as any other run, typically a minute or two." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3f5924f6-0d35-40d3-95f9-c67374532dff", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'num_qubits': 16, 'function_size': 'm', 'compute_profile': '16x128', 'license_fee_ru': 1.0, 'qubit_limit': None, 'within_qubit_limit': True}\n" - ] - } - ], - "source": [ - "estimate_job = function.run(\n", - " geometry=geometry,\n", - " backend_name=backend_name,\n", - " function_size=\"s\", # an estimate fits any size, so use the cheapest\n", - " max_states=2000,\n", - " max_expansion_states=10,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", - " estimate_only=True,\n", - ")\n", - "print(estimate_job.result()[\"estimate\"])" - ] - }, - { - "cell_type": "markdown", - "id": "e08cb40a-174c-4a54-9411-9089c353591b", - "metadata": {}, - "source": [ - "The `\"estimate\"` dictionary reports:\n", - "\n", - "| Key | Meaning |\n", - "| --- | --- |\n", - "| `\"num_qubits\"` | The number of qubits this problem needs |\n", - "| `\"function_size\"` | The size to submit it at |\n", - "| `\"compute_profile\"` | The CPU and memory that size provides |\n", - "| `\"license_fee_ru\"` | What a run at that size is billed |\n", - "| `\"qubit_limit\"` | The limit that applies to you, or `None` if there is none |\n", - "| `\"within_qubit_limit\"` | Whether this problem fits that limit |\n", - "\n", - "An estimate reports your qubit limit rather than enforcing it, so you can\n", - "find out what a problem needs before you hold a license that allows it." - ] - }, { "cell_type": "markdown", "id": "5f252348-720f-47c0-9e7f-ae5e5512b8d1", @@ -766,8 +705,11 @@ "source": [ "## Licensed use\n", "\n", - "A license grants a qubit limit of its own, and runs made with a license\n", - "token are not subject to the function size check. If you do not hold a\n", + "A license grants a qubit limit of its own. Runs made with a license token\n", + "are held to the function size like any other, since the size is the machine\n", + "the job runs on: the default `\"m\"` fits up to 20 qubits, and a larger problem\n", + "needs `function_size=\"l\"`. To find the size, see\n", + "[Check the size before you run](#check-the-size-before-you-run). If you do not hold a\n", "token, see [Limits and billing](#limits-and-billing) instead.\n", "\n", "To request access and a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", @@ -806,6 +748,8 @@ "job = hivqe.run(\n", " geometry=molecule_geometry,\n", " backend_name=backend_name, # can use any device with at least 14 qubits\n", + " # 14 qubits fit the default \"m\"; a problem over 20 qubits needs \"l\"\n", + " function_size=\"m\",\n", " max_states=10000,\n", " max_expansion_states=1000,\n", " hivqe_options={\"ansatz\": \"epa\", \"max_iter\": 10},\n", @@ -1072,6 +1016,7 @@ "\n", "### 5.0.3\n", "\n", + "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Check the size before you run](#check-the-size-before-you-run).\n", "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Fetch error messages](#fetch-error-messages).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", @@ -1082,7 +1027,6 @@ "### 5.0.0\n", "\n", "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Limits and billing](#limits-and-billing).\n", - "- Added `estimate_only=True`, which returns the qubits and function size a problem needs without running HI-VQE. It is billed as a run at the size it is submitted at, so submit it at `\"s\"`. See [Check the size before you run](#check-the-size-before-you-run).\n", "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", "\n", From e3d5adfa6c817b2dd73dd59dfab20a13ab5ee487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:06:39 +0900 Subject: [PATCH 35/59] Say the size rules once, and check arguments where run() is called The function-size rules were repeated in Limits and billing, Function sizes, Check the size and Licensed use; they are now in Function sizes only. The trial limit is a note under the table it qualifies. How run() refuses a bad argument, and validate_arguments(), move from the end of the error section to the Example, right after the first run(). Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 83 +++++++++++++++++------------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index a335d25abb2e..1ef7f02c34b6 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -310,6 +310,39 @@ "This example then utilizes 16 qubits with 8 orbitals of sto3g basis for an NH3 molecule." ] }, + { + "cell_type": "markdown", + "id": "3c7a91e2", + "metadata": {}, + "source": [ + "`run()` checks the arguments against the function's argument schema before a\n", + "job is created. An argument with the wrong name, type or range is refused\n", + "straight away: `run()` raises an exception naming the argument, no job is\n", + "created, and nothing is billed. To check arguments without running anything,\n", + "use `validate_arguments()`, which returns `{\"valid\": True}` or raises the same\n", + "exception. `function.arguments_schema` shows every argument the function\n", + "accepts, with its type, range and default." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d0b84f6", + "metadata": {}, + "outputs": [], + "source": [ + "function.validate_arguments(\n", + " {\n", + " \"geometry\": geometry,\n", + " \"backend_name\": backend_name,\n", + " \"max_states\": 2000,\n", + " \"max_expansion_states\": 10,\n", + " \"molecule_options\": molecule_options,\n", + " \"hivqe_options\": hivqe_options,\n", + " }\n", + ")" + ] + }, { "cell_type": "markdown", "id": "ad1c9bcb", @@ -485,14 +518,13 @@ "| --- | --- | --- |\n", "| **Qubits** | No limit | What your license grants |\n", "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", - "| **Choosing a size** | The default `\"m\"` fits up to 20 qubits. Too small and the run is rejected before any QPU time is spent, though it is still billed at the size you chose | The same check: the default `\"m\"` fits up to 20 qubits, and a run submitted too small is rejected. The size sets the CPU and memory the job gets |\n", "\n", - "Most users are in the first column. If you have not been issued a token, that\n", - "is you, and the two sections that follow are the ones you need. License\n", - "holders can skip to [Licensed use](#licensed-use).\n", + "\n", + " Trial access is limited to 20 qubits. A job that needs more fails with error code 4500.\n", + "\n", "\n", - "Trial access is limited to 20 qubits. A job that needs more fails with error\n", - "code 4500." + "Every run is submitted at a function size and is checked against it, with or\n", + "without a token. The two sections that follow explain how to choose it." ] }, { @@ -519,8 +551,9 @@ "If you leave `function_size` out, the job runs at `\"m\"`.\n", "\n", "A size smaller than the problem needs is rejected before any QPU time is\n", - "spent, and the error names the size to use instead. The rejected run is still\n", - "billed at the size you chose, because a run is billed once it starts. A size\n", + "spent, and the error names the size to use instead. This applies to runs with\n", + "a license token too. Without a token, the rejected run is still billed at the\n", + "size you chose, because a run is billed once it starts. A size\n", "larger than it needs runs and is billed at that larger size, with a warning\n", "telling you which size would have been enough. To get the size right the\n", "first time, check it before you submit, as the next section shows." @@ -705,12 +738,9 @@ "source": [ "## Licensed use\n", "\n", - "A license grants a qubit limit of its own. Runs made with a license token\n", - "are held to the function size like any other, since the size is the machine\n", - "the job runs on: the default `\"m\"` fits up to 20 qubits, and a larger problem\n", - "needs `function_size=\"l\"`. To find the size, see\n", - "[Check the size before you run](#check-the-size-before-you-run). If you do not hold a\n", - "token, see [Limits and billing](#limits-and-billing) instead.\n", + "A license grants a qubit limit of its own. Runs made with a license token are\n", + "still submitted at a function size and checked against it; see\n", + "[Function sizes](#function-sizes).\n", "\n", "To request access and a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with your inquiry.\n", @@ -983,28 +1013,9 @@ "code. If you need help with a failure, send the Function job ID to\n", "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com).\n", "\n", - "Arguments are also checked when you call `run()`, before a job is created. An\n", - "argument with the wrong name, type or range is refused straight away: `run()`\n", - "raises an exception naming the argument, no job is created and nothing is\n", - "billed. To check arguments without running anything, use\n", - "`validate_arguments()`, which returns `{\"valid\": True}` or raises the same\n", - "exception:\n", - "\n", - "```python\n", - "function.validate_arguments(\n", - " {\n", - " \"geometry\": geometry,\n", - " \"backend_name\": backend_name,\n", - " \"max_states\": 2000,\n", - " \"max_expansion_states\": 10,\n", - " \"molecule_options\": molecule_options,\n", - " \"hivqe_options\": hivqe_options,\n", - " }\n", - ")\n", - "```\n", - "\n", - "`function.arguments_schema` shows every argument the function accepts, with\n", - "its type, range and default." + "A call with a wrong argument name, type or range does not get this far:\n", + "`run()` refuses it before a job is created, as described in\n", + "[Example](#example)." ] }, { From c0c4ac052d78407e3da5e44559284be03c1ec88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:08:08 +0900 Subject: [PATCH 36/59] Give the size estimator a section of its own Its 124 lines sat between Function sizes and Licensed use. The definition and the NH3 call now form a section before the Changelog, so the notebook still runs top to bottom, and Check the size before you run keeps the table and a link. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 321 +++++++++++++++-------------- 1 file changed, 170 insertions(+), 151 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 1ef7f02c34b6..f22a8d7dc8d6 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -579,156 +579,9 @@ "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", "\n", - "To find the size on your own machine, use the size estimator below. It is the\n", - "same code IBM and the function use to size a job, so the size it gives is the\n", - "one your run is placed and checked at. It needs only PySCF\n", - "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell, or\n", - "save it as `hivqe_chemistry_size_estimator.py`. Call `estimate_size`; the rest\n", - "of the file is how the size is worked out." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a88635c-b4c0-4b8c-b1dd-faf369836b5c", - "metadata": {}, - "outputs": [], - "source": [ - "\"\"\"\n", - "Size estimator for Qunova HI-VQE Chemistry -- a function that is neither a circuit function\n", - "nor an optimization function, so it follows ``size_estimator_template.py``.\n", - "\n", - "Input: the \"problem\" the function accepts -- ``geometry``, as passed to ``function.run()`` --\n", - " plus the other function inputs as ``**kwargs``. Only ``molecule_options`` is read;\n", - " everything else is accepted and ignored.\n", - "Output: ``\"s\"``, ``\"m\"`` or ``\"l\"``.\n", - "\n", - "What drives the resource usage is the number of qubits the problem needs, two per active\n", - "orbital, so that is what ``_measure`` returns. The active space is the one the function\n", - "builds from ``molecule_options``:\n", - "\n", - "- ``avas_aolabels`` set: the orbitals AVAS selects, at ``avas_threshold`` (default 0.2)\n", - "- ``active_orbitals`` set: those orbitals\n", - "- neither: every orbital in the basis\n", - "\n", - "Only AVAS needs a calculation (one RHF); the other two only build the molecule. The result\n", - "depends on nothing but the input, so the same call always gives the same size.\n", - "\n", - "Requires ``pyscf``. Self-contained: it imports nothing from the function.\n", - "\"\"\"\n", - "from __future__ import annotations\n", - "\n", - "from typing import Any, Literal\n", - "\n", - "from pyscf import gto, scf\n", - "from pyscf.mcscf import avas\n", - "\n", - "Size = Literal[\"s\", \"m\", \"l\"]\n", - "_ORDER = {\"s\": 0, \"m\": 1, \"l\": 2}\n", - "\n", - "# Upper bounds (inclusive) on the number of qubits for each size.\n", - "_SMALL = 10\n", - "_MEDIUM = 20\n", - "\n", - "# The function's defaults for the molecule_options that decide the active space.\n", - "_DEFAULTS = {\n", - " \"active_orbitals\": None,\n", - " \"avas_aolabels\": None,\n", - " \"avas_threshold\": 0.2,\n", - " \"basis\": \"sto-3g\",\n", - " \"charge\": 0,\n", - " \"symmetry\": False,\n", - " \"symmetry_subgroup\": None,\n", - " \"unit\": \"angstrom\",\n", - " \"nucmod\": None,\n", - " \"pseudo\": None,\n", - " \"cart\": False,\n", - " \"magmom\": None,\n", - "}\n", - "\n", - "# AVAS weights below this are numerical noise; counting them would make the size vary\n", - "# from one call to the next.\n", - "_AVAS_WEIGHT_TOLERANCE = 1e-10\n", - "\n", - "\n", - "def estimate_size(problem: Any, **kwargs: Any) -> Size:\n", - " \"\"\"Return the size (\"s\", \"m\" or \"l\") required to run the function.\"\"\"\n", - " metrics = _measure(problem, **kwargs)\n", - " if _is_small(metrics):\n", - " return \"s\"\n", - " if _is_medium(metrics):\n", - " return \"m\"\n", - " return \"l\"\n", - "\n", - "\n", - "def _measure(problem: Any, **kwargs: Any) -> dict:\n", - " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", - " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", - " mol = gto.M(\n", - " atom=problem,\n", - " basis=options[\"basis\"],\n", - " spin=0, # the function runs singlets only\n", - " charge=options[\"charge\"],\n", - " symmetry=options[\"symmetry\"],\n", - " symmetry_subgroup=options[\"symmetry_subgroup\"],\n", - " unit=options[\"unit\"],\n", - " nucmod=options[\"nucmod\"],\n", - " pseudo=options[\"pseudo\"],\n", - " cart=options[\"cart\"],\n", - " magmom=options[\"magmom\"],\n", - " verbose=0,\n", - " )\n", - "\n", - " if options[\"avas_aolabels\"] is None:\n", - " # The active space is the orbitals given, or the whole basis; building the molecule\n", - " # is enough to know it.\n", - " if options[\"active_orbitals\"]:\n", - " return {\"num_qubits\": 2 * len(options[\"active_orbitals\"])}\n", - " return {\"num_qubits\": 2 * mol.nao_nr()}\n", - "\n", - " # AVAS picks the active space from an RHF, so it has to run one.\n", - " rhf = scf.RHF(mol)\n", - " rhf.verbose = 0\n", - " rhf.kernel()\n", - " selection = avas.AVAS(\n", - " mf=rhf,\n", - " aolabels=options[\"avas_aolabels\"],\n", - " threshold=max(options[\"avas_threshold\"], _AVAS_WEIGHT_TOLERANCE),\n", - " )\n", - " selection.verbose = 0\n", - " selection.kernel()\n", - " return {\"num_qubits\": 2 * selection.ncas}\n", - "\n", - "\n", - "def _is_small(metrics: dict) -> bool:\n", - " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", - " return metrics[\"num_qubits\"] <= _SMALL\n", - "\n", - "\n", - "def _is_medium(metrics: dict) -> bool:\n", - " \"\"\"Determine if the metrics fit T-size 'm'.\"\"\"\n", - " return metrics[\"num_qubits\"] <= _MEDIUM\n", - "\n", - "\n", - "def validate_size(provided_size: Size, problem: Any, **kwargs: Any) -> None:\n", - " \"\"\"Call at the start of the function. Raise if ``provided_size`` is smaller than\n", - " the estimated size; the estimated size or a larger one is accepted.\"\"\"\n", - " expected = estimate_size(problem, **kwargs)\n", - " if _ORDER[provided_size] < _ORDER[expected]:\n", - " raise ValueError(\n", - " f\"Size '{provided_size}' is too small for this problem; expected '{expected}' or larger.\"\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "216827a3-35e1-4499-b924-6ec5b6b7af92", - "metadata": {}, - "outputs": [], - "source": [ - "# NH3 in STO-3G has 8 orbitals, so 16 qubits: \"m\"\n", - "print(estimate_size(geometry, molecule_options=molecule_options))" + "To find the size on your own machine before you submit, use the\n", + "[size estimator](#size-estimator). It gives the size IBM and the function\n", + "check your run at, needs only PySCF, and costs nothing." ] }, { @@ -1018,6 +871,172 @@ "[Example](#example)." ] }, + { + "cell_type": "markdown", + "id": "9e2f4a17", + "metadata": {}, + "source": [ + "## Size estimator\n", + "\n", + "This is the code IBM and the function use to size a job, so the size it gives\n", + "is the one your run is placed and checked at. It needs only PySCF\n", + "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell below,\n", + "or save it as `hivqe_chemistry_size_estimator.py`. You only need to call\n", + "`estimate_size`; the rest of the file is how the size is worked out." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a88635c-b4c0-4b8c-b1dd-faf369836b5c", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"\n", + "Size estimator for Qunova HI-VQE Chemistry -- a function that is neither a circuit function\n", + "nor an optimization function, so it follows ``size_estimator_template.py``.\n", + "\n", + "Input: the \"problem\" the function accepts -- ``geometry``, as passed to ``function.run()`` --\n", + " plus the other function inputs as ``**kwargs``. Only ``molecule_options`` is read;\n", + " everything else is accepted and ignored.\n", + "Output: ``\"s\"``, ``\"m\"`` or ``\"l\"``.\n", + "\n", + "What drives the resource usage is the number of qubits the problem needs, two per active\n", + "orbital, so that is what ``_measure`` returns. The active space is the one the function\n", + "builds from ``molecule_options``:\n", + "\n", + "- ``avas_aolabels`` set: the orbitals AVAS selects, at ``avas_threshold`` (default 0.2)\n", + "- ``active_orbitals`` set: those orbitals\n", + "- neither: every orbital in the basis\n", + "\n", + "Only AVAS needs a calculation (one RHF); the other two only build the molecule. The result\n", + "depends on nothing but the input, so the same call always gives the same size.\n", + "\n", + "Requires ``pyscf``. Self-contained: it imports nothing from the function.\n", + "\"\"\"\n", + "from __future__ import annotations\n", + "\n", + "from typing import Any, Literal\n", + "\n", + "from pyscf import gto, scf\n", + "from pyscf.mcscf import avas\n", + "\n", + "Size = Literal[\"s\", \"m\", \"l\"]\n", + "_ORDER = {\"s\": 0, \"m\": 1, \"l\": 2}\n", + "\n", + "# Upper bounds (inclusive) on the number of qubits for each size.\n", + "_SMALL = 10\n", + "_MEDIUM = 20\n", + "\n", + "# The function's defaults for the molecule_options that decide the active space.\n", + "_DEFAULTS = {\n", + " \"active_orbitals\": None,\n", + " \"avas_aolabels\": None,\n", + " \"avas_threshold\": 0.2,\n", + " \"basis\": \"sto-3g\",\n", + " \"charge\": 0,\n", + " \"symmetry\": False,\n", + " \"symmetry_subgroup\": None,\n", + " \"unit\": \"angstrom\",\n", + " \"nucmod\": None,\n", + " \"pseudo\": None,\n", + " \"cart\": False,\n", + " \"magmom\": None,\n", + "}\n", + "\n", + "# AVAS weights below this are numerical noise; counting them would make the size vary\n", + "# from one call to the next.\n", + "_AVAS_WEIGHT_TOLERANCE = 1e-10\n", + "\n", + "\n", + "def estimate_size(problem: Any, **kwargs: Any) -> Size:\n", + " \"\"\"Return the size (\"s\", \"m\" or \"l\") required to run the function.\"\"\"\n", + " metrics = _measure(problem, **kwargs)\n", + " if _is_small(metrics):\n", + " return \"s\"\n", + " if _is_medium(metrics):\n", + " return \"m\"\n", + " return \"l\"\n", + "\n", + "\n", + "def _measure(problem: Any, **kwargs: Any) -> dict:\n", + " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", + " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", + " mol = gto.M(\n", + " atom=problem,\n", + " basis=options[\"basis\"],\n", + " spin=0, # the function runs singlets only\n", + " charge=options[\"charge\"],\n", + " symmetry=options[\"symmetry\"],\n", + " symmetry_subgroup=options[\"symmetry_subgroup\"],\n", + " unit=options[\"unit\"],\n", + " nucmod=options[\"nucmod\"],\n", + " pseudo=options[\"pseudo\"],\n", + " cart=options[\"cart\"],\n", + " magmom=options[\"magmom\"],\n", + " verbose=0,\n", + " )\n", + "\n", + " if options[\"avas_aolabels\"] is None:\n", + " # The active space is the orbitals given, or the whole basis; building the molecule\n", + " # is enough to know it.\n", + " if options[\"active_orbitals\"]:\n", + " return {\"num_qubits\": 2 * len(options[\"active_orbitals\"])}\n", + " return {\"num_qubits\": 2 * mol.nao_nr()}\n", + "\n", + " # AVAS picks the active space from an RHF, so it has to run one.\n", + " rhf = scf.RHF(mol)\n", + " rhf.verbose = 0\n", + " rhf.kernel()\n", + " selection = avas.AVAS(\n", + " mf=rhf,\n", + " aolabels=options[\"avas_aolabels\"],\n", + " threshold=max(options[\"avas_threshold\"], _AVAS_WEIGHT_TOLERANCE),\n", + " )\n", + " selection.verbose = 0\n", + " selection.kernel()\n", + " return {\"num_qubits\": 2 * selection.ncas}\n", + "\n", + "\n", + "def _is_small(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _SMALL\n", + "\n", + "\n", + "def _is_medium(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 'm'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _MEDIUM\n", + "\n", + "\n", + "def validate_size(provided_size: Size, problem: Any, **kwargs: Any) -> None:\n", + " \"\"\"Call at the start of the function. Raise if ``provided_size`` is smaller than\n", + " the estimated size; the estimated size or a larger one is accepted.\"\"\"\n", + " expected = estimate_size(problem, **kwargs)\n", + " if _ORDER[provided_size] < _ORDER[expected]:\n", + " raise ValueError(\n", + " f\"Size '{provided_size}' is too small for this problem; expected '{expected}' or larger.\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "b71c3d58", + "metadata": {}, + "source": [ + "For the NH3 molecule in the [Example](#example):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "216827a3-35e1-4499-b924-6ec5b6b7af92", + "metadata": {}, + "outputs": [], + "source": [ + "# NH3 in STO-3G has 8 orbitals, so 16 qubits: \"m\"\n", + "print(estimate_size(geometry, molecule_options=molecule_options))" + ] + }, { "cell_type": "markdown", "id": "7c1e4a2b", @@ -1028,7 +1047,7 @@ "### 5.0.3\n", "\n", "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", - "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Check the size before you run](#check-the-size-before-you-run).\n", + "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Size estimator](#size-estimator).\n", "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Fetch error messages](#fetch-error-messages).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", From 769678a27888f353b7c6d90b189c85d66b22a08f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:45:42 +0900 Subject: [PATCH 37/59] Check the arguments before run(), and say it does not check the size validate_arguments() came after the first run(), so "check without running" followed a run. It now comes first, and says the size is the estimator's job. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 69 ++++++++++++++++-------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index f22a8d7dc8d6..e97be30ae429 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -245,6 +245,42 @@ "hivqe_options = {\"shots\": 100, \"max_iter\": 20}" ] }, + { + "cell_type": "markdown", + "id": "3c7a91e2", + "metadata": {}, + "source": [ + "Before running, you can check the arguments with `validate_arguments()`. It\n", + "checks their names, types and ranges against the function's argument schema\n", + "without creating a job, so it costs nothing. It returns `{\"valid\": True}`, or\n", + "raises an exception naming the argument. `run()` makes the same check before\n", + "it creates a job, so a call that fails it is refused straight away and is not\n", + "billed. `function.arguments_schema` shows every argument the function accepts,\n", + "with its type, range and default.\n", + "\n", + "This check does not cover the function size. To check that the size fits the\n", + "problem, use the [size estimator](#size-estimator)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d0b84f6", + "metadata": {}, + "outputs": [], + "source": [ + "function.validate_arguments(\n", + " {\n", + " \"geometry\": geometry,\n", + " \"backend_name\": backend_name,\n", + " \"max_states\": 2000,\n", + " \"max_expansion_states\": 10,\n", + " \"molecule_options\": molecule_options,\n", + " \"hivqe_options\": hivqe_options,\n", + " }\n", + ")" + ] + }, { "cell_type": "markdown", "id": "bf180336", @@ -310,39 +346,6 @@ "This example then utilizes 16 qubits with 8 orbitals of sto3g basis for an NH3 molecule." ] }, - { - "cell_type": "markdown", - "id": "3c7a91e2", - "metadata": {}, - "source": [ - "`run()` checks the arguments against the function's argument schema before a\n", - "job is created. An argument with the wrong name, type or range is refused\n", - "straight away: `run()` raises an exception naming the argument, no job is\n", - "created, and nothing is billed. To check arguments without running anything,\n", - "use `validate_arguments()`, which returns `{\"valid\": True}` or raises the same\n", - "exception. `function.arguments_schema` shows every argument the function\n", - "accepts, with its type, range and default." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5d0b84f6", - "metadata": {}, - "outputs": [], - "source": [ - "function.validate_arguments(\n", - " {\n", - " \"geometry\": geometry,\n", - " \"backend_name\": backend_name,\n", - " \"max_states\": 2000,\n", - " \"max_expansion_states\": 10,\n", - " \"molecule_options\": molecule_options,\n", - " \"hivqe_options\": hivqe_options,\n", - " }\n", - ")" - ] - }, { "cell_type": "markdown", "id": "ad1c9bcb", From adfc9c6bf6bc3d6ef2a71adcfe472ccacc992138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:48:43 +0900 Subject: [PATCH 38/59] Match the API reference to the schema, and link the options from the example The reference gave magmom a default of 1_000 (it is None), gave avas_threshold a range of 0 to 2 that nothing checks, left out max_states' upper bound, and did not list use_session at all. The example now links to the full option lists. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 13 +++++++++++-- docs/guides/qunova-chemistry.ipynb | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 1124472631a8..3409e9525dcb 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -40,6 +40,7 @@ Name of the backend to make the query. The maximum subspace dimension for the diagonalization. Fewer states will be used if the number is not a perfect square. - Required: Yes +- Valid range: Between 1 and 400 000 000 - Example: `100` @@ -47,6 +48,7 @@ The maximum subspace dimension for the diagonalization. Fewer states will be use The maximum number of classically-generated CI states to be included in each iteration. - Required: Yes +- Valid range: At least 1 - Example: `10` @@ -122,7 +124,7 @@ Specifies whether to use cartesian GTOs as the angular momentum basis functions #### `magmom` - + Sets the colinear spin magnetic moment of each atom. By default, this is None and each atom is initialized with a spin of zero. - Valid range: See [pyscf documentation](https://pyscf.org/pyscf_api_docs/pyscf.gto.html#pyscf.gto.mole.MoleBase.build) @@ -136,7 +138,6 @@ This defines Atomic Orbital to be included in AVAS scheme. See [AVAS documentati #### `avas_threshold` This specifies the cutoff value used to determine which Atomic Orbitals (AOs) are retained in the active space. -- Valid range: Between 0.0 and 2.0 #### `noons_level` @@ -230,6 +231,14 @@ The tolerance for predicting which states should be screened out of the subspace - Example: `{"shots": 10_000, "max_iter": 10 }` +### `use_session` + +Runs the function's quantum jobs in one Qiskit Runtime session, so that jobs +after the first do not wait in the queue again. +- Required: No +- Example: `True` + + ### `function_size` Which resources the job runs on, and what the run is billed. It is passed to diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index e97be30ae429..91fc99f31332 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -230,7 +230,10 @@ "id": "64429e13", "metadata": {}, "source": [ - "Additional options can be defined and provided for molecular system in the following dictionary format." + "Additional options can be defined and provided for molecular system in the following dictionary format.\n", + "For every option you can set, with its type, default and valid range, see\n", + "[`molecule_options`](/docs/api/functions/qunova-chemistry#molecule_options) and\n", + "[`hivqe_options`](/docs/api/functions/qunova-chemistry#hivqe_options) in the API reference." ] }, { From a92dfce6f68bbd4f0dd7fbe029b40ea7deeb03ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:52:20 +0900 Subject: [PATCH 39/59] Keep each benchmark time on one line On a narrow page the eight-column table wrapped "46547 s" between the number and the unit. A non-breaking space keeps them together. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 91fc99f31332..ac03e3d2ce5a 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -769,12 +769,12 @@ "\n", "| Chemical system | Number of qubits | Exact matrix size | HI-VQE matrix size | E(diff) from exact (mHa) | Number of iteration | Total time | QPU runtime usage |\n", "| ------------------ | ---------------- | ----------------- | ------------------- | ------------------------ | ------------------- | ------------- | ----------------- |\n", - "| $NH_3$ (8o,10e) | 16 | 3136 | 1936 | 0.08 | 6 | 37 s | 34 s |\n", - "| $Li_2S$ (10o,10e) | 20 | 63504 | 3969 | 0.60 | 5 | 250 s | 50 s |\n", - "| $NH_3$ (15o,10e) | 30 | 9018009 | 49729 | 0.90 | 5 | 354 s | 54 s |\n", - "| $N_2$ (16o,14e) | 32 | 130873600 | 1798281 | 1.10 | 9 | 6531 s | 121 s |\n", - "| $3H_2O$ (18o,24e) | 36 | 344622096 | 399424 | 0.90 | 24 | 5174 s | 130 s |\n", - "| $N_2$ (20o,14e) | 40 | 6009350400 | 9012004 | 1.20 | 21 | 46547 s | 258 s |" + "| $NH_3$ (8o,10e) | 16 | 3136 | 1936 | 0.08 | 6 | 37 s | 34 s |\n", + "| $Li_2S$ (10o,10e) | 20 | 63504 | 3969 | 0.60 | 5 | 250 s | 50 s |\n", + "| $NH_3$ (15o,10e) | 30 | 9018009 | 49729 | 0.90 | 5 | 354 s | 54 s |\n", + "| $N_2$ (16o,14e) | 32 | 130873600 | 1798281 | 1.10 | 9 | 6531 s | 121 s |\n", + "| $3H_2O$ (18o,24e) | 36 | 344622096 | 399424 | 0.90 | 24 | 5174 s | 130 s |\n", + "| $N_2$ (20o,14e) | 40 | 6009350400 | 9012004 | 1.20 | 21 | 46547 s | 258 s |" ] }, { From ead71bb923d4b31050a96f7e4f8826dc587a88f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 16:55:35 +0900 Subject: [PATCH 40/59] Shorten the size estimator's docstring, as in the function's copy Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index ac03e3d2ce5a..f8e8a3224655 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -898,27 +898,12 @@ "metadata": {}, "outputs": [], "source": [ - "\"\"\"\n", - "Size estimator for Qunova HI-VQE Chemistry -- a function that is neither a circuit function\n", - "nor an optimization function, so it follows ``size_estimator_template.py``.\n", - "\n", - "Input: the \"problem\" the function accepts -- ``geometry``, as passed to ``function.run()`` --\n", - " plus the other function inputs as ``**kwargs``. Only ``molecule_options`` is read;\n", - " everything else is accepted and ignored.\n", - "Output: ``\"s\"``, ``\"m\"`` or ``\"l\"``.\n", - "\n", - "What drives the resource usage is the number of qubits the problem needs, two per active\n", - "orbital, so that is what ``_measure`` returns. The active space is the one the function\n", - "builds from ``molecule_options``:\n", - "\n", - "- ``avas_aolabels`` set: the orbitals AVAS selects, at ``avas_threshold`` (default 0.2)\n", - "- ``active_orbitals`` set: those orbitals\n", - "- neither: every orbital in the basis\n", - "\n", - "Only AVAS needs a calculation (one RHF); the other two only build the molecule. The result\n", - "depends on nothing but the input, so the same call always gives the same size.\n", + "\"\"\"Size estimator for Qunova HI-VQE Chemistry. Requires PySCF only.\n", "\n", - "Requires ``pyscf``. Self-contained: it imports nothing from the function.\n", + "estimate_size(geometry, molecule_options=...) returns \"s\", \"m\" or \"l\" from the\n", + "number of qubits the problem needs: two per active orbital. The active space is\n", + "the orbitals AVAS selects if avas_aolabels is set, else active_orbitals if set,\n", + "else every orbital in the basis. Other function inputs are accepted and ignored.\n", "\"\"\"\n", "from __future__ import annotations\n", "\n", From d573802f293cbc86cb7feadd05fdd25275ddcff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Mon, 12 Oct 2026 17:08:44 +0900 Subject: [PATCH 41/59] Fix a stale changelog link, and split the size rules by case The 5.0.3 entry sent readers to Fetch error messages for validate_arguments(), which now lives in the Example. Next steps listed the same tutorial twice. What happens at a wrong size is now one bullet per case, and the example's qubit count sits with the run it explains. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 33 ++++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index f8e8a3224655..d866431b1711 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -289,7 +289,9 @@ "id": "bf180336", "metadata": {}, "source": [ - "Execute the function with geometry and option inputs." + "Execute the function with geometry and option inputs. This example uses 16\n", + "qubits, from the 8 orbitals of the STO-3G basis for NH3, so it runs at the\n", + "default function size `\"m\"`." ] }, { @@ -341,14 +343,6 @@ "print(\"Job ID:\", job.job_id)" ] }, - { - "cell_type": "markdown", - "id": "608cf736", - "metadata": {}, - "source": [ - "This example then utilizes 16 qubits with 8 orbitals of sto3g basis for an NH3 molecule." - ] - }, { "cell_type": "markdown", "id": "ad1c9bcb", @@ -556,13 +550,17 @@ "\n", "If you leave `function_size` out, the job runs at `\"m\"`.\n", "\n", - "A size smaller than the problem needs is rejected before any QPU time is\n", - "spent, and the error names the size to use instead. This applies to runs with\n", - "a license token too. Without a token, the rejected run is still billed at the\n", - "size you chose, because a run is billed once it starts. A size\n", - "larger than it needs runs and is billed at that larger size, with a warning\n", - "telling you which size would have been enough. To get the size right the\n", - "first time, check it before you submit, as the next section shows." + "If the size does not match the problem:\n", + "\n", + "- **Too small:** the run is rejected before any QPU time is spent, with error\n", + " code 1221 naming the size to use. This applies to runs with a license token\n", + " too. Without a token, the rejected run is still billed at the size you\n", + " chose, because a run is billed once it starts.\n", + "- **Too large:** the run goes ahead and is billed at the larger size, with a\n", + " warning naming the size that would have been enough.\n", + "\n", + "To get the size right the first time, check it before you submit, as the next\n", + "section shows." ] }, { @@ -1039,7 +1037,7 @@ "\n", "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Size estimator](#size-estimator).\n", - "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Fetch error messages](#fetch-error-messages).\n", + "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Example](#example).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", "- `avas_threshold` accepts a whole number, such as `0`.\n", @@ -1079,7 +1077,6 @@ "\n", "- Request access and a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", - "- Try the [Compute dissociation PES curve for FeP-NO with HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", "- Try the [Dissociation PES curves with Qunova HiVQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "" From 4908c68277e2ee8d089e7739bf3a7a133bf4a6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 14 Oct 2026 16:08:24 +0900 Subject: [PATCH 42/59] Say the guide's backend must be one you can access, not its qubit count Every IBM device has more qubits than these examples use, so the qubit counts never limit the choice; access does. The size each example needs stays in its function_size comment. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index d866431b1711..02ccf28e5cf5 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -304,7 +304,7 @@ "# Run HI-VQE\n", "job = function.run(\n", " geometry=geometry,\n", - " # `backend_name` is the name of a backend with at least 16 qubits,\n", + " # `backend_name` is a backend you have access to,\n", " # for example, \"ibm_marrakesh\".\n", " backend_name=backend_name,\n", " # `function_size` sets the resources the job runs on and what it\n", @@ -634,7 +634,7 @@ ")\n", "job = hivqe.run(\n", " geometry=molecule_geometry,\n", - " backend_name=backend_name, # can use any device with at least 14 qubits\n", + " backend_name=backend_name, # a backend you have access to\n", " # 14 qubits fit the default \"m\"; a problem over 20 qubits needs \"l\"\n", " function_size=\"m\",\n", " max_states=10000,\n", @@ -711,7 +711,7 @@ " # Run HI-VQE\n", " job = function.run(\n", " geometry=Li2S_geoms[geom],\n", - " backend_name=backend_name, # can use any device with at least 38 qubits\n", + " backend_name=backend_name, # a backend you have access to\n", " function_size=\"l\", # 38 qubits, more than \"m\" allows\n", " max_states=2000,\n", " max_expansion_states=10,\n", From e550534537a2b1f2d22707d2d9c9787e7b8182ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 14 Oct 2026 17:05:48 +0900 Subject: [PATCH 43/59] Add error code 4631 and the 5.0.4 changelog Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 02ccf28e5cf5..de7036fafbcf 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -865,6 +865,11 @@ "| 2409 | The license has expired, has been revoked, or was used from an instance it was not issued for |\n", "| 4500 | The problem needs more qubits than your license or trial access allows |\n", "| 4630 | Your license could not be read. Nothing is wrong with what you submitted; contact us with the job ID |\n", + "| 4631 | A Qiskit Runtime job made by the run failed or was cancelled, and Runtime gave no error code of its own. Submit the job again |\n", + "\n", + "When a Qiskit Runtime job made by the run fails with an error code of its\n", + "own, such as 1305, that code is reported instead; look it up in the\n", + "registry.\n", "\n", "Several codes cover more than one cause, so read the message as well as the\n", "code. If you need help with a failure, send the Function job ID to\n", @@ -1033,6 +1038,12 @@ "source": [ "## Changelog\n", "\n", + "### 5.0.4\n", + "\n", + "- A run whose Qiskit Runtime job fails or is cancelled now reports Runtime's own error code, or 4631 when Runtime gives none, with a message and solution. It used to report an unexpected error, and the result lost its `\"resource_usage\"`.\n", + "- A failed run reports its error once. It used to be reported twice.\n", + "- `\"resource_usage\"` lists every stage of the job, with zero for a stage the run did not reach.\n", + "\n", "### 5.0.3\n", "\n", "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", From b6a86a50f14cf3d54b4789ebc0fb81204cbdb7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Wed, 14 Oct 2026 17:39:52 +0900 Subject: [PATCH 44/59] Document running from an uploaded FCIDUMP file Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 9 +- docs/guides/qunova-chemistry.ipynb | 131 +++++++++++++++++++++++- 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 3409e9525dcb..cad1122839dc 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -25,10 +25,17 @@ type, range and default. ### `geometry` This can be either a string or structured lists containing atom and coordinate pairs. If this is given as a string, it must be a molecule geometry in Cartesian Coordinate Format. If this is given as a list, it should be given as a list of lists that each contain an atom string and coordinate tuple. -- Required: Yes +- Required: Yes, unless `fcidump_file_name` is given - Example: `[['O', (0, 0, 0)], ['H', (0, 1, 0)], ['H', (0, 0, 1)]]` or `"O 0 0 0; H 0 1 0; H 0 0 1"` +### `fcidump_file_name` + +The name of an FCIDUMP file you uploaded to the function with `file_upload`, without a directory part, to use in place of `geometry`. The integrals of the file are used as they are, and `geometry` and `molecule_options` are ignored. The file can be plain text or gzip-compressed, and must describe a closed-shell singlet. See [Run from an FCIDUMP file](/docs/guides/qunova-chemistry#run-from-an-fcidump-file). +- Required: Yes, unless `geometry` is given +- Example: `"nh3.FCIDUMP"` + + ### `backend_name` Name of the backend to make the query. diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index de7036fafbcf..59de83ac4f1b 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -505,6 +505,72 @@ " final_energy_variance = f[\"final_energy_variance\"][0]" ] }, + { + "cell_type": "markdown", + "id": "32946cb4", + "metadata": {}, + "source": [ + "#### Run from an FCIDUMP file\n", + "\n", + "Instead of a geometry, you can give the problem as an FCIDUMP file of its\n", + "integrals, for example one written by PySCF or by another quantum chemistry\n", + "program. Upload the file to the function, then pass its name as\n", + "`fcidump_file_name`:\n", + "\n", + "- The integrals are used as they are. No mean-field calculation is run, and\n", + " `geometry` and `molecule_options` are ignored if you pass them as well.\n", + "- Every orbital in the file is active, so the problem uses 2 × `NORB` qubits.\n", + "- The file can be plain text or gzip-compressed. Only closed-shell singlets\n", + " are supported: `MS2=0` and an even `NELEC`.\n", + "- The first `NELEC`/2 orbitals are taken as the occupied orbitals of the\n", + " reference state. If the orbitals of the file are not in order of energy,\n", + " the job log says so, as the run can converge slowly from that state.\n", + "\n", + "This writes the NH3 problem of the example to a file with PySCF:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d629f4a", + "metadata": {}, + "outputs": [], + "source": [ + "from pyscf import gto, scf\n", + "from pyscf.tools import fcidump\n", + "\n", + "mol = gto.M(atom=geometry, basis=\"sto3g\")\n", + "fcidump.from_scf(scf.RHF(mol).run(), \"nh3.FCIDUMP\")" + ] + }, + { + "cell_type": "markdown", + "id": "b4173b97", + "metadata": {}, + "source": [ + "Upload the file and run. Pass the file name alone, without a directory. The\n", + "file stays uploaded until you remove it with `serverless.file_delete()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e574ac1", + "metadata": {}, + "outputs": [], + "source": [ + "serverless.file_upload(\"nh3.FCIDUMP\", function)\n", + "\n", + "job = function.run(\n", + " fcidump_file_name=\"nh3.FCIDUMP\",\n", + " backend_name=backend_name,\n", + " function_size=\"m\",\n", + " max_states=2000,\n", + " max_expansion_states=10,\n", + " hivqe_options=hivqe_options,\n", + ")" + ] + }, { "cell_type": "markdown", "id": "77066575-76b0-4416-a033-a33083d418f3", @@ -579,6 +645,10 @@ "| `active_orbitals` set | 2 × the number of active orbitals |\n", "| Neither | 2 × the number of atomic orbitals in the basis |\n", "\n", + "With [`fcidump_file_name`](#run-from-an-fcidump-file), the size depends only on\n", + "the file: 2 × `NORB`, the number of orbitals in its header. `molecule_options`\n", + "are then ignored.\n", + "\n", "Submit at the smallest size that fits: up to 10 qubits is `\"s\"`, up to 20 is\n", "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", @@ -906,10 +976,14 @@ "estimate_size(geometry, molecule_options=...) returns \"s\", \"m\" or \"l\" from the\n", "number of qubits the problem needs: two per active orbital. The active space is\n", "the orbitals AVAS selects if avas_aolabels is set, else active_orbitals if set,\n", - "else every orbital in the basis. Other function inputs are accepted and ignored.\n", + "else every orbital in the basis. With fcidump_file_name, the path of an FCIDUMP\n", + "file, it is every orbital of the file, and geometry and molecule_options are\n", + "ignored, as the function ignores them. Other inputs are accepted and ignored.\n", "\"\"\"\n", "from __future__ import annotations\n", "\n", + "import gzip\n", + "import re\n", "from typing import Any, Literal\n", "\n", "from pyscf import gto, scf\n", @@ -955,6 +1029,8 @@ "\n", "def _measure(problem: Any, **kwargs: Any) -> dict:\n", " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", + " if kwargs.get(\"fcidump_file_name\"):\n", + " return {\"num_qubits\": 2 * _fcidump_num_orbitals(kwargs[\"fcidump_file_name\"])}\n", " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", " mol = gto.M(\n", " atom=problem,\n", @@ -992,6 +1068,38 @@ " return {\"num_qubits\": 2 * selection.ncas}\n", "\n", "\n", + "# An FCIDUMP header is read up to its end (&END or /). It is a few lines; its\n", + "# only part that grows with the problem is ORBSYM, a few characters per orbital.\n", + "_FCIDUMP_MAX_HEADER_LINES = 1000\n", + "\n", + "\n", + "def _fcidump_num_orbitals(path: str) -> int:\n", + " \"\"\"NORB from the header of an FCIDUMP file, plain or gzip-compressed,\n", + " without reading the integrals.\"\"\"\n", + " with open(path, \"rb\") as raw:\n", + " gzipped = raw.read(2) == b\"\\x1f\\x8b\"\n", + " opener = gzip.open if gzipped else open\n", + " header = []\n", + " try:\n", + " with opener(path, \"rt\") as in_file:\n", + " for line_number, line in enumerate(in_file):\n", + " header.append(line.upper())\n", + " if \"&END\" in header[-1] or \"/\" in line:\n", + " break\n", + " if line_number >= _FCIDUMP_MAX_HEADER_LINES:\n", + " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " else:\n", + " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " except (UnicodeDecodeError, OSError, EOFError) as error:\n", + " raise ValueError(\n", + " \"The FCIDUMP file could not be read as text or as gzip-compressed text.\"\n", + " ) from error\n", + " match = re.search(r\"NORB\\s*=\\s*(\\d+)\", \"\".join(header))\n", + " if match is None or int(match.group(1)) < 1:\n", + " raise ValueError(\"No valid NORB entry was found in the FCIDUMP file header.\")\n", + " return int(match.group(1))\n", + "\n", + "\n", "def _is_small(metrics: dict) -> bool:\n", " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", " return metrics[\"num_qubits\"] <= _SMALL\n", @@ -1031,6 +1139,26 @@ "print(estimate_size(geometry, molecule_options=molecule_options))" ] }, + { + "cell_type": "markdown", + "id": "80af2a86", + "metadata": {}, + "source": [ + "For an FCIDUMP file, pass its path as `fcidump_file_name`, as you will pass its\n", + "name to `run()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e20b4b85", + "metadata": {}, + "outputs": [], + "source": [ + "# nh3.FCIDUMP, written in \"Run from an FCIDUMP file\", has 8 orbitals: \"m\"\n", + "print(estimate_size(None, fcidump_file_name=\"nh3.FCIDUMP\"))" + ] + }, { "cell_type": "markdown", "id": "7c1e4a2b", @@ -1040,6 +1168,7 @@ "\n", "### 5.0.4\n", "\n", + "- Runs can take the problem from an FCIDUMP file you upload, in place of a geometry: pass its name as `fcidump_file_name`. The size estimator accepts it too. See [Run from an FCIDUMP file](#run-from-an-fcidump-file).\n", "- A run whose Qiskit Runtime job fails or is cancelled now reports Runtime's own error code, or 4631 when Runtime gives none, with a message and solution. It used to report an unexpected error, and the result lost its `\"resource_usage\"`.\n", "- A failed run reports its error once. It used to be reported twice.\n", "- `\"resource_usage\"` lists every stage of the job, with zero for a stage the run did not reach.\n", From 81a11de6d39cb32964fbd7588943a13921eb646c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:10:37 +0900 Subject: [PATCH 45/59] Restructure the HI-VQE guide around the reader's questions A new reader could not tell who they were or what a run costs: the two ways to use the function were never named, "trial" appeared only in a note, and billing was spread over five places, with the size estimator near the end of the page. - Get started opens with a table of the two ways to use HI-VQE, usage-based and licensed: how to start, qubits, what you pay. - Function sizes and billing gathers sizes and fees, a table of what is billed, the qubit rule and the size estimator in one section. - The size fee is called the per-run fee, since "license fee" is also what a licensed customer pays Qunova. - The error example and the Li2S cell say that they are billed. - Headings use ## and ### only; Benchmarks moves under Performance. The API reference and tutorial links into the guide follow the new anchors. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 8 +- docs/guides/qunova-chemistry.ipynb | 778 ++++++++++++------------ docs/tutorials/qunova-hivqe.ipynb | 4 +- 3 files changed, 408 insertions(+), 382 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index cad1122839dc..10d03486c44b 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -252,7 +252,7 @@ Which resources the job runs on, and what the run is billed. It is passed to `run()` like the arguments above, though it belongs to the platform rather than to this function. -| `function_size` | Qubits | Compute profile | License fee per run | +| `function_size` | Qubits | Compute profile | Per-run fee | |-----|-----|-----|-----| | `"s"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU | | `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | @@ -262,9 +262,9 @@ A size smaller than the problem needs is rejected before any QPU time is spent, with error code 1221 naming the size to use; the rejected run is still billed at the size it was submitted at. A size larger than it needs runs, and is billed at that larger size. To check the size before submitting, see -[Check the size before you run](/docs/guides/qunova-chemistry#check-the-size-before-you-run). This applies to runs made -with a license token and to trial runs too, since the size is the machine the -job runs on; a license token also sets its own qubit limit. +[Qubits your problem needs](/docs/guides/qunova-chemistry#qubits-your-problem-needs). This applies to runs made +with a license token too, since the size is the machine the job runs on; a +license token also sets its own qubit limit. - Required: No - Example: `"l"` diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 59de83ac4f1b..a4bf521b11fd 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -135,9 +135,24 @@ "source": [ "## Get started\n", "\n", - "Runs are billed per execution at the function size you choose, with no qubit limit; see [Limits and billing](#limits-and-billing). If you hold or need a license, see [Licensed use](#licensed-use).\n", + "### Ways to use HI-VQE\n", "\n", - "The instance you authenticate with needs [Qiskit Functions access enabled](/docs/guides/access-instances-platform-apis#configure-qiskit-functions-access-on-an-instance), or the function will not appear in the catalog.\n", + "You can use HI-VQE in one of two ways. Either way, the instance you\n", + "authenticate with needs [Qiskit Functions access\n", + "enabled](/docs/guides/access-instances-platform-apis#configure-qiskit-functions-access-on-an-instance),\n", + "or the function will not appear in the catalog.\n", + "\n", + "| | Usage-based | Licensed |\n", + "| --- | --- | --- |\n", + "| **How to start** | Run the function; there is nothing to sign up for | [Request a license](https://forms.office.com/r/zN3hvMTqJ1) from Qunova |\n", + "| **Qubits** | No limit | Set by your license |\n", + "| **What you pay** | A per-run fee for the [function size](#function-sizes-and-billing) you choose, plus the QPU and classical compute time the run uses | Your license fee to Qunova, plus the QPU and classical compute time the run uses |\n", + "| **License token** | Not needed | Needed; see [Licensed use](#licensed-use) |\n", + "\n", + "The examples on this page are usage-based runs. With a license, only the way\n", + "you load the function changes.\n", + "\n", + "### Load the function\n", "\n", "Save your [IBM Quantum® API key](http://quantum.cloud.ibm.com/) [to your local environment](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) if you have not already, then select the Qiskit Function as follows:" ] @@ -204,7 +219,7 @@ "id": "b03aa968", "metadata": {}, "source": [ - "#### Define the molecular geometry and options\n", + "### Define the molecule\n", "\n", "The molecular geometry of NH3 is provided with Cartesian coordinates separated with \";\" for each atom." ] @@ -253,16 +268,16 @@ "id": "3c7a91e2", "metadata": {}, "source": [ + "### Check the arguments\n", + "\n", "Before running, you can check the arguments with `validate_arguments()`. It\n", "checks their names, types and ranges against the function's argument schema\n", - "without creating a job, so it costs nothing. It returns `{\"valid\": True}`, or\n", - "raises an exception naming the argument. `run()` makes the same check before\n", - "it creates a job, so a call that fails it is refused straight away and is not\n", - "billed. `function.arguments_schema` shows every argument the function accepts,\n", - "with its type, range and default.\n", - "\n", - "This check does not cover the function size. To check that the size fits the\n", - "problem, use the [size estimator](#size-estimator)." + "without creating a job, so it is free. It returns `{\"valid\": True}`, or raises\n", + "an exception describing what failed. `function.arguments_schema` shows every\n", + "argument the function accepts, with its type, range and default.\n", + "\n", + "This check does not cover the function size; see [Qubits your problem\n", + "needs](#qubits-your-problem-needs)." ] }, { @@ -289,9 +304,12 @@ "id": "bf180336", "metadata": {}, "source": [ - "Execute the function with geometry and option inputs. This example uses 16\n", - "qubits, from the 8 orbitals of the STO-3G basis for NH3, so it runs at the\n", - "default function size `\"m\"`." + "### Run the function\n", + "\n", + "Run the function with the geometry and options. NH3 has 8 orbitals in the\n", + "STO-3G basis, so the problem uses 16 qubits and fits the default function\n", + "size, `\"m\"`. A run is billed once it starts; see [Function sizes and\n", + "billing](#function-sizes-and-billing)." ] }, { @@ -308,7 +326,7 @@ " # for example, \"ibm_marrakesh\".\n", " backend_name=backend_name,\n", " # `function_size` sets the resources the job runs on and what it\n", - " # costs. See \"Limits and billing\" below.\n", + " # costs. See \"Function sizes and billing\" below.\n", " function_size=\"m\",\n", " max_states=2000,\n", " max_expansion_states=10,\n", @@ -348,6 +366,8 @@ "id": "ad1c9bcb", "metadata": {}, "source": [ + "### Get the results\n", + "\n", "Check your Qiskit Function workload's [status](/docs/guides/functions-get-started#check-job-status) or return [results](/docs/guides/functions-get-started#retrieve-results) as follows:" ] }, @@ -454,6 +474,8 @@ "id": "03b51be7", "metadata": {}, "source": [ + "### Download the results file\n", + "\n", "To download the results file for the calculation, you will need to create a `QiskitServerless` instance using the same credentials as `QiskitFunctionCatalog`." ] }, @@ -510,7 +532,7 @@ "id": "32946cb4", "metadata": {}, "source": [ - "#### Run from an FCIDUMP file\n", + "### Run from an FCIDUMP file\n", "\n", "Instead of a geometry, you can give the problem as an FCIDUMP file of its\n", "integrals, for example one written by PySCF or by another quantum chemistry\n", @@ -526,7 +548,8 @@ " reference state. If the orbitals of the file are not in order of energy,\n", " the job log says so, as the run can converge slowly from that state.\n", "\n", - "This writes the NH3 problem of the example to a file with PySCF:" + "This writes the NH3 problem of the example to a file with PySCF, which you\n", + "can install with `pip install pyscf`:" ] }, { @@ -573,24 +596,14 @@ }, { "cell_type": "markdown", - "id": "77066575-76b0-4416-a033-a33083d418f3", + "id": "30399da1", "metadata": {}, "source": [ - "## Limits and billing\n", - "\n", - "What applies to your runs depends on whether you hold a license token.\n", - "\n", - "| | Without a token | With a license token |\n", - "| --- | --- | --- |\n", - "| **Qubits** | No limit | What your license grants |\n", - "| **What you pay** | Per run, at the function size you choose | Per your license agreement |\n", + "## Function sizes and billing\n", "\n", - "\n", - " Trial access is limited to 20 qubits. A job that needs more fails with error code 4500.\n", - "\n", - "\n", - "Every run is submitted at a function size and is checked against it, with or\n", - "without a token. The two sections that follow explain how to choose it." + "Every run is submitted at a function size, which sets the resources it runs\n", + "on and, for a usage-based run, its per-run fee. The size is checked against\n", + "the problem with or without a license token." ] }, { @@ -598,35 +611,45 @@ "id": "df5164aa-c7ca-438e-a414-f7f5a6795aa5", "metadata": {}, "source": [ - "### Function sizes\n", + "### Sizes and fees\n", "\n", - "`function_size` tells the platform what resources to run the job on, and it\n", - "is what the run is billed at. Pass it to `run()` alongside the function's own\n", - "arguments.\n", + "Pass `function_size` to `run()` alongside the function's own arguments. If\n", + "you leave it out, the run uses `\"m\"`.\n", "\n", - "| `function_size` | Qubits | License fee per run |\n", - "| --- | --- | --- |\n", - "| `\"s\"` | Up to 10 | 0.4 RU |\n", - "| `\"m\"` | Up to 20 | 1.0 RU |\n", - "| `\"l\"` | No limit | 4.0 RU |\n", + "| `function_size` | Qubits | Compute | Per-run fee |\n", + "| --- | --- | --- | --- |\n", + "| `\"s\"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU |\n", + "| `\"m\"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU |\n", + "| `\"l\"` | No limit | 48 CPUs, 768 GB | 4.0 RU |\n", "\n", - "Fees are given in resource units. See [IBM Quantum\n", + "A usage-based run costs its per-run fee plus the QPU and classical compute\n", + "time it uses. Fees are given in resource units (RU); see [IBM Quantum\n", "plans](/docs/guides/plans-overview) for what a resource unit costs on your\n", - "plan.\n", - "\n", - "If you leave `function_size` out, the job runs at `\"m\"`.\n", - "\n", - "If the size does not match the problem:\n", + "plan. With a license, you pay your license fee to Qunova in place of the\n", + "per-run fee." + ] + }, + { + "cell_type": "markdown", + "id": "6cf9a7ea", + "metadata": {}, + "source": [ + "### What is billed\n", "\n", - "- **Too small:** the run is rejected before any QPU time is spent, with error\n", - " code 1221 naming the size to use. This applies to runs with a license token\n", - " too. Without a token, the rejected run is still billed at the size you\n", - " chose, because a run is billed once it starts.\n", - "- **Too large:** the run goes ahead and is billed at the larger size, with a\n", - " warning naming the size that would have been enough.\n", + "For a usage-based run:\n", "\n", - "To get the size right the first time, check it before you submit, as the next\n", - "section shows." + "| What happens | Billed |\n", + "| --- | --- |\n", + "| You call `validate_arguments()` | No |\n", + "| You call `run()` with a wrong argument name, type or range | No. The call is refused before a job is created |\n", + "| The run completes | Yes |\n", + "| The run fails after it starts, for example on an invalid geometry | Yes |\n", + "| `function_size` is too small for the problem | Yes, at the size you chose. The run is rejected with error code 1221, naming the size to use, before any QPU time is spent |\n", + "| `function_size` is larger than needed | Yes, at the larger size. The run goes ahead, with a warning naming the size that would have been enough |\n", + "\n", + "A run with a license token at too small a size is rejected in the same way.\n", + "To get the size right the first time, work it out before you submit, as the\n", + "next two sections show." ] }, { @@ -634,7 +657,7 @@ "id": "5569c36e-04c2-453f-a7fd-89b36b9d0d7b", "metadata": {}, "source": [ - "### Check the size before you run\n", + "### Qubits your problem needs\n", "\n", "The size a run needs depends only on how many qubits the problem uses, which\n", "follows from your `molecule_options`:\n", @@ -653,9 +676,216 @@ "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", "\n", - "To find the size on your own machine before you submit, use the\n", - "[size estimator](#size-estimator). It gives the size IBM and the function\n", - "check your run at, needs only PySCF, and costs nothing." + "To work this out on your own machine, use the [size estimator](#size-estimator)." + ] + }, + { + "cell_type": "markdown", + "id": "9e2f4a17", + "metadata": {}, + "source": [ + "### Size estimator\n", + "\n", + "This is the code IBM and the function use to size a job, so the size it gives\n", + "is the one your run is placed and checked at. It needs only PySCF\n", + "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell below,\n", + "or save it as `hivqe_chemistry_size_estimator.py`. You only need to call\n", + "`estimate_size`; the rest of the file is how the size is worked out." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a88635c-b4c0-4b8c-b1dd-faf369836b5c", + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Size estimator for Qunova HI-VQE Chemistry. Requires PySCF only.\n", + "\n", + "estimate_size(geometry, molecule_options=...) returns \"s\", \"m\" or \"l\" from the\n", + "number of qubits the problem needs: two per active orbital. The active space is\n", + "the orbitals AVAS selects if avas_aolabels is set, else active_orbitals if set,\n", + "else every orbital in the basis. With fcidump_file_name, the path of an FCIDUMP\n", + "file, it is every orbital of the file, and geometry and molecule_options are\n", + "ignored, as the function ignores them. Other inputs are accepted and ignored.\n", + "\"\"\"\n", + "from __future__ import annotations\n", + "\n", + "import gzip\n", + "import re\n", + "from typing import Any, Literal\n", + "\n", + "from pyscf import gto, scf\n", + "from pyscf.mcscf import avas\n", + "\n", + "Size = Literal[\"s\", \"m\", \"l\"]\n", + "_ORDER = {\"s\": 0, \"m\": 1, \"l\": 2}\n", + "\n", + "# Upper bounds (inclusive) on the number of qubits for each size.\n", + "_SMALL = 10\n", + "_MEDIUM = 20\n", + "\n", + "# The function's defaults for the molecule_options that decide the active space.\n", + "_DEFAULTS = {\n", + " \"active_orbitals\": None,\n", + " \"avas_aolabels\": None,\n", + " \"avas_threshold\": 0.2,\n", + " \"basis\": \"sto-3g\",\n", + " \"charge\": 0,\n", + " \"symmetry\": False,\n", + " \"symmetry_subgroup\": None,\n", + " \"unit\": \"angstrom\",\n", + " \"nucmod\": None,\n", + " \"pseudo\": None,\n", + " \"cart\": False,\n", + " \"magmom\": None,\n", + "}\n", + "\n", + "# AVAS weights below this are numerical noise; counting them would make the size vary\n", + "# from one call to the next.\n", + "_AVAS_WEIGHT_TOLERANCE = 1e-10\n", + "\n", + "\n", + "def estimate_size(problem: Any, **kwargs: Any) -> Size:\n", + " \"\"\"Return the size (\"s\", \"m\" or \"l\") required to run the function.\"\"\"\n", + " metrics = _measure(problem, **kwargs)\n", + " if _is_small(metrics):\n", + " return \"s\"\n", + " if _is_medium(metrics):\n", + " return \"m\"\n", + " return \"l\"\n", + "\n", + "\n", + "def _measure(problem: Any, **kwargs: Any) -> dict:\n", + " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", + " if kwargs.get(\"fcidump_file_name\"):\n", + " return {\"num_qubits\": 2 * _fcidump_num_orbitals(kwargs[\"fcidump_file_name\"])}\n", + " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", + " mol = gto.M(\n", + " atom=problem,\n", + " basis=options[\"basis\"],\n", + " spin=0, # the function runs singlets only\n", + " charge=options[\"charge\"],\n", + " symmetry=options[\"symmetry\"],\n", + " symmetry_subgroup=options[\"symmetry_subgroup\"],\n", + " unit=options[\"unit\"],\n", + " nucmod=options[\"nucmod\"],\n", + " pseudo=options[\"pseudo\"],\n", + " cart=options[\"cart\"],\n", + " magmom=options[\"magmom\"],\n", + " verbose=0,\n", + " )\n", + "\n", + " if options[\"avas_aolabels\"] is None:\n", + " # The active space is the orbitals given, or the whole basis; building the molecule\n", + " # is enough to know it.\n", + " if options[\"active_orbitals\"]:\n", + " return {\"num_qubits\": 2 * len(options[\"active_orbitals\"])}\n", + " return {\"num_qubits\": 2 * mol.nao_nr()}\n", + "\n", + " # AVAS picks the active space from an RHF, so it has to run one.\n", + " rhf = scf.RHF(mol)\n", + " rhf.verbose = 0\n", + " rhf.kernel()\n", + " selection = avas.AVAS(\n", + " mf=rhf,\n", + " aolabels=options[\"avas_aolabels\"],\n", + " threshold=max(options[\"avas_threshold\"], _AVAS_WEIGHT_TOLERANCE),\n", + " )\n", + " selection.verbose = 0\n", + " selection.kernel()\n", + " return {\"num_qubits\": 2 * selection.ncas}\n", + "\n", + "\n", + "# An FCIDUMP header is read up to its end (&END or /). It is a few lines; its\n", + "# only part that grows with the problem is ORBSYM, a few characters per orbital.\n", + "_FCIDUMP_MAX_HEADER_LINES = 1000\n", + "\n", + "\n", + "def _fcidump_num_orbitals(path: str) -> int:\n", + " \"\"\"NORB from the header of an FCIDUMP file, plain or gzip-compressed,\n", + " without reading the integrals.\"\"\"\n", + " with open(path, \"rb\") as raw:\n", + " gzipped = raw.read(2) == b\"\\x1f\\x8b\"\n", + " opener = gzip.open if gzipped else open\n", + " header = []\n", + " try:\n", + " with opener(path, \"rt\") as in_file:\n", + " for line_number, line in enumerate(in_file):\n", + " header.append(line.upper())\n", + " if \"&END\" in header[-1] or \"/\" in line:\n", + " break\n", + " if line_number >= _FCIDUMP_MAX_HEADER_LINES:\n", + " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " else:\n", + " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " except (UnicodeDecodeError, OSError, EOFError) as error:\n", + " raise ValueError(\n", + " \"The FCIDUMP file could not be read as text or as gzip-compressed text.\"\n", + " ) from error\n", + " match = re.search(r\"NORB\\s*=\\s*(\\d+)\", \"\".join(header))\n", + " if match is None or int(match.group(1)) < 1:\n", + " raise ValueError(\"No valid NORB entry was found in the FCIDUMP file header.\")\n", + " return int(match.group(1))\n", + "\n", + "\n", + "def _is_small(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _SMALL\n", + "\n", + "\n", + "def _is_medium(metrics: dict) -> bool:\n", + " \"\"\"Determine if the metrics fit T-size 'm'.\"\"\"\n", + " return metrics[\"num_qubits\"] <= _MEDIUM\n", + "\n", + "\n", + "def validate_size(provided_size: Size, problem: Any, **kwargs: Any) -> None:\n", + " \"\"\"Call at the start of the function. Raise if ``provided_size`` is smaller than\n", + " the estimated size; the estimated size or a larger one is accepted.\"\"\"\n", + " expected = estimate_size(problem, **kwargs)\n", + " if _ORDER[provided_size] < _ORDER[expected]:\n", + " raise ValueError(\n", + " f\"Size '{provided_size}' is too small for this problem; expected '{expected}' or larger.\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "b71c3d58", + "metadata": {}, + "source": [ + "For the NH3 molecule in the [Example](#example):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "216827a3-35e1-4499-b924-6ec5b6b7af92", + "metadata": {}, + "outputs": [], + "source": [ + "# NH3 in STO-3G has 8 orbitals, so 16 qubits: \"m\"\n", + "print(estimate_size(geometry, molecule_options=molecule_options))" + ] + }, + { + "cell_type": "markdown", + "id": "80af2a86", + "metadata": {}, + "source": [ + "For an FCIDUMP file, pass its path as `fcidump_file_name`, as you will pass its\n", + "name to `run()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e20b4b85", + "metadata": {}, + "outputs": [], + "source": [ + "# nh3.FCIDUMP, written in \"Run from an FCIDUMP file\", has 8 orbitals: \"m\"\n", + "print(estimate_size(None, fcidump_file_name=\"nh3.FCIDUMP\"))" ] }, { @@ -665,18 +895,19 @@ "source": [ "## Licensed use\n", "\n", - "A license grants a qubit limit of its own. Runs made with a license token are\n", - "still submitted at a function size and checked against it; see\n", - "[Function sizes](#function-sizes).\n", + "### Get a license\n", "\n", - "To request access and a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", + "To request a license, fill in [this form](https://forms.office.com/r/zN3hvMTqJ1), or email\n", "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com) with your inquiry.\n", + "Your license sets your qubit limit, and comes with a license token.\n", "\n", - "### Example of licensed function use\n", + "### Run with a license token\n", "\n", - "Licensed users are issued a license token, and then must use a wrapper library to submit their license token to the function.\n", - "The wrapper library can be installed [from PyPI](https://pypi.org/project/hivqe-qiskit-function-utils/) with `pip install hivqe-qiskit-function-utils`.\n", - "The below example shows how this library should be used to submit your license token when calling the function." + "Pass your license token to the function through the wrapper library, which you\n", + "can install [from PyPI](https://pypi.org/project/hivqe-qiskit-function-utils/)\n", + "with `pip install hivqe-qiskit-function-utils`. Everything else is as in the\n", + "[Example](#example), including `function_size`: see [Function sizes and\n", + "billing](#function-sizes-and-billing)." ] }, { @@ -716,150 +947,20 @@ }, { "cell_type": "markdown", - "id": "4af252f6", - "metadata": {}, - "source": [ - "## Performance\n", - "\n", - "This section shows the demonstrated benchmark calculations of HI-VQE with a 24-qubit case for Li2S, a 40-qubit case for an N2 molecule, and a 44-qubit case for an FeP-NO system." - ] - }, - { - "cell_type": "markdown", - "id": "54d8f446", + "id": "04236c83", "metadata": {}, "source": [ - "#### Dissociation potential energy surface curve for an Li2S molecule with 24 qubits\n", - "\n", - "The PES curve is shown with the FCI reference and initial guess from RHF, together with the energy error from the FCI reference.\n", - "\n", - "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the Li2S system](/docs/images/guides/qunova-chemistry/Li2S_PES.avif).\n", + "## Fetch error messages\n", "\n", - "The calculations have been conducted with the following geometries and options." + "If your workload fails, the status will be `ERROR` and calling\n", + "`job.result()` will raise an exception. This run fails after it starts, so it\n", + "is [billed](#what-is-billed) like any other:" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "294a02cfa0c3", - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# This cell is hidden from users\n", - "backend_name = service.least_busy(operational=True, min_num_qubits=38).name" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "8c998f54", - "metadata": {}, - "outputs": [], - "source": [ - "# Define Li2S geometries\n", - "Li2S_geoms = {\n", - " \"Li2S_1.51\": \"S -1.239044 0.671232 -0.030374;Li -1.506327 0.432403 -1.498949;Li -0.899996 0.973348 1.826768;\",\n", - " \"Li2S_2.40\": \"S -1.741432 0.680397 0.346702;Li -0.529307 0.488006 -1.729343;Li -1.284307 0.989409 2.177209;\",\n", - " \"Li2S_3.80\": \"S -2.707255 0.674298 0.909161;Li 0.079218 0.552012 -1.671656;Li -0.927010 0.931502 1.557063;\",\n", - "}\n", - "\n", - "# Configure some options for the job.\n", - "molecule_options = {\n", - " \"basis\": \"sto3g\",\n", - "}\n", - "hivqe_options = {\n", - " \"shots\": 100,\n", - " \"max_iter\": 20,\n", - "}\n", - "\n", - "results = []\n", - "for geom in [\"Li2S_1.51\", \"Li2S_2.40\", \"Li2S_3.80\"]:\n", - " # Run HI-VQE\n", - " job = function.run(\n", - " geometry=Li2S_geoms[geom],\n", - " backend_name=backend_name, # a backend you have access to\n", - " function_size=\"l\", # 38 qubits, more than \"m\" allows\n", - " max_states=2000,\n", - " max_expansion_states=10,\n", - " molecule_options=molecule_options,\n", - " hivqe_options=hivqe_options,\n", - " )\n", - " results.append(job.result())" - ] - }, - { - "cell_type": "markdown", - "id": "81129f0f", - "metadata": {}, - "source": [ - "The red dots represent the HI-VQE calculation results for six different geometries, and three geometries corresponding to 1.51, 2.40, and 3.80 Angstrom are provided as input in the above cell." - ] - }, - { - "cell_type": "markdown", - "id": "4d8d6cad", - "metadata": {}, - "source": [ - "#### Dissociation PES curve for an N2 molecule with 40 qubits\n", - "\n", - "The nitrogen molecule has been identified as a multireference system with large correlation energy contributions beyond the Hartree-Fock state. We conducted a benchmark calculation for the N2 molecule with cc-pvdz basis, (20o,14e) using the homo-lumo active orbital selection. The complete active space (CAS) number to represent this problem is 6,009,350,400. It is not possible to obtain the eigenvalue problem solution (for energy and electronic structure) with this number of states using a powerful desktop (16cpu/64GB). With HI-VQE, users can efficiently search the subspace of CAS states to find chemically accurate results while saving computation resources significantly. The following plots show the PES curve of 40 qubits HI-VQE calculation of the N2 molecule dissociation.\n", - "\n", - "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the N2 system](/docs/images/guides/qunova-chemistry/N2_PES_40qubits.avif)" - ] - }, - { - "cell_type": "markdown", - "id": "e84bc625", - "metadata": {}, - "source": [ - "#### Dissociation PES curve for five-coordinated iron(II)-porphyrin with an NO system with 44 qubits\n", - "\n", - "Another interesting chemical system is an iron(II)-porphyrin (FeP) complex with a coordinated nitric oxide (NO) ligand, which represents a biologically relevant metalloporphyrin system that plays crucial roles in various physiological processes. In this example, HI-VQE has been utilized to estimate the accurate potential energy surface curve of the intermolecular interaction between FeP and NO (ground state energy for differently separated geometries). The combined system has 450 orbitals and 202 electrons (450o,202e) with 6-31g(d) basis in total. The homo-lumo active orbital selection was utilized to calculate the smaller case from the real case with (22o,22e). From the following benchmark results, we were able to achieve the chemical accuracy (> 1.6 mHa) with a state-of-the-art classical computer chemistry calculation of CASCI(DMRG) (22o,22e) reference.\n", - "\n", - "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the FeP-NO system](/docs/images/guides/qunova-chemistry/fepno_44qubits.avif)" - ] - }, - { - "cell_type": "markdown", - "id": "b34fe075", - "metadata": {}, - "source": [ - "## Benchmarks\n", - "\n", - "- Exact matrix size is the number of determinants for exact solution, such as FCI and CASCI.\n", - "- HI-VQE calculation samples and calculates the subspace of it (as in, HI-VQE matrix size).\n", - "- Total time includes QPU runtime and Qiskit Function runs with CPU.\n", - "- Accuracy is estimated from the energy difference from exact solution.\n", - "\n", - "| Chemical system | Number of qubits | Exact matrix size | HI-VQE matrix size | E(diff) from exact (mHa) | Number of iteration | Total time | QPU runtime usage |\n", - "| ------------------ | ---------------- | ----------------- | ------------------- | ------------------------ | ------------------- | ------------- | ----------------- |\n", - "| $NH_3$ (8o,10e) | 16 | 3136 | 1936 | 0.08 | 6 | 37 s | 34 s |\n", - "| $Li_2S$ (10o,10e) | 20 | 63504 | 3969 | 0.60 | 5 | 250 s | 50 s |\n", - "| $NH_3$ (15o,10e) | 30 | 9018009 | 49729 | 0.90 | 5 | 354 s | 54 s |\n", - "| $N_2$ (16o,14e) | 32 | 130873600 | 1798281 | 1.10 | 9 | 6531 s | 121 s |\n", - "| $3H_2O$ (18o,24e) | 36 | 344622096 | 399424 | 0.90 | 24 | 5174 s | 130 s |\n", - "| $N_2$ (20o,14e) | 40 | 6009350400 | 9012004 | 1.20 | 21 | 46547 s | 258 s |" - ] - }, - { - "cell_type": "markdown", - "id": "04236c83", - "metadata": {}, - "source": [ - "## Fetch error messages\n", - "\n", - "If your workload fails, the status will be `ERROR` and calling\n", - "`job.result()` will raise an exception:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "90c6de7c", + "execution_count": 12, + "id": "90c6de7c", "metadata": { "editable": true, "slideshow": { @@ -946,217 +1047,142 @@ "[qiskit.support@qunovacomputing.com](mailto:qiskit.support@qunovacomputing.com).\n", "\n", "A call with a wrong argument name, type or range does not get this far:\n", - "`run()` refuses it before a job is created, as described in\n", - "[Example](#example)." + "`run()` refuses it before a job is created; see [Check the\n", + "arguments](#check-the-arguments)." ] }, { "cell_type": "markdown", - "id": "9e2f4a17", + "id": "4af252f6", "metadata": {}, "source": [ - "## Size estimator\n", + "## Performance\n", "\n", - "This is the code IBM and the function use to size a job, so the size it gives\n", - "is the one your run is placed and checked at. It needs only PySCF\n", - "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell below,\n", - "or save it as `hivqe_chemistry_size_estimator.py`. You only need to call\n", - "`estimate_size`; the rest of the file is how the size is worked out." + "This section shows the demonstrated benchmark calculations of HI-VQE with a 24-qubit case for Li2S, a 40-qubit case for an N2 molecule, and a 44-qubit case for an FeP-NO system." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7a88635c-b4c0-4b8c-b1dd-faf369836b5c", + "cell_type": "markdown", + "id": "54d8f446", "metadata": {}, - "outputs": [], "source": [ - "\"\"\"Size estimator for Qunova HI-VQE Chemistry. Requires PySCF only.\n", - "\n", - "estimate_size(geometry, molecule_options=...) returns \"s\", \"m\" or \"l\" from the\n", - "number of qubits the problem needs: two per active orbital. The active space is\n", - "the orbitals AVAS selects if avas_aolabels is set, else active_orbitals if set,\n", - "else every orbital in the basis. With fcidump_file_name, the path of an FCIDUMP\n", - "file, it is every orbital of the file, and geometry and molecule_options are\n", - "ignored, as the function ignores them. Other inputs are accepted and ignored.\n", - "\"\"\"\n", - "from __future__ import annotations\n", + "### Dissociation potential energy surface curve for an Li2S molecule with 24 qubits\n", "\n", - "import gzip\n", - "import re\n", - "from typing import Any, Literal\n", - "\n", - "from pyscf import gto, scf\n", - "from pyscf.mcscf import avas\n", - "\n", - "Size = Literal[\"s\", \"m\", \"l\"]\n", - "_ORDER = {\"s\": 0, \"m\": 1, \"l\": 2}\n", + "The PES curve is shown with the FCI reference and initial guess from RHF, together with the energy error from the FCI reference.\n", "\n", - "# Upper bounds (inclusive) on the number of qubits for each size.\n", - "_SMALL = 10\n", - "_MEDIUM = 20\n", + "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the Li2S system](/docs/images/guides/qunova-chemistry/Li2S_PES.avif).\n", "\n", - "# The function's defaults for the molecule_options that decide the active space.\n", - "_DEFAULTS = {\n", - " \"active_orbitals\": None,\n", - " \"avas_aolabels\": None,\n", - " \"avas_threshold\": 0.2,\n", - " \"basis\": \"sto-3g\",\n", - " \"charge\": 0,\n", - " \"symmetry\": False,\n", - " \"symmetry_subgroup\": None,\n", - " \"unit\": \"angstrom\",\n", - " \"nucmod\": None,\n", - " \"pseudo\": None,\n", - " \"cart\": False,\n", - " \"magmom\": None,\n", + "The calculations have been conducted with the following geometries and options.\n", + "The cell below runs them in the full STO-3G basis, which takes 38 qubits, so it\n", + "submits three runs at `\"l\"`: 12 RU in per-run fees, plus QPU and classical\n", + "compute time." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "294a02cfa0c3", + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# This cell is hidden from users\n", + "backend_name = service.least_busy(operational=True, min_num_qubits=38).name" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "8c998f54", + "metadata": {}, + "outputs": [], + "source": [ + "# Define Li2S geometries\n", + "Li2S_geoms = {\n", + " \"Li2S_1.51\": \"S -1.239044 0.671232 -0.030374;Li -1.506327 0.432403 -1.498949;Li -0.899996 0.973348 1.826768;\",\n", + " \"Li2S_2.40\": \"S -1.741432 0.680397 0.346702;Li -0.529307 0.488006 -1.729343;Li -1.284307 0.989409 2.177209;\",\n", + " \"Li2S_3.80\": \"S -2.707255 0.674298 0.909161;Li 0.079218 0.552012 -1.671656;Li -0.927010 0.931502 1.557063;\",\n", "}\n", "\n", - "# AVAS weights below this are numerical noise; counting them would make the size vary\n", - "# from one call to the next.\n", - "_AVAS_WEIGHT_TOLERANCE = 1e-10\n", - "\n", - "\n", - "def estimate_size(problem: Any, **kwargs: Any) -> Size:\n", - " \"\"\"Return the size (\"s\", \"m\" or \"l\") required to run the function.\"\"\"\n", - " metrics = _measure(problem, **kwargs)\n", - " if _is_small(metrics):\n", - " return \"s\"\n", - " if _is_medium(metrics):\n", - " return \"m\"\n", - " return \"l\"\n", - "\n", - "\n", - "def _measure(problem: Any, **kwargs: Any) -> dict:\n", - " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", - " if kwargs.get(\"fcidump_file_name\"):\n", - " return {\"num_qubits\": 2 * _fcidump_num_orbitals(kwargs[\"fcidump_file_name\"])}\n", - " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", - " mol = gto.M(\n", - " atom=problem,\n", - " basis=options[\"basis\"],\n", - " spin=0, # the function runs singlets only\n", - " charge=options[\"charge\"],\n", - " symmetry=options[\"symmetry\"],\n", - " symmetry_subgroup=options[\"symmetry_subgroup\"],\n", - " unit=options[\"unit\"],\n", - " nucmod=options[\"nucmod\"],\n", - " pseudo=options[\"pseudo\"],\n", - " cart=options[\"cart\"],\n", - " magmom=options[\"magmom\"],\n", - " verbose=0,\n", - " )\n", - "\n", - " if options[\"avas_aolabels\"] is None:\n", - " # The active space is the orbitals given, or the whole basis; building the molecule\n", - " # is enough to know it.\n", - " if options[\"active_orbitals\"]:\n", - " return {\"num_qubits\": 2 * len(options[\"active_orbitals\"])}\n", - " return {\"num_qubits\": 2 * mol.nao_nr()}\n", + "# Configure some options for the job.\n", + "molecule_options = {\n", + " \"basis\": \"sto3g\",\n", + "}\n", + "hivqe_options = {\n", + " \"shots\": 100,\n", + " \"max_iter\": 20,\n", + "}\n", "\n", - " # AVAS picks the active space from an RHF, so it has to run one.\n", - " rhf = scf.RHF(mol)\n", - " rhf.verbose = 0\n", - " rhf.kernel()\n", - " selection = avas.AVAS(\n", - " mf=rhf,\n", - " aolabels=options[\"avas_aolabels\"],\n", - " threshold=max(options[\"avas_threshold\"], _AVAS_WEIGHT_TOLERANCE),\n", + "results = []\n", + "for geom in [\"Li2S_1.51\", \"Li2S_2.40\", \"Li2S_3.80\"]:\n", + " # Run HI-VQE\n", + " job = function.run(\n", + " geometry=Li2S_geoms[geom],\n", + " backend_name=backend_name, # a backend you have access to\n", + " function_size=\"l\", # 38 qubits, more than \"m\" allows\n", + " max_states=2000,\n", + " max_expansion_states=10,\n", + " molecule_options=molecule_options,\n", + " hivqe_options=hivqe_options,\n", " )\n", - " selection.verbose = 0\n", - " selection.kernel()\n", - " return {\"num_qubits\": 2 * selection.ncas}\n", - "\n", - "\n", - "# An FCIDUMP header is read up to its end (&END or /). It is a few lines; its\n", - "# only part that grows with the problem is ORBSYM, a few characters per orbital.\n", - "_FCIDUMP_MAX_HEADER_LINES = 1000\n", - "\n", - "\n", - "def _fcidump_num_orbitals(path: str) -> int:\n", - " \"\"\"NORB from the header of an FCIDUMP file, plain or gzip-compressed,\n", - " without reading the integrals.\"\"\"\n", - " with open(path, \"rb\") as raw:\n", - " gzipped = raw.read(2) == b\"\\x1f\\x8b\"\n", - " opener = gzip.open if gzipped else open\n", - " header = []\n", - " try:\n", - " with opener(path, \"rt\") as in_file:\n", - " for line_number, line in enumerate(in_file):\n", - " header.append(line.upper())\n", - " if \"&END\" in header[-1] or \"/\" in line:\n", - " break\n", - " if line_number >= _FCIDUMP_MAX_HEADER_LINES:\n", - " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", - " else:\n", - " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", - " except (UnicodeDecodeError, OSError, EOFError) as error:\n", - " raise ValueError(\n", - " \"The FCIDUMP file could not be read as text or as gzip-compressed text.\"\n", - " ) from error\n", - " match = re.search(r\"NORB\\s*=\\s*(\\d+)\", \"\".join(header))\n", - " if match is None or int(match.group(1)) < 1:\n", - " raise ValueError(\"No valid NORB entry was found in the FCIDUMP file header.\")\n", - " return int(match.group(1))\n", - "\n", - "\n", - "def _is_small(metrics: dict) -> bool:\n", - " \"\"\"Determine if the metrics fit T-size 's'.\"\"\"\n", - " return metrics[\"num_qubits\"] <= _SMALL\n", - "\n", - "\n", - "def _is_medium(metrics: dict) -> bool:\n", - " \"\"\"Determine if the metrics fit T-size 'm'.\"\"\"\n", - " return metrics[\"num_qubits\"] <= _MEDIUM\n", - "\n", - "\n", - "def validate_size(provided_size: Size, problem: Any, **kwargs: Any) -> None:\n", - " \"\"\"Call at the start of the function. Raise if ``provided_size`` is smaller than\n", - " the estimated size; the estimated size or a larger one is accepted.\"\"\"\n", - " expected = estimate_size(problem, **kwargs)\n", - " if _ORDER[provided_size] < _ORDER[expected]:\n", - " raise ValueError(\n", - " f\"Size '{provided_size}' is too small for this problem; expected '{expected}' or larger.\"\n", - " )" + " results.append(job.result())" ] }, { "cell_type": "markdown", - "id": "b71c3d58", + "id": "81129f0f", "metadata": {}, "source": [ - "For the NH3 molecule in the [Example](#example):" + "The red dots represent the HI-VQE calculation results for six different geometries, and three geometries corresponding to 1.51, 2.40, and 3.80 Angstrom are provided as input in the above cell." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "216827a3-35e1-4499-b924-6ec5b6b7af92", + "cell_type": "markdown", + "id": "4d8d6cad", "metadata": {}, - "outputs": [], "source": [ - "# NH3 in STO-3G has 8 orbitals, so 16 qubits: \"m\"\n", - "print(estimate_size(geometry, molecule_options=molecule_options))" + "### Dissociation PES curve for an N2 molecule with 40 qubits\n", + "\n", + "The nitrogen molecule has been identified as a multireference system with large correlation energy contributions beyond the Hartree-Fock state. We conducted a benchmark calculation for the N2 molecule with cc-pvdz basis, (20o,14e) using the homo-lumo active orbital selection. The complete active space (CAS) number to represent this problem is 6,009,350,400. It is not possible to obtain the eigenvalue problem solution (for energy and electronic structure) with this number of states using a powerful desktop (16cpu/64GB). With HI-VQE, users can efficiently search the subspace of CAS states to find chemically accurate results while saving computation resources significantly. The following plots show the PES curve of 40 qubits HI-VQE calculation of the N2 molecule dissociation.\n", + "\n", + "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the N2 system](/docs/images/guides/qunova-chemistry/N2_PES_40qubits.avif)" ] }, { "cell_type": "markdown", - "id": "80af2a86", + "id": "e84bc625", "metadata": {}, "source": [ - "For an FCIDUMP file, pass its path as `fcidump_file_name`, as you will pass its\n", - "name to `run()`:" + "### Dissociation PES curve for five-coordinated iron(II)-porphyrin with an NO system with 44 qubits\n", + "\n", + "Another interesting chemical system is an iron(II)-porphyrin (FeP) complex with a coordinated nitric oxide (NO) ligand, which represents a biologically relevant metalloporphyrin system that plays crucial roles in various physiological processes. In this example, HI-VQE has been utilized to estimate the accurate potential energy surface curve of the intermolecular interaction between FeP and NO (ground state energy for differently separated geometries). The combined system has 450 orbitals and 202 electrons (450o,202e) with 6-31g(d) basis in total. The homo-lumo active orbital selection was utilized to calculate the smaller case from the real case with (22o,22e). From the following benchmark results, we were able to achieve the chemical accuracy (> 1.6 mHa) with a state-of-the-art classical computer chemistry calculation of CASCI(DMRG) (22o,22e) reference.\n", + "\n", + "![Image showing that HI-VQE produces solutions within chemical accuracy of a classical reference PES curve for the FeP-NO system](/docs/images/guides/qunova-chemistry/fepno_44qubits.avif)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "e20b4b85", + "cell_type": "markdown", + "id": "b34fe075", "metadata": {}, - "outputs": [], "source": [ - "# nh3.FCIDUMP, written in \"Run from an FCIDUMP file\", has 8 orbitals: \"m\"\n", - "print(estimate_size(None, fcidump_file_name=\"nh3.FCIDUMP\"))" + "### Benchmarks\n", + "\n", + "- Exact matrix size is the number of determinants for exact solution, such as FCI and CASCI.\n", + "- HI-VQE calculation samples and calculates the subspace of it (as in, HI-VQE matrix size).\n", + "- Total time includes QPU runtime and Qiskit Function runs with CPU.\n", + "- Accuracy is estimated from the energy difference from exact solution.\n", + "\n", + "| Chemical system | Number of qubits | Exact matrix size | HI-VQE matrix size | E(diff) from exact (mHa) | Number of iteration | Total time | QPU runtime usage |\n", + "| ------------------ | ---------------- | ----------------- | ------------------- | ------------------------ | ------------------- | ------------- | ----------------- |\n", + "| $NH_3$ (8o,10e) | 16 | 3136 | 1936 | 0.08 | 6 | 37 s | 34 s |\n", + "| $Li_2S$ (10o,10e) | 20 | 63504 | 3969 | 0.60 | 5 | 250 s | 50 s |\n", + "| $NH_3$ (15o,10e) | 30 | 9018009 | 49729 | 0.90 | 5 | 354 s | 54 s |\n", + "| $N_2$ (16o,14e) | 32 | 130873600 | 1798281 | 1.10 | 9 | 6531 s | 121 s |\n", + "| $3H_2O$ (18o,24e) | 36 | 344622096 | 399424 | 0.90 | 24 | 5174 s | 130 s |\n", + "| $N_2$ (20o,14e) | 40 | 6009350400 | 9012004 | 1.20 | 21 | 46547 s | 258 s |" ] }, { @@ -1177,7 +1203,7 @@ "\n", "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Size estimator](#size-estimator).\n", - "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Example](#example).\n", + "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", "- `avas_threshold` accepts a whole number, such as `0`.\n", @@ -1185,7 +1211,7 @@ "\n", "### 5.0.0\n", "\n", - "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Limits and billing](#limits-and-billing).\n", + "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Function sizes and billing](#function-sizes-and-billing).\n", "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", "\n", diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index d5d6a11f8587..d8df9b222d5b 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -112,8 +112,8 @@ "below names a `function_size`, which sets the resources it gets and what it is\n", "billed: `\"m\"` for Part 1, and `\"l\"` for Part 2, which needs 44 qubits. Running\n", "the whole tutorial is six runs at `\"m\"` and three at `\"l\"`, or 18.0 resource\n", - "units. See [Limits and\n", - "billing](/docs/guides/qunova-chemistry#limits-and-billing) in the guide for\n", + "units. See [Function sizes and\n", + "billing](/docs/guides/qunova-chemistry#function-sizes-and-billing) in the guide for\n", "what the sizes cost.\n", "\n", "**With a license.** Load the function through the wrapper library instead of\n", From 3ee4d407d68714d51e15ae38c4530d0a7e7ba675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:42:08 +0900 Subject: [PATCH 46/59] Fold the size estimator's code into an accordion Readers only need estimate_size, but the full estimator took up most of the billing section. The code cell is unchanged and still runs; it is now shown only when the reader opens it. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index a4bf521b11fd..98ca11637e7d 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -688,9 +688,13 @@ "\n", "This is the code IBM and the function use to size a job, so the size it gives\n", "is the one your run is placed and checked at. It needs only PySCF\n", - "(`pip install pyscf`), submits nothing, and costs nothing. Run the cell below,\n", - "or save it as `hivqe_chemistry_size_estimator.py`. You only need to call\n", - "`estimate_size`; the rest of the file is how the size is worked out." + "(`pip install pyscf`), submits nothing, and costs nothing. Open the code\n", + "below, then run it in a cell or save it as `hivqe_chemistry_size_estimator.py`.\n", + "You only need to call `estimate_size`; the rest of the code is how the size is\n", + "worked out.\n", + "\n", + "\n", + "" ] }, { @@ -854,6 +858,9 @@ "id": "b71c3d58", "metadata": {}, "source": [ + "\n", + "\n", + "\n", "For the NH3 molecule in the [Example](#example):" ] }, From 0ac43202e1c9eac72a34ac19fcfc938b6097e140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:45:56 +0900 Subject: [PATCH 47/59] Separate the licensed example's wrapper from its run Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 98ca11637e7d..6ac5bb370d9c 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -940,6 +940,7 @@ " token=\"your_hivqe_license_token\",\n", " function=catalog.load(\"qunova/hivqe-chemistry\"),\n", ")\n", + "\n", "job = hivqe.run(\n", " geometry=molecule_geometry,\n", " backend_name=backend_name, # a backend you have access to\n", From 381e3a01e7eea3488f18d817ae70f4177c8301cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:52:23 +0900 Subject: [PATCH 48/59] Call the size fee the per-execution fee, as IBM's pricing does Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 2 +- docs/guides/qunova-chemistry.ipynb | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 10d03486c44b..b54af426db8d 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -252,7 +252,7 @@ Which resources the job runs on, and what the run is billed. It is passed to `run()` like the arguments above, though it belongs to the platform rather than to this function. -| `function_size` | Qubits | Compute profile | Per-run fee | +| `function_size` | Qubits | Compute profile | Per-execution fee | |-----|-----|-----|-----| | `"s"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU | | `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 6ac5bb370d9c..2271242bf926 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -146,7 +146,7 @@ "| --- | --- | --- |\n", "| **How to start** | Run the function; there is nothing to sign up for | [Request a license](https://forms.office.com/r/zN3hvMTqJ1) from Qunova |\n", "| **Qubits** | No limit | Set by your license |\n", - "| **What you pay** | A per-run fee for the [function size](#function-sizes-and-billing) you choose, plus the QPU and classical compute time the run uses | Your license fee to Qunova, plus the QPU and classical compute time the run uses |\n", + "| **What you pay** | A per-execution fee for the [function size](#function-sizes-and-billing) you choose, plus the QPU and classical compute time the run uses | Your license fee to Qunova, plus the QPU and classical compute time the run uses |\n", "| **License token** | Not needed | Needed; see [Licensed use](#licensed-use) |\n", "\n", "The examples on this page are usage-based runs. With a license, only the way\n", @@ -602,7 +602,7 @@ "## Function sizes and billing\n", "\n", "Every run is submitted at a function size, which sets the resources it runs\n", - "on and, for a usage-based run, its per-run fee. The size is checked against\n", + "on and, for a usage-based run, its per-execution fee. The size is checked against\n", "the problem with or without a license token." ] }, @@ -616,17 +616,17 @@ "Pass `function_size` to `run()` alongside the function's own arguments. If\n", "you leave it out, the run uses `\"m\"`.\n", "\n", - "| `function_size` | Qubits | Compute | Per-run fee |\n", + "| `function_size` | Qubits | Compute | Per-execution fee |\n", "| --- | --- | --- | --- |\n", "| `\"s\"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU |\n", "| `\"m\"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU |\n", "| `\"l\"` | No limit | 48 CPUs, 768 GB | 4.0 RU |\n", "\n", - "A usage-based run costs its per-run fee plus the QPU and classical compute\n", + "A usage-based run costs its per-execution fee plus the QPU and classical compute\n", "time it uses. Fees are given in resource units (RU); see [IBM Quantum\n", "plans](/docs/guides/plans-overview) for what a resource unit costs on your\n", "plan. With a license, you pay your license fee to Qunova in place of the\n", - "per-run fee." + "per-execution fee." ] }, { @@ -1082,7 +1082,7 @@ "\n", "The calculations have been conducted with the following geometries and options.\n", "The cell below runs them in the full STO-3G basis, which takes 38 qubits, so it\n", - "submits three runs at `\"l\"`: 12 RU in per-run fees, plus QPU and classical\n", + "submits three runs at `\"l\"`: 12 RU in per-execution fees, plus QPU and classical\n", "compute time." ] }, @@ -1219,7 +1219,7 @@ "\n", "### 5.0.0\n", "\n", - "- Runs without a license token are no longer limited to 20 qubits. They are billed per run at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Function sizes and billing](#function-sizes-and-billing).\n", + "- Runs without a license token are no longer limited to 20 qubits. They are billed per execution at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Function sizes and billing](#function-sizes-and-billing).\n", "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", "\n", From b09304876dbf4e2537368d46e4f5ced0d023398a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:55:27 +0900 Subject: [PATCH 49/59] Give the qubit count as one formula, with the NH3 example The section listed every option that shapes the active space. Readers need the rule and an example; the size estimator handles the options. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 2271242bf926..63fa7ffd672d 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -659,24 +659,21 @@ "source": [ "### Qubits your problem needs\n", "\n", - "The size a run needs depends only on how many qubits the problem uses, which\n", - "follows from your `molecule_options`:\n", + "HI-VQE represents each orbital of the active space with two qubits, one for\n", + "each electron spin:\n", "\n", - "| Your `molecule_options` | Qubits |\n", - "| --- | --- |\n", - "| `avas_aolabels` set | 2 × the number of orbitals AVAS selects (threshold `avas_threshold`, default 0.2) |\n", - "| `active_orbitals` set | 2 × the number of active orbitals |\n", - "| Neither | 2 × the number of atomic orbitals in the basis |\n", + "$$\n", + "\\text{qubits} = 2 \\times \\text{active orbitals}\n", + "$$\n", "\n", - "With [`fcidump_file_name`](#run-from-an-fcidump-file), the size depends only on\n", - "the file: 2 × `NORB`, the number of orbitals in its header. `molecule_options`\n", - "are then ignored.\n", + "By default, every orbital in the basis is active. You can choose a smaller\n", + "active space with\n", + "[`molecule_options`](/docs/api/functions/qunova-chemistry#molecule_options).\n", "\n", - "Submit at the smallest size that fits: up to 10 qubits is `\"s\"`, up to 20 is\n", - "`\"m\"`, and anything larger is `\"l\"`. The NH3 example has 8 orbitals in STO-3G,\n", - "so it needs 16 qubits and runs at `\"m\"`, as in the [Example](#example) above.\n", + "For example, NH3 has 8 orbitals in the STO-3G basis, so the\n", + "[Example](#example) uses 2 × 8 = 16 qubits and fits `\"m\"`.\n", "\n", - "To work this out on your own machine, use the [size estimator](#size-estimator)." + "To find the size for your own problem, use the [size estimator](#size-estimator)." ] }, { From d5c33c35638aa2d6f495fe6a79dcc3ff17bd178c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 10:58:42 +0900 Subject: [PATCH 50/59] Say the size estimator is the function's own size check, without IBM Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 63fa7ffd672d..71348b92a20b 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -683,8 +683,8 @@ "source": [ "### Size estimator\n", "\n", - "This is the code IBM and the function use to size a job, so the size it gives\n", - "is the one your run is placed and checked at. It needs only PySCF\n", + "This is the same code the function uses to check a run's size, so the size it\n", + "gives is the one your run is checked at. It needs only PySCF\n", "(`pip install pyscf`), submits nothing, and costs nothing. Open the code\n", "below, then run it in a cell or save it as `hivqe_chemistry_size_estimator.py`.\n", "You only need to call `estimate_size`; the rest of the code is how the size is\n", @@ -1207,7 +1207,7 @@ "### 5.0.3\n", "\n", "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", - "- Added a size estimator to run on your own machine at no charge. It is the code IBM and the function use to size a job. See [Size estimator](#size-estimator).\n", + "- Added a size estimator to run on your own machine at no charge. It is the same code the function uses to check a run's size. See [Size estimator](#size-estimator).\n", "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", From f55f20648eadca58fefe4010e111a9df02fa0fc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 11:35:15 +0900 Subject: [PATCH 51/59] Merge the unreleased 5.0.x changelog entries into one, for 5.0.4 Production goes from 4.0.0 straight to 5.0.x, so the entry lists what changed since 4.0.0. Fixes for problems only -dev ever had are dropped. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 71348b92a20b..2f306a9b19be 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -1199,26 +1199,14 @@ "\n", "### 5.0.4\n", "\n", - "- Runs can take the problem from an FCIDUMP file you upload, in place of a geometry: pass its name as `fcidump_file_name`. The size estimator accepts it too. See [Run from an FCIDUMP file](#run-from-an-fcidump-file).\n", - "- A run whose Qiskit Runtime job fails or is cancelled now reports Runtime's own error code, or 4631 when Runtime gives none, with a message and solution. It used to report an unexpected error, and the result lost its `\"resource_usage\"`.\n", - "- A failed run reports its error once. It used to be reported twice.\n", - "- `\"resource_usage\"` lists every stage of the job, with zero for a stage the run did not reach.\n", - "\n", - "### 5.0.3\n", - "\n", - "- Runs made with a license token, and trial runs, are now held to the function size like other runs: one submitted at a size too small for the problem is rejected with error code 1221. The default `\"m\"` fits up to 20 qubits.\n", - "- Added a size estimator to run on your own machine at no charge. It is the same code the function uses to check a run's size. See [Size estimator](#size-estimator).\n", - "- Arguments are checked against the function's argument schema when you call `run()`. A malformed call is refused before a job is created, and is not billed. Check arguments in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", - "- Runs that pass `orbital_coeffs` no longer fail. It also accepts a NumPy array, such as PySCF's `mo_coeff`.\n", - "- `ansatz_entanglement` accepts any letter case, as `ansatz` and `noons_level` already did.\n", - "- `avas_threshold` accepts a whole number, such as `0`.\n", - "- `active_orbitals`, `frozen_orbitals` and `avas_aolabels` must not repeat an entry.\n", - "\n", - "### 5.0.0\n", - "\n", - "- Runs without a license token are no longer limited to 20 qubits. They are billed per execution at a function size you choose with the new `function_size` argument: `\"s\"` (up to 10 qubits), `\"m\"` (up to 20, the default) or `\"l\"` (no limit). A size too small for the problem is rejected with error code 1221 before any QPU time is spent, but is still billed at the size chosen. See [Function sizes and billing](#function-sizes-and-billing).\n", - "- The result now includes `\"function_version\"`, the version of the function that ran the job, and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time.\n", - "- Errors use the error codes listed in [Fetch error messages](#fetch-error-messages), and each one says what to do about it.\n", + "- Runs without a license token are no longer limited to 20 qubits. Each run is billed per execution at the function size you choose with the new `function_size` argument, and a size too small for the problem is rejected with error code 1221. This applies with a license token too. See [Function sizes and billing](#function-sizes-and-billing).\n", + "- Added a size estimator to run on your own machine at no charge. See [Size estimator](#size-estimator).\n", + "- Runs can take the problem from an FCIDUMP file you upload, in place of a geometry. See [Run from an FCIDUMP file](#run-from-an-fcidump-file).\n", + "- Arguments are checked when you call `run()`, and a malformed call is refused before a job is created. Check them in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", + "- The result includes `\"function_version\"` and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job.\n", + "- Errors carry the codes listed in [Fetch error messages](#fetch-error-messages), with a message and what to do about it.\n", + "- Runs that pass `orbital_coeffs` no longer fail, and it accepts a NumPy array such as PySCF's `mo_coeff`.\n", + "- `ansatz_entanglement` accepts any letter case, `avas_threshold` accepts a whole number, and `active_orbitals`, `frozen_orbitals` and `avas_aolabels` must not repeat an entry.\n", "\n", "### 4.0.0\n", "\n", From b509b867e27cb4958b93ff565eaedfe3f83a8bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 12:00:52 +0900 Subject: [PATCH 52/59] List only the main changes of 5.0.4 in the changelog Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 2f306a9b19be..a5f118a1a42d 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -1199,14 +1199,13 @@ "\n", "### 5.0.4\n", "\n", - "- Runs without a license token are no longer limited to 20 qubits. Each run is billed per execution at the function size you choose with the new `function_size` argument, and a size too small for the problem is rejected with error code 1221. This applies with a license token too. See [Function sizes and billing](#function-sizes-and-billing).\n", - "- Added a size estimator to run on your own machine at no charge. See [Size estimator](#size-estimator).\n", + "- Runs execute on dedicated compute, sized by the function size you choose.\n", + "- Runs without a license token are no longer limited to 20 qubits. Each run is billed per execution at the function size you choose with the new `function_size` argument: `\"s\"`, `\"m\"` (the default) or `\"l\"`. Runs with a license token are checked against the function size too. See [Function sizes and billing](#function-sizes-and-billing).\n", "- Runs can take the problem from an FCIDUMP file you upload, in place of a geometry. See [Run from an FCIDUMP file](#run-from-an-fcidump-file).\n", - "- Arguments are checked when you call `run()`, and a malformed call is refused before a job is created. Check them in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", - "- The result includes `\"function_version\"` and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job.\n", - "- Errors carry the codes listed in [Fetch error messages](#fetch-error-messages), with a message and what to do about it.\n", - "- Runs that pass `orbital_coeffs` no longer fail, and it accepts a NumPy array such as PySCF's `mo_coeff`.\n", - "- `ansatz_entanglement` accepts any letter case, `avas_threshold` accepts a whole number, and `active_orbitals`, `frozen_orbitals` and `avas_aolabels` must not repeat an entry.\n", + "- Added a size estimator that gives the function size a problem needs, on your own machine and at no charge. See [Size estimator](#size-estimator).\n", + "- Arguments are checked against the function's argument schema when you call `run()`, and a malformed call is refused before a job is created, at no charge. Check them in advance with `validate_arguments()`. See [Check the arguments](#check-the-arguments).\n", + "- Every error carries an error code, a message saying what went wrong, and what to do about it. See [Fetch error messages](#fetch-error-messages).\n", + "- The result includes `\"function_version\"` and `\"metadata\"`, whose `\"resource_usage\"` gives the time spent in each stage of the job, including QPU time. The job status also shows `RUNNING: MAPPING` while the problem is being set up.\n", "\n", "### 4.0.0\n", "\n", From a8e9f382054d383f3dab5818ab8184f16a6647fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 13:17:55 +0900 Subject: [PATCH 53/59] Say a licensed run is still checked against its function size The tutorial said function_size was passed through and not checked on a license. Since 5.0.3 every run is checked, and the size sets the compute the run uses, which a licensed run pays for as classical compute time. Co-Authored-By: Claude Opus 5.5 --- docs/tutorials/qunova-hivqe.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index d8df9b222d5b..16e2d8476016 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -130,7 +130,9 @@ "```\n", "\n", "Your license sets the qubit limit, so it has to permit at least 44 qubits for\n", - "Part 2. The `function_size` in each run is passed through and not checked." + "Part 2. You don't pay the per-execution fee, but `function_size` still sets\n", + "the compute each run uses, and so its classical compute cost, and is checked\n", + "against the problem as for any run." ] }, { From 414e9261ee55c5488a5bde5d888d3e62b9924afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 13:20:49 +0900 Subject: [PATCH 54/59] Say the function size sets a licensed run's classical compute cost Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index a5f118a1a42d..347ff2264432 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -626,7 +626,8 @@ "time it uses. Fees are given in resource units (RU); see [IBM Quantum\n", "plans](/docs/guides/plans-overview) for what a resource unit costs on your\n", "plan. With a license, you pay your license fee to Qunova in place of the\n", - "per-execution fee." + "per-execution fee. The function size still sets the compute the run uses, and\n", + "so its classical compute cost." ] }, { From 4aa04e8e6a637e8b6c0dc628ab23ead3ab52eebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 13:21:58 +0900 Subject: [PATCH 55/59] Format the size estimator cell with ruff Only line breaks change: the code parses to the same tree as the function's hivqe_chemistry_size_estimator.py. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 347ff2264432..6a7ac5aab3d8 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -761,7 +761,10 @@ "def _measure(problem: Any, **kwargs: Any) -> dict:\n", " \"\"\"Return the number of qubits the run uses for this geometry and these options.\"\"\"\n", " if kwargs.get(\"fcidump_file_name\"):\n", - " return {\"num_qubits\": 2 * _fcidump_num_orbitals(kwargs[\"fcidump_file_name\"])}\n", + " return {\n", + " \"num_qubits\": 2\n", + " * _fcidump_num_orbitals(kwargs[\"fcidump_file_name\"])\n", + " }\n", " options = {**_DEFAULTS, **(kwargs.get(\"molecule_options\") or {})}\n", " mol = gto.M(\n", " atom=problem,\n", @@ -818,16 +821,22 @@ " if \"&END\" in header[-1] or \"/\" in line:\n", " break\n", " if line_number >= _FCIDUMP_MAX_HEADER_LINES:\n", - " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " raise ValueError(\n", + " \"No end of header (&END or /) was found in the FCIDUMP file.\"\n", + " )\n", " else:\n", - " raise ValueError(\"No end of header (&END or /) was found in the FCIDUMP file.\")\n", + " raise ValueError(\n", + " \"No end of header (&END or /) was found in the FCIDUMP file.\"\n", + " )\n", " except (UnicodeDecodeError, OSError, EOFError) as error:\n", " raise ValueError(\n", " \"The FCIDUMP file could not be read as text or as gzip-compressed text.\"\n", " ) from error\n", " match = re.search(r\"NORB\\s*=\\s*(\\d+)\", \"\".join(header))\n", " if match is None or int(match.group(1)) < 1:\n", - " raise ValueError(\"No valid NORB entry was found in the FCIDUMP file header.\")\n", + " raise ValueError(\n", + " \"No valid NORB entry was found in the FCIDUMP file header.\"\n", + " )\n", " return int(match.group(1))\n", "\n", "\n", From 2400ce0dc5575edc0f084f80b2c2e27f1319ef9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 14:15:45 +0900 Subject: [PATCH 56/59] Correct three passages of the HI-VQE API reference - A rejected argument gets an exception describing what failed; for an unknown name it does not name the argument. - active_orbitals indexes the orbitals of the basis, not the qubits. - A licensed run is checked against its size and pays for the compute the size sets, but is not charged the per-execution fee. Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index b54af426db8d..0fcb7d44d522 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -17,8 +17,8 @@ description: API reference for HI-VQE Chemistry, a Qiskit Function by Qunova Com ## Inputs Arguments are checked when you call `run()`, before a job is created: one with -the wrong name, type or range raises an exception naming it, and nothing is -billed. `function.validate_arguments({...})` runs the same check without +the wrong name, type or range raises an exception describing what failed, and +nothing is billed. `function.validate_arguments({...})` runs the same check without running anything, and `function.arguments_schema` lists every argument with its type, range and default. @@ -78,7 +78,7 @@ A string specifying the basis type; these are passed to pyscf. For example: `"st #### `active_orbitals` -A list of active orbital indices in the interval [0, n) where n is the number of qubits used in the problem. If this is specified, then the frozen_orbitals argument must also be specified. +A list of active orbital indices in the interval [0, n) where n is the number of orbitals in the basis. If this is specified, then the frozen_orbitals argument must also be specified. - Valid range: The spatial orbital indices valid for the problem, each at most once @@ -262,9 +262,10 @@ A size smaller than the problem needs is rejected before any QPU time is spent, with error code 1221 naming the size to use; the rejected run is still billed at the size it was submitted at. A size larger than it needs runs, and is billed at that larger size. To check the size before submitting, see -[Qubits your problem needs](/docs/guides/qunova-chemistry#qubits-your-problem-needs). This applies to runs made -with a license token too, since the size is the machine the job runs on; a -license token also sets its own qubit limit. +[Qubits your problem needs](/docs/guides/qunova-chemistry#qubits-your-problem-needs). With a license token, +the size is checked the same way and sets the compute, and so the classical +compute cost, but no per-execution fee is charged; the token also sets its own +qubit limit. - Required: No - Example: `"l"` From 98e193beda2fa4c63655d8a116b4819611012502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 14:23:04 +0900 Subject: [PATCH 57/59] Fix the HI-VQE tutorial so it runs as written - Every run passed backend_name="", which the argument schema refuses. Setup now picks a backend with enough qubits for Part 2. - Part 1 freezes five orbitals, so its active space is (10o,12e), not (10o,10e) with six frozen; the CASCI reference matches (10o,12e). - 18.0 RU is the per-execution fees; QPU and compute time come on top. - Results files are downloaded under their own names, and the reading example opens one of them instead of a placeholder path. - Drop a stale output of the FeP-NO geometry cell, and the old qiskit-ibm-runtime pin. - Fix typos, and spell HI-VQE as the guide does, in the title too. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 2 +- docs/tutorials/_toc.json | 2 +- docs/tutorials/index.mdx | 2 +- docs/tutorials/qunova-hivqe.ipynb | 84 ++++++++++++++++-------------- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 6a7ac5aab3d8..062056431b2f 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -1246,7 +1246,7 @@ "- Request access and a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", - "- Try the [Dissociation PES curves with Qunova HiVQE](/docs/tutorials/qunova-hivqe) tutorial.\n", + "- Try the [Dissociation PES curves with Qunova HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "" ] } diff --git a/docs/tutorials/_toc.json b/docs/tutorials/_toc.json index ffdfd3b25f9a..2f372ef00ed2 100644 --- a/docs/tutorials/_toc.json +++ b/docs/tutorials/_toc.json @@ -196,7 +196,7 @@ "url": "/docs/tutorials/colibritd-pde" }, { - "title": "Dissociation PES curves with Qunova HiVQE", + "title": "Dissociation PES curves with Qunova HI-VQE", "url": "/docs/tutorials/qunova-hivqe" }, { diff --git a/docs/tutorials/index.mdx b/docs/tutorials/index.mdx index 4a303aa85106..060a8ac51453 100644 --- a/docs/tutorials/index.mdx +++ b/docs/tutorials/index.mdx @@ -141,7 +141,7 @@ Qiskit Functions are a collection of pre-packaged error management and applicati * [Model a flowing non-viscous fluid using QUICK-PDE](/docs/tutorials/colibritd-pde) - * [Dissociation PES curves with Qunova HiVQE](/docs/tutorials/qunova-hivqe) + * [Dissociation PES curves with Qunova HI-VQE](/docs/tutorials/qunova-hivqe) * [Hybrid quantum-enhanced ensemble classification (grid stability workflow)](/docs/tutorials/sml-classification) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 16e2d8476016..77640be836bd 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -6,14 +6,14 @@ "metadata": {}, "source": [ "---\n", - "title: Dissociation PES curves with Qunova HiVQE\n", - "description: Use Qunova HiVQE to compute dissociation potential energy surface (PES) curves.\n", + "title: Dissociation PES curves with Qunova HI-VQE\n", + "description: Use Qunova HI-VQE to compute dissociation potential energy surface (PES) curves.\n", "---\n", "\n", "\n", "{/* cspell:ignore asstr fontsize labelsize DMRG hivqe mcscf CASCI */}\n", "\n", - "# Dissociation PES curves with Qunova HiVQE" + "# Dissociation PES curves with Qunova HI-VQE" ] }, { @@ -39,7 +39,7 @@ "source": [ "## Background\n", "\n", - "Accurately calculating chemical reaction energies is crucial for scientific advancements in materials science, chemical engineering, drug discovery, and other fields. Among various chemical systems, the Li-S system has garnered significant interest for understanding and developing new battery compositions. This tutorial provides hands-on experience in calculating the Li-S bond dissociation potential energy surface (PES) of a $Li_2S$ system by removing one lithium atom using HiVQE calculations. The results can be compared with reference calculations (CASCI) as well as classical methods like Hartree-Fock (HF) for a 20-qubit problem.\n", + "Accurately calculating chemical reaction energies is crucial for scientific advancements in materials science, chemical engineering, drug discovery, and other fields. Among various chemical systems, the Li-S system has garnered significant interest for understanding and developing new battery compositions. This tutorial provides hands-on experience in calculating the Li-S bond dissociation potential energy surface (PES) of a $Li_2S$ system by removing one lithium atom using HI-VQE calculations. The results can be compared with reference calculations (CASCI) as well as classical methods like Hartree-Fock (HF) for a 20-qubit problem.\n", "\n", "The lithium–sulfur example connects this workflow to research on next-generation batteries for energy storage. Calculating how energy changes as a Li–S bond breaks provides molecular-level insight relevant to understanding the chemical transformations in these systems. More broadly, potential energy surfaces are tools for studying reaction pathways and catalysts for more resource-efficient chemical processes." ] @@ -62,7 +62,7 @@ "outputs": [], "source": [ "!pip install --upgrade pip\n", - "!pip install -U qiskit-ibm-catalog \"qiskit_ibm_runtime<0.42.0\" pyscf numpy matplotlib typing_extensions h5py" + "!pip install -U qiskit-ibm-catalog qiskit-ibm-runtime pyscf numpy matplotlib typing_extensions h5py" ] }, { @@ -86,6 +86,7 @@ "outputs": [], "source": [ "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n", + "from qiskit_ibm_runtime import QiskitRuntimeService\n", "from pyscf import gto, scf, mcscf\n", "import matplotlib.pyplot as plt\n", "import pprint\n", @@ -98,7 +99,15 @@ " token=\"YOUR_API_KEY\",\n", ")\n", "\n", - "hivqe = catalog.load(\"qunova/hivqe-chemistry\")" + "hivqe = catalog.load(\"qunova/hivqe-chemistry\")\n", + "\n", + "# A backend you have access to, with enough qubits for Part 2\n", + "service = QiskitRuntimeService(\n", + " channel=\"ibm_quantum_platform\",\n", + " instance=\"INSTANCE_CRN\",\n", + " token=\"YOUR_API_KEY\",\n", + ")\n", + "backend_name = service.least_busy(operational=True, min_num_qubits=44).name" ] }, { @@ -112,7 +121,8 @@ "below names a `function_size`, which sets the resources it gets and what it is\n", "billed: `\"m\"` for Part 1, and `\"l\"` for Part 2, which needs 44 qubits. Running\n", "the whole tutorial is six runs at `\"m\"` and three at `\"l\"`, or 18.0 resource\n", - "units. See [Function sizes and\n", + "units in per-execution fees, plus the QPU and classical compute time the runs\n", + "use. See [Function sizes and\n", "billing](/docs/guides/qunova-chemistry#function-sizes-and-billing) in the guide for\n", "what the sizes cost.\n", "\n", @@ -140,7 +150,7 @@ "id": "00c68174", "metadata": {}, "source": [ - "You will also need to create a `QiskitServerless` instance to download the results file for the calculation. This uses the same credentials as `QiskitFunctionCatalog`." + "You will also need to create a `QiskitServerless` instance to download the results file for the calculation. This uses the same credentials as `QiskitFunctionsCatalog`." ] }, { @@ -211,7 +221,7 @@ "id": "3cd2cc70", "metadata": {}, "source": [ - "HiVQE calculations will be performed with the options defined below. Using sto3g basis for $Li_2S$, there are 19 spatial orbitals with 22 electrons. To run (10o,10e) case with HiVQE calculation, you can define 10 active orbitals and six frozen orbitals. At each iteration, 100 shots will be used to sample electron configuration generated by the ExcitationPreserving quantum circuit (`epa`) with `circular` entanglement and two repetitions (`reps`). The maximum number of iteration is set to be 30 to ensure termination of iteration with energy convergence." + "HI-VQE calculations will be performed with the options defined below. Using sto3g basis for $Li_2S$, there are 19 spatial orbitals with 22 electrons. To run (10o,12e) case with HI-VQE calculation, you can define 10 active orbitals and freeze the five lowest orbitals, which leaves 12 active electrons. At each iteration, 100 shots will be used to sample electron configuration generated by the ExcitationPreserving quantum circuit (`epa`) with `circular` entanglement and two repetitions (`reps`). The maximum number of iteration is set to be 30 to ensure termination of iteration with energy convergence." ] }, { @@ -241,9 +251,9 @@ "id": "3ee5ec4c", "metadata": {}, "source": [ - "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HiVQE Chemistry function\n", + "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HI-VQE Chemistry function\n", "\n", - "Set up the `for` loop to run HiVQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the ouptut. These geometries need 20 qubits, so the runs are submitted at `function_size=\"m\"`." + "Set up the `for` loop to run HI-VQE calculations with geometries with options defined below. Jobs are submitted in the `for` loop. In this tutorial, you will submit six geometries and retrieve results when they are all completed. In the main function run, you need to define the `max_states` and `max_expansion_states` to control the maximum size of the subspace matrix and to control how many states can be generated using classical CI expansion methods per iteration. The function job ids will be stored in the dictionary with each geometry label to further track and process the output. These geometries need 20 qubits, so the runs are submitted at `function_size=\"m\"`." ] }, { @@ -265,7 +275,7 @@ "for dis, geom in str_geometries.items():\n", " hivqe_run = hivqe.run(\n", " geometry=geom,\n", - " backend_name=\"\",\n", + " backend_name=backend_name,\n", " function_size=\"m\",\n", " max_states=40000,\n", " max_expansion_states=100,\n", @@ -392,7 +402,7 @@ "id": "51a9e47b", "metadata": {}, "source": [ - "The results file for each of the calculations can be downloaded into the current directory using `QiskitServerless`. These files contain `\"states\"`, `\"eigenvector\"`, `\"energy_history\"`, `\"final_energy\"`, and `\"final_energy_variance\"`." + "The results file for each of the calculations can be downloaded into the current directory, under its own name, using `QiskitServerless`. These files contain `\"states\"`, `\"eigenvector\"`, `\"energy_history\"`, `\"final_energy\"`, and `\"final_energy_variance\"`." ] }, { @@ -407,7 +417,10 @@ " for i, job in enumerate(completed_jobs.items()):\n", " dis, cal = job\n", " print(dis, cal.result()[\"results_file_name\"])\n", - " serverless.file_download(cal.result()[\"results_file_name\"], hivqe)" + " results_file_name = cal.result()[\"results_file_name\"]\n", + " serverless.file_download(\n", + " results_file_name, hivqe, target_name=results_file_name\n", + " )" ] }, { @@ -427,7 +440,8 @@ "source": [ "import h5py\n", "\n", - "results_file_name = \"PATH_TO_DOWNLOADED_RESULTS_FILE\"\n", + "# The results file of the 1.51 calculation\n", + "results_file_name = completed_jobs[\"1.51\"].result()[\"results_file_name\"]\n", "\n", "# Read data from the results file for a single calculation\n", "with h5py.File(results_file_name, \"r\") as f:\n", @@ -453,7 +467,7 @@ "source": [ "### Step 4: Post-process and compare with classical methods\n", "\n", - "Classical reference calculation (CASCI) can be conducted for (10o,10e) to validate HiVQE results." + "Classical reference calculation (CASCI) can be conducted for (10o,12e) to validate HI-VQE results." ] }, { @@ -580,8 +594,8 @@ "id": "e1900a94", "metadata": {}, "source": [ - "Let's plot and compare HiVQE results with HF and CASCI.\n", - "You can observe that all HiVQE calculations are well-matched with the classical reference result (CASCI)." + "Let's plot and compare HI-VQE results with HF and CASCI.\n", + "You can observe that all HI-VQE calculations are well-matched with the classical reference result (CASCI)." ] }, { @@ -630,7 +644,7 @@ "\n", "### Step 1: Map classical inputs to a quantum problem\n", "\n", - "Define the options for HiVQE calculations" + "Define the options for HI-VQE calculations" ] }, { @@ -670,17 +684,7 @@ "execution_count": null, "id": "8c93344d", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'5.0': '\\nFe 9.918629 31.289202 1.717339\\nN 10.542914 31.832173 -0.080685\\nN 11.795572 31.199413 2.341831\\nN 9.294593 30.741247 3.513929\\nN 8.042689 31.359481 1.087282\\nC 9.775254 32.111817 -1.200449\\nC 10.600219 32.479101 -2.319680\\nC 11.891090 32.425876 -1.887580\\nC 11.847694 32.024341 -0.507342\\nC 12.945734 31.464689 1.611366\\nC 14.116395 31.289997 2.423572\\nC 13.685777 30.915122 3.663719\\nC 12.252381 30.861042 3.608186\\nC 10.062170 30.463021 4.634102\\nC 9.236749 30.104333 5.755782\\nC 7.945687 30.161198 5.324720\\nC 7.989641 30.552269 3.941498\\nC 6.892881 31.087489 1.815829\\nC 5.722676 31.253502 1.001149\\nC 6.153153 31.631057 -0.238233\\nC 7.586010 31.695401 -0.179773\\nC 8.390724 32.047572 -1.247553\\nH 7.903308 32.291586 -2.187969\\nC 12.973334 31.849872 0.283741\\nH 13.944682 32.031190 -0.169145\\nC 11.447158 30.518591 4.678739\\nH 11.934423 30.277429 5.619969\\nC 6.864795 30.711643 3.146118\\nH 5.893357 30.532078 3.599511\\nH 12.800139 32.636412 -2.439296\\nH 10.224017 32.743662 -3.301293\\nH 15.131785 31.441247 2.076257\\nH 14.273933 30.694315 4.546802\\nH 9.612512 29.848040 6.739754\\nH 7.036117 29.960530 5.879248\\nH 4.707408 31.099933 1.347803\\nH 5.564992 31.851940 -1.121294\\nN 9.666041 36.091609 3.085945\\nO 9.598728 37.226756 3.411299\\n'}" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "geometry_1_75 = \"\"\"\n", "Fe 9.910596 31.534095 1.798088\n", @@ -823,9 +827,9 @@ "id": "5ed92d44", "metadata": {}, "source": [ - "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HiVQE Chemistry function\n", + "### Step 2 and 3: Optimize problem for quantum hardware execution and execute using the HI-VQE Chemistry function\n", "\n", - "Based on the setup of HiVQE and geometries, obtain results sequentially." + "Based on the setup of HI-VQE and geometries, obtain results sequentially." ] }, { @@ -845,7 +849,7 @@ "source": [ "hivqe_run_1_75 = hivqe.run(\n", " geometry=fepno_geometries[\"1.75\"],\n", - " backend_name=\"\",\n", + " backend_name=backend_name,\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", @@ -875,7 +879,7 @@ "print(submitted_job_1_75.job_id, stat)\n", "if stat == \"DONE\":\n", " hivqe_run_1_75_energy = submitted_job_1_75.result()[\"energy\"]\n", - " print(f\"Completed HiVQE calculation, Energy {hivqe_run_1_75_energy}\")\n", + " print(f\"Completed HI-VQE calculation, Energy {hivqe_run_1_75_energy}\")\n", " hivqe_result_fepno[\"1.75\"] = hivqe_run_1_75_energy" ] }, @@ -896,7 +900,7 @@ "source": [ "hivqe_run_2_00 = hivqe.run(\n", " geometry=fepno_geometries[\"2.00\"],\n", - " backend_name=\"\",\n", + " backend_name=backend_name,\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", @@ -926,7 +930,7 @@ "print(submitted_job_2_00.job_id, stat)\n", "if stat == \"DONE\":\n", " hivqe_run_2_00_energy = submitted_job_2_00.result()[\"energy\"]\n", - " print(f\"Completed HiVQE calculation, Energy {hivqe_run_2_00_energy}\")\n", + " print(f\"Completed HI-VQE calculation, Energy {hivqe_run_2_00_energy}\")\n", " hivqe_result_fepno[\"2.00\"] = hivqe_run_2_00_energy" ] }, @@ -947,7 +951,7 @@ "source": [ "hivqe_run_5_00 = hivqe.run(\n", " geometry=fepno_geometries[\"5.00\"],\n", - " backend_name=\"\",\n", + " backend_name=backend_name,\n", " function_size=\"l\",\n", " max_states=400000000,\n", " max_expansion_states=100,\n", @@ -977,7 +981,7 @@ "print(submitted_job_5_00.job_id, stat)\n", "if stat == \"DONE\":\n", " hivqe_run_5_00_energy = submitted_job_5_00.result()[\"energy\"]\n", - " print(f\"Completed HiVQE calculation, Energy {hivqe_run_5_00_energy}\")\n", + " print(f\"Completed HI-VQE calculation, Energy {hivqe_run_5_00_energy}\")\n", " hivqe_result_fepno[\"5.00\"] = hivqe_run_5_00_energy" ] }, @@ -986,7 +990,7 @@ "id": "1c0606d4-088a-4999-bf16-cb6b87637652", "metadata": {}, "source": [ - "The energies from these three runs, so that the comparison below works\n", + "These are the energies from the three runs, so that the comparison below works\n", "without waiting for your own jobs. Skip this cell to use your own." ] }, @@ -1011,7 +1015,7 @@ "source": [ "### Step 4: Post-process and compare with classical methods\n", "\n", - "Classical reference calculation (CASCI-DMRG, maxM=800) results are provided for (22o,22e) to validate HiVQE results." + "Classical reference calculation (CASCI-DMRG, maxM=800) results are provided for (22o,22e) to validate HI-VQE results." ] }, { From f2f4de2f740530df90ff2df0ada0b28c2a850c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 14:25:08 +0900 Subject: [PATCH 58/59] Keep the tutorial's title, and the shared index and toc, unchanged The title is listed in docs/tutorials/index.mdx and _toc.json, which are not ours to change for a spelling. The body keeps HI-VQE. Co-Authored-By: Claude Opus 5.5 --- docs/guides/qunova-chemistry.ipynb | 2 +- docs/tutorials/_toc.json | 2 +- docs/tutorials/index.mdx | 2 +- docs/tutorials/qunova-hivqe.ipynb | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 062056431b2f..6a7ac5aab3d8 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -1246,7 +1246,7 @@ "- Request access and a license, if you need one, by filling in [this form](https://forms.office.com/r/zN3hvMTqJ1).\n", "- Visit the [API reference](/docs/api/functions/qunova-chemistry) for this Qiskit Function.\n", "- Review [Pellow-Jarman, A., et al. (2025). HIVQE: Handover Iterative Variational Quantum Eigensolver for Efficient Quantum Chemistry Calculations. arXiv preprint arXiv:2503.06292](https://arxiv.org/abs/2503.06292).\n", - "- Try the [Dissociation PES curves with Qunova HI-VQE](/docs/tutorials/qunova-hivqe) tutorial.\n", + "- Try the [Dissociation PES curves with Qunova HiVQE](/docs/tutorials/qunova-hivqe) tutorial.\n", "" ] } diff --git a/docs/tutorials/_toc.json b/docs/tutorials/_toc.json index 2f372ef00ed2..ffdfd3b25f9a 100644 --- a/docs/tutorials/_toc.json +++ b/docs/tutorials/_toc.json @@ -196,7 +196,7 @@ "url": "/docs/tutorials/colibritd-pde" }, { - "title": "Dissociation PES curves with Qunova HI-VQE", + "title": "Dissociation PES curves with Qunova HiVQE", "url": "/docs/tutorials/qunova-hivqe" }, { diff --git a/docs/tutorials/index.mdx b/docs/tutorials/index.mdx index 060a8ac51453..4a303aa85106 100644 --- a/docs/tutorials/index.mdx +++ b/docs/tutorials/index.mdx @@ -141,7 +141,7 @@ Qiskit Functions are a collection of pre-packaged error management and applicati * [Model a flowing non-viscous fluid using QUICK-PDE](/docs/tutorials/colibritd-pde) - * [Dissociation PES curves with Qunova HI-VQE](/docs/tutorials/qunova-hivqe) + * [Dissociation PES curves with Qunova HiVQE](/docs/tutorials/qunova-hivqe) * [Hybrid quantum-enhanced ensemble classification (grid stability workflow)](/docs/tutorials/sml-classification) diff --git a/docs/tutorials/qunova-hivqe.ipynb b/docs/tutorials/qunova-hivqe.ipynb index 77640be836bd..f90c011905c2 100644 --- a/docs/tutorials/qunova-hivqe.ipynb +++ b/docs/tutorials/qunova-hivqe.ipynb @@ -6,14 +6,14 @@ "metadata": {}, "source": [ "---\n", - "title: Dissociation PES curves with Qunova HI-VQE\n", - "description: Use Qunova HI-VQE to compute dissociation potential energy surface (PES) curves.\n", + "title: Dissociation PES curves with Qunova HiVQE\n", + "description: Use Qunova HiVQE to compute dissociation potential energy surface (PES) curves.\n", "---\n", "\n", "\n", "{/* cspell:ignore asstr fontsize labelsize DMRG hivqe mcscf CASCI */}\n", "\n", - "# Dissociation PES curves with Qunova HI-VQE" + "# Dissociation PES curves with Qunova HiVQE" ] }, { From 07707d7f3156310cb49b40820029c548e0115491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=B8=ED=98=84?= Date: Thu, 15 Oct 2026 14:57:55 +0900 Subject: [PATCH 59/59] Give size "l" as more than 20 qubits, not "no limit" Co-Authored-By: Claude Opus 5.5 --- docs/api/functions/qunova-chemistry.mdx | 2 +- docs/guides/qunova-chemistry.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/functions/qunova-chemistry.mdx b/docs/api/functions/qunova-chemistry.mdx index 0fcb7d44d522..a843cfd4c229 100644 --- a/docs/api/functions/qunova-chemistry.mdx +++ b/docs/api/functions/qunova-chemistry.mdx @@ -256,7 +256,7 @@ to this function. |-----|-----|-----|-----| | `"s"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU | | `"m"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU | -| `"l"` | No limit | 48 CPUs, 768 GB | 4.0 RU | +| `"l"` | More than 20 | 48 CPUs, 768 GB | 4.0 RU | A size smaller than the problem needs is rejected before any QPU time is spent, with error code 1221 naming the size to use; the rejected run is still diff --git a/docs/guides/qunova-chemistry.ipynb b/docs/guides/qunova-chemistry.ipynb index 6a7ac5aab3d8..a95bf559d801 100644 --- a/docs/guides/qunova-chemistry.ipynb +++ b/docs/guides/qunova-chemistry.ipynb @@ -620,7 +620,7 @@ "| --- | --- | --- | --- |\n", "| `\"s\"` | Up to 10 | 8 CPUs, 32 GB | 0.4 RU |\n", "| `\"m\"` | Up to 20 | 16 CPUs, 128 GB | 1.0 RU |\n", - "| `\"l\"` | No limit | 48 CPUs, 768 GB | 4.0 RU |\n", + "| `\"l\"` | More than 20 | 48 CPUs, 768 GB | 4.0 RU |\n", "\n", "A usage-based run costs its per-execution fee plus the QPU and classical compute\n", "time it uses. Fees are given in resource units (RU); see [IBM Quantum\n",