-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
894 additions
and
459 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,7 @@ | ||
{ | ||
"python.analysis.extraPaths": [ | ||
"qiskit_quantuminspire" | ||
], | ||
"python.testing.unittestEnabled": false, | ||
"python.testing.pytestEnabled": true, | ||
"python.testing.pytestPath": "${command:python.interpreterPath}", | ||
"python.testing.autoTestDiscoverOnSaveEnabled": true, | ||
"python.testing.cwd": "${workspaceFolder}", | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Basics | ||
|
||
Quantum Inspire 2 supports hybrid classical-quantum algorithms, and allows execution of both the quantum and the classical part fully on the QI2 servers. | ||
|
||
## Script format | ||
|
||
Any script that will be executed on the QI2 platform is required to have at least the `execute()` and `finalize()` functions. | ||
|
||
### Execute | ||
|
||
The execute function is the function that gets called by QI2 first. As an argument it gets a `QuantumInterface`, which is what allows you to actually execute your circuit. A simple example, where a function `generate_circuit()` is called that returns cQASM as a string, is shown below. In this example, the same circuit is executed 5 times in a row as a simple illustration of the interchanging control between the hybrid and classical domains. Normally, you might want to change your `QuantumCircuit` between each execution based on your results. | ||
|
||
```python | ||
def execute(qi: QuantumInterface) -> None: | ||
"""Run the classical part of the Hybrid Quantum/Classical Algorithm. | ||
Args: | ||
qi: A QuantumInterface instance that can be used to execute quantum circuits | ||
The qi object has a single method called execute_circuit, its interface is described below: | ||
qi.execute_circuit args: | ||
circuit: a string representation of a quantum circuit | ||
number_of_shots: how often to execute the circuit | ||
qi.execute_circuit return value: | ||
The results of executing the quantum circuit, this is an object with the following attributes | ||
results: The results from iteration n-1. | ||
shots_requested: The number of shots requested by the user for the previous iteration. | ||
shots_done: The number of shots actually run. | ||
""" | ||
for i in range(1, 5): | ||
circuit = generate_circuit() | ||
_ = qi.execute_circuit(circuit, 1024) | ||
``` | ||
|
||
### Finalize | ||
|
||
The `finalize()` function allows you to aggregate your results. It should return a dictionary which will be stored as the final result. By default it takes a list of all measurements as an argument, but through the use of globals you could also export other data. | ||
|
||
```python | ||
def finalize(list_of_measurements: List[Dict[str, Any]]) -> Dict[str, Any]: | ||
"""Aggregate the results from all iterations into one final result. | ||
Args: | ||
list_of_measurements: List of all results from the previous iterations. | ||
Returns: | ||
A free-form result, with a `property`: `value` structure. Value can | ||
be everything serializable. | ||
""" | ||
return {"results": list_of_measurements} | ||
``` | ||
|
||
## Execution | ||
|
||
A complete script with both example functions can be found [here](./hqca_circuit.py). This can be uploaded to QI2 as follows (using the CLI), where `<backend_id>` is the id number of the selected quantum backend, which can be retrieved using the Qiskit-QuantumInspire QIProvider. | ||
|
||
```bash | ||
qi files upload ./hqca_circuit.py <backend_id> | ||
``` | ||
|
||
The final results can be retrieved as follows, where `<job_id>` is the job id returned by the previous command. | ||
|
||
```bash | ||
qi final_results get <job_id> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
from typing import Any, Dict, List | ||
|
||
from qiskit.circuit import QuantumCircuit | ||
|
||
from qiskit_quantuminspire import cqasm | ||
from qiskit_quantuminspire.hybrid.quantum_interface import QuantumInterface | ||
|
||
|
||
def generate_circuit() -> str: | ||
# Create a basic Bell State circuit: | ||
qc = QuantumCircuit(2, 2) | ||
qc.reset(0) | ||
qc.h(0) | ||
qc.cx(0, 1) | ||
qc.measure([0, 1], [0, 1]) | ||
|
||
return cqasm.dumps(qc) | ||
|
||
|
||
def execute(qi: QuantumInterface) -> None: | ||
"""Run the classical part of the Hybrid Quantum/Classical Algorithm. | ||
Args: | ||
qi: A QuantumInterface instance that can be used to execute quantum circuits | ||
The qi object has a single method called execute_circuit, its interface is described below: | ||
qi.execute_circuit args: | ||
circuit: a string representation of a quantum circuit | ||
number_of_shots: how often to execute the circuit | ||
qi.execute_circuit return value: | ||
The results of executing the quantum circuit, this is an object with the following attributes | ||
results: The results from iteration n-1. | ||
shots_requested: The number of shots requested by the user for the previous iteration. | ||
shots_done: The number of shots actually run. | ||
""" | ||
for i in range(1, 5): | ||
circuit = generate_circuit() | ||
_ = qi.execute_circuit(circuit, 1024) | ||
|
||
|
||
def finalize(list_of_measurements: List[Dict[str, Any]]) -> Dict[str, Any]: | ||
"""Aggregate the results from all iterations into one final result. | ||
Args: | ||
list_of_measurements: List of all results from the previous iterations. | ||
Returns: | ||
A free-form result, with a `property`: `value` structure. Value can | ||
be everything serializable. | ||
""" | ||
return {"results": list_of_measurements} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# (H2) Hydrogen molecuole ground state energy determined using VQE with a UCCSD-ansatz function. | ||
# Compared with Hartee-Fock energies and with energies calculated by NumPyMinimumEigensolver | ||
# This script is based on the Qiskit Chemistry tutorials | ||
import warnings | ||
from dataclasses import dataclass | ||
from typing import Any, Dict, List | ||
|
||
from qiskit.primitives import BackendEstimator | ||
from qiskit_algorithms import NumPyMinimumEigensolverResult, VQEResult | ||
from qiskit_algorithms.minimum_eigensolvers import VQE | ||
from qiskit_algorithms.optimizers import COBYLA | ||
from qiskit_nature.second_q.circuit.library import UCCSD, HartreeFock | ||
from qiskit_nature.second_q.drivers import PySCFDriver | ||
from qiskit_nature.second_q.mappers import ParityMapper | ||
|
||
from qiskit_quantuminspire.hybrid.hybrid_backend import QIHybridBackend | ||
from qiskit_quantuminspire.hybrid.quantum_interface import QuantumInterface | ||
|
||
resultstring = "" | ||
|
||
|
||
@dataclass | ||
class _GroundStateEnergyResults: | ||
result: VQEResult | NumPyMinimumEigensolverResult | ||
nuclear_repulsion_energy: float | ||
|
||
|
||
def calculate_H0(backend: QIHybridBackend, distance: float = 0.735) -> _GroundStateEnergyResults: | ||
mapper = ParityMapper(num_particles=(1, 1)) | ||
molecule = f"H 0.0 0.0 0.0; H 0.0 0.0 {distance}" | ||
driver = PySCFDriver(molecule) | ||
with warnings.catch_warnings(): | ||
warnings.simplefilter("ignore", category=UserWarning) | ||
es_problem = driver.run() | ||
|
||
fermionic_op = es_problem.hamiltonian.second_q_op() | ||
qubit_op = mapper.map(fermionic_op) | ||
n_particles = es_problem.num_particles | ||
n_spatial_orbitals = es_problem.num_spatial_orbitals | ||
|
||
nuclear_repulsion_energy = es_problem.nuclear_repulsion_energy | ||
|
||
initial_state = HartreeFock(n_spatial_orbitals, n_particles, mapper) | ||
ansatz = UCCSD(n_spatial_orbitals, n_particles, mapper, initial_state=initial_state) | ||
|
||
optimizer = COBYLA(maxiter=1) # 10 iterations take two minutes | ||
estimator = BackendEstimator(backend=backend) | ||
|
||
algo = VQE(estimator, ansatz, optimizer) | ||
result = algo.compute_minimum_eigenvalue(qubit_op) | ||
|
||
print(f"{distance=}: nuclear_repulsion_energy={nuclear_repulsion_energy}, eigenvalue={result.eigenvalue}") | ||
global resultstring | ||
resultstring += ( | ||
f"{distance=}: nuclear_repulsion_energy={nuclear_repulsion_energy}, eigenvalue={result.eigenvalue}\n" | ||
) | ||
return _GroundStateEnergyResults(result, nuclear_repulsion_energy) | ||
|
||
|
||
def execute(qi: QuantumInterface) -> None: | ||
c = calculate_H0(backend=QIHybridBackend(qi)) | ||
global resultstring | ||
resultstring += str(c) | ||
print(c) | ||
|
||
|
||
def finalize(list_of_measurements: Dict[int, List[Any]]) -> Dict[str, Any]: | ||
return {"measurements": list_of_measurements, "resultstring": resultstring} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
====================== | ||
Hybrid Algorithms | ||
====================== | ||
|
||
Unlock the power of hybrid quantum-classical computing with Qiskit-QuantumInspire. | ||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
|
||
Basics <basics> | ||
Leveraging Qiskit <leveraging_qiskit> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Leveraging Qiskit | ||
|
||
Qiskit has a lot more to offer than execution of simple `QuantumCircuits`, and because QI2 allows for execution of both the classical and quantum parts of a hybrid algorithm you can achieve fast execution of many of the quantum algorithms the Qiskit ecosystem has to offer. Apart from ensuring your scripts use the format shown [here](./basics.md), you are required to use the special `QIHybridBackend()` as your Qiskit backend object. This backend ensures the correct quantum backend is inferred from what you selected when uploading the script. A full working example (that can be uploaded to QI2 as-is) can be found [here](./hydrogen.py). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.