Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctly parse string boolean for ai param #7

Merged
merged 6 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down Expand Up @@ -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.

Expand All @@ -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.

Expand Down
4 changes: 2 additions & 2 deletions ai-transpiler-demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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",
")"
]
Expand Down Expand Up @@ -282,7 +282,7 @@
"\n",
"qiskit_lvl3_ai_transpiler_service = TranspilerService(\n",
" backend_name=\"ibm_torino\",\n",
" ai=True,\n",
" ai='true',\n",
" optimization_level=3,\n",
")"
]
Expand Down
4 changes: 2 additions & 2 deletions documentation-examples.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
Expand Down Expand Up @@ -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)"
Expand Down
8 changes: 4 additions & 4 deletions qiskit_transpiler_service/transpiler_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"""

import logging
from typing import Dict, List, Union
from typing import Dict, List, Union, Literal

from qiskit import QuantumCircuit

Expand All @@ -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.
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions qiskit_transpiler_service/wrappers/transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
):
Expand Down
12 changes: 6 additions & 6 deletions tests/test_transpiler_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}],
Expand All @@ -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}],
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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,
)

Expand All @@ -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

Expand Down