diff --git a/README.md b/README.md index 0b2b11c..b5c6da9 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ pip install qiskit-transpiler-service By default, the package tries to authenticate to IBM Quantum services with the defined Qiskit API token, and uses your token from the `QISKIT_IBM_TOKEN` environment variable or from the file `~/.qiskit/qiskit-ibm.json` (under the section `default-ibm-quantum`). -*Note*: This library requires Qiskit 1.0 by default. +_Note_: This library requires Qiskit 1.0 by default. ## How to use the library @@ -24,37 +24,37 @@ The following examples demonstrate how to transpile circuits using the Qiskit tr 1. Create a circuit and call the Qiskit transpiler service to transpile the circuit with `ibm_sherbrooke` as the `backend_name`, 3 as the `optimization_level`, and not using AI during the transpilation. - ```python - from qiskit.circuit.library import EfficientSU2 - from qiskit_transpiler_service.transpiler_service import TranspilerService + ```python + from qiskit.circuit.library import EfficientSU2 + from qiskit_transpiler_service.transpiler_service import TranspilerService - circuit = EfficientSU2(101, entanglement="circular", reps=1).decompose() + circuit = EfficientSU2(101, entanglement="circular", reps=1).decompose() - cloud_transpiler_service = TranspilerService( - backend_name="ibm_sherbrooke", - ai=False, - optimization_level=3, - ) - transpiled_circuit = cloud_transpiler_service.run(circuit) - ``` + cloud_transpiler_service = TranspilerService( + backend_name="ibm_sherbrooke", + ai='false', + optimization_level=3, + ) + transpiled_circuit = cloud_transpiler_service.run(circuit) + ``` -*Note:* you only can use `backend_name` devices you are allowed to with your IBM Quantum Account. Apart from the `backend_name`, the `TranspilerService` also allows `coupling_map` as parameter. +_Note:_ you only can use `backend_name` devices you are allowed to with your IBM Quantum Account. Apart from the `backend_name`, the `TranspilerService` also allows `coupling_map` as parameter. -2. Produce a similar circuit and transpile it, requesting AI transpiling capabilities by setting the flag `ai` to `True`: +2. Produce a similar circuit and transpile it, requesting AI transpiling capabilities by setting the flag `ai` to `'true'`: - ```python - from qiskit.circuit.library import EfficientSU2 - from qiskit_transpiler_service.transpiler_service import TranspilerService + ```python + from qiskit.circuit.library import EfficientSU2 + from qiskit_transpiler_service.transpiler_service import TranspilerService - circuit = EfficientSU2(101, entanglement="circular", reps=1).decompose() + circuit = EfficientSU2(101, entanglement="circular", reps=1).decompose() - cloud_transpiler_service = TranspilerService( - backend_name="ibm_sherbrooke", - ai=True, - optimization_level=1, - ) - transpiled_circuit = cloud_transpiler_service.run(circuit) - ``` + cloud_transpiler_service = TranspilerService( + backend_name="ibm_sherbrooke", + ai='true', + optimization_level=1, + ) + transpiled_circuit = cloud_transpiler_service.run(circuit) + ``` ### Using the AIRouting pass manually @@ -108,9 +108,9 @@ The synthesis respects the coupling map of the device: it can be run safely afte The following synthesis passes are available from `qiskit_transpiler_service.ai.synthesis`: -- *AICliffordSynthesis*: Synthesis for [Clifford](https://docs.quantum.ibm.com/api/qiskit/qiskit.quantum_info.Clifford) circuits (blocks of `H`, `S` and `CX` gates). Currently up to 9 qubit blocks. -- *AILinearFunctionSynthesis*: Synthesis for [Linear Function](https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.LinearFunction) circuits (blocks of `CX` and `SWAP` gates). Currently up to 9 qubit blocks. -- *AIPermutationSynthesis*: Synthesis for [Permutation](https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.Permutation#permutation) circuits (blocks of `SWAP` gates). Currently available for 65, 33, and 27 qubit blocks. +- _AICliffordSynthesis_: Synthesis for [Clifford](https://docs.quantum.ibm.com/api/qiskit/qiskit.quantum_info.Clifford) circuits (blocks of `H`, `S` and `CX` gates). Currently up to 9 qubit blocks. +- _AILinearFunctionSynthesis_: Synthesis for [Linear Function](https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.LinearFunction) circuits (blocks of `CX` and `SWAP` gates). Currently up to 9 qubit blocks. +- _AIPermutationSynthesis_: Synthesis for [Permutation](https://docs.quantum.ibm.com/api/qiskit/qiskit.circuit.library.Permutation#permutation) circuits (blocks of `SWAP` gates). Currently available for 65, 33, and 27 qubit blocks. We expect to gradually increase the size of the supported blocks. @@ -126,9 +126,9 @@ For sub-circuit to be synthesized by the AI synthesis passes, it must lay on a c To complement the synthesis passes we also provide custom collection passes for Cliffords, Linear Functions and Permutations that can be imported from `qiskit_transpiler_service.ai.collection`: -- *CollectCliffords*: Collects `Clifford` blocks as `Instruction` objects and stores the original sub-circuit to compare against it after synthesis. -- *CollectLinearFunctions*: Collects blocks of `SWAP` and `CX` as `LinearFunction` objects and stores the original sub-circuit to compare against it after synthesis. -- *CollectPermutations*: Collects blocks of `SWAP` circuits as `Permutations`. +- _CollectCliffords_: Collects `Clifford` blocks as `Instruction` objects and stores the original sub-circuit to compare against it after synthesis. +- _CollectLinearFunctions_: Collects blocks of `SWAP` and `CX` as `LinearFunction` objects and stores the original sub-circuit to compare against it after synthesis. +- _CollectPermutations_: Collects blocks of `SWAP` circuits as `Permutations`. These custom collection passes limit the sizes of the collected sub-circuits so that they are supported by the AI synthesis passes, so it is recommended to use them after the routing passes and before the synthesis passes to get a better optimization overall. diff --git a/ai-transpiler-demo.ipynb b/ai-transpiler-demo.ipynb index 6ae40f9..d4c0c42 100644 --- a/ai-transpiler-demo.ipynb +++ b/ai-transpiler-demo.ipynb @@ -212,7 +212,7 @@ "\n", "qiskit_lvl3_transpiler_service = TranspilerService(\n", " backend_name=\"ibm_torino\",\n", - " ai=False,\n", + " ai='false',\n", " optimization_level=3,\n", ")" ] @@ -281,7 +281,7 @@ "source": [ "qiskit_lvl3_ai_transpiler_service = TranspilerService(\n", " backend_name=\"ibm_torino\",\n", - " ai=True,\n", + " ai='true',\n", " optimization_level=3,\n", ")" ] diff --git a/documentation-examples.ipynb b/documentation-examples.ipynb index 76e8c5d..494179d 100644 --- a/documentation-examples.ipynb +++ b/documentation-examples.ipynb @@ -22,7 +22,7 @@ "\n", "cloud_transpiler_service = TranspilerService(\n", " backend_name=\"ibm_sherbrooke\",\n", - " ai=False,\n", + " ai='false',\n", " optimization_level=3,\n", ")\n", "transpiled_circuit_no_ai = cloud_transpiler_service.run(circuit)" @@ -50,7 +50,7 @@ "\n", "cloud_transpiler_service = TranspilerService(\n", " backend_name=\"ibm_sherbrooke\",\n", - " ai=True,\n", + " ai='true',\n", " optimization_level=1,\n", ")\n", "transpiled_circuit_ai = cloud_transpiler_service.run(circuit)" diff --git a/qiskit_transpiler_service/transpiler_service.py b/qiskit_transpiler_service/transpiler_service.py index ac98514..9741123 100644 --- a/qiskit_transpiler_service/transpiler_service.py +++ b/qiskit_transpiler_service/transpiler_service.py @@ -27,7 +27,7 @@ """ import logging -from typing import Dict, List, Union +from typing import Dict, List, Union, Literal from qiskit import QuantumCircuit @@ -42,8 +42,8 @@ class TranspilerService: :param optimization_level: The optimization level to use during the transpilation. There are 4 optimization levels ranging from 0 to 3, where 0 is intended for not performing any optimizations and 3 spends the most effort to optimize the circuit. :type optimization_level: int - :param ai: Specifyies if the transpilation should use AI or not, defaults to True. - :type ai: bool, optional + :param ai: Specifies if the transpilation should use AI or not, defaults to True. + :type ai: str, optional :param coupling_map: A list of pairs that represents physical links between qubits. :type coupling_map: list[list[int]], optional :param backend_name: Name of the backend used for doing the transpilation. @@ -57,7 +57,7 @@ class TranspilerService: def __init__( self, optimization_level: int, - ai: bool = True, + ai: Literal['true', 'false', 'auto'] = 'true', coupling_map: Union[List[List[int]], None] = None, backend_name: Union[str, None] = None, qiskit_transpile_options: Dict = None, diff --git a/qiskit_transpiler_service/wrappers/transpile.py b/qiskit_transpiler_service/wrappers/transpile.py index d3014a4..053b126 100644 --- a/qiskit_transpiler_service/wrappers/transpile.py +++ b/qiskit_transpiler_service/wrappers/transpile.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. import logging -from typing import Dict, List, Union +from typing import Dict, List, Union, Literal import numpy as np from qiskit import QuantumCircuit, QuantumRegister, qasm2, qasm3 @@ -43,7 +43,7 @@ def transpile( optimization_level: int = 1, backend: Union[str, None] = None, coupling_map: Union[List[List[int]], None] = None, - ai: bool = True, + ai: Literal['true', 'false', 'auto'] = 'true', qiskit_transpile_options: Dict = None, ai_layout_mode: str = None, ): diff --git a/tests/test_transpiler_service.py b/tests/test_transpiler_service.py index fc8af7f..4661ab0 100644 --- a/tests/test_transpiler_service.py +++ b/tests/test_transpiler_service.py @@ -32,7 +32,7 @@ @pytest.mark.parametrize( "optimization_level", [1, 2, 3], ids=["opt_level_1", "opt_level_2", "opt_level_3"] ) -@pytest.mark.parametrize("ai", [False, True], ids=["no_ai", "ai"]) +@pytest.mark.parametrize("ai", ['false', 'true'], ids=["no_ai", "ai"]) @pytest.mark.parametrize( "qiskit_transpile_options", [None, {"seed_transpiler": 0}], @@ -56,7 +56,7 @@ def test_rand_circ_backend_routing(optimization_level, ai, qiskit_transpile_opti @pytest.mark.parametrize( "optimization_level", [1, 2, 3], ids=["opt_level_1", "opt_level_2", "opt_level_3"] ) -@pytest.mark.parametrize("ai", [False, True], ids=["no_ai", "ai"]) +@pytest.mark.parametrize("ai", ['false', 'true'], ids=["no_ai", "ai"]) @pytest.mark.parametrize( "qiskit_transpile_options", [None, {"seed_transpiler": 0}], @@ -85,7 +85,7 @@ def test_qv_backend_routing(optimization_level, ai, qiskit_transpile_options): ], ) @pytest.mark.parametrize("optimization_level", [1, 2, 3]) -@pytest.mark.parametrize("ai", [False, True], ids=["no_ai", "ai"]) +@pytest.mark.parametrize("ai", ['false', 'true'], ids=["no_ai", "ai"]) @pytest.mark.parametrize("qiskit_transpile_options", [None, {"seed_transpiler": 0}]) def test_rand_circ_cmap_routing( coupling_map, optimization_level, ai, qiskit_transpile_options @@ -108,7 +108,7 @@ def test_qv_circ_several_circuits_routing(): cloud_transpiler_service = TranspilerService( backend_name="ibm_brisbane", - ai=True, + ai='true', optimization_level=1, ) transpiled_circuit = cloud_transpiler_service.run([qv_circ] * 2) @@ -129,7 +129,7 @@ def test_qv_circ_wrong_input_routing(): cloud_transpiler_service = TranspilerService( backend_name="ibm_brisbane", - ai=True, + ai='true', optimization_level=1, ) @@ -138,7 +138,7 @@ def test_qv_circ_wrong_input_routing(): cloud_transpiler_service.run(circ_dict) -@pytest.mark.parametrize("ai", [False, True], ids=["no_ai", "ai"]) +@pytest.mark.parametrize("ai", ['false', 'true'], ids=["no_ai", "ai"]) def test_transpile_layout_reconstruction(ai): n_qubits = 27