-
Notifications
You must be signed in to change notification settings - Fork 18
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
Integrating BQSKit into MQTBench benchmark generation module #286
base: main
Are you sure you want to change the base?
Integrating BQSKit into MQTBench benchmark generation module #286
Conversation
In independent level benchmark, circuit is transpiled to QASM 2.0 compatible. This is because there are some gates used in Qiskit such as `mcx` and `mcphase` which are not correctly decomposed and converted by bqskit.
Error threshold is used for compilation verification. As stated in bqskit tutorial, verification is not for free. It is exponentially costly in time. By default, bqskit doesn't do verification. For MQTBench, verification may not be necessary.
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> Circuit: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> bool: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> Circuit: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> bool: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> Circuit: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
target_directory: str = "./", | ||
target_filename: str = "", | ||
) -> bool: | ||
... |
Check notice
Code scanning / CodeQL
Statement has no effect Note
Bqskit code in benchmark generator was not properly setup. Test cases were also not properly setup. This commit fixes both. Note that the test convert bqskit circuit to qiskit is commented out because of the bug in bqskit BQSKit/bqskit#214
The test case fix is just to get it passing. It doesn't test the actual QASM file generation in the functions. I have left TODOs in the code to remind me to add these tests later.
TODOs are added to test_bench to indicate the test case code that needs to be updated once the bugs in bqskit library are fixed.
Fixed failing test cases due to bugs in code. Some test cases were left to failed intentionally to indicate the part that needs to be updated when the bugs in bqskit library are fixed. Alternatively, in some cases, I have left TODOs comments in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for your effort and this PR, @jagandecapri. I am very happy that we will (soon) also support BQSKit as another compiler. I have just mentioned a few things that caught my attention. Additionally I was wondering, whether we really need all the newly introduced type ignores. Please carefully double check, whether those are actually necessary.
@@ -19,6 +19,7 @@ requires-python = ">=3.9" | |||
dynamic = ["version"] | |||
|
|||
dependencies = [ | |||
"bqskit>=1.1.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to add an upper cap as well.
@@ -141,6 +148,31 @@ def generate_mapped_levels( | |||
) -> None: | |||
for provider in get_available_providers(): | |||
for device in provider.get_available_devices(): | |||
for opt_level in [1, 2, 3, 4]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be iterate over BQSKitSettings
that cover those optimization levels? I am aware that this is not the case for Qiskit and TKET as well but desired (see #88). Therefore, I would like this new implementation to already follow this direction.
@@ -198,6 +230,28 @@ def generate_native_gates_levels( | |||
parameter_space: list[tuple[int, str]] | list[int] | list[str] | range, | |||
) -> None: | |||
for provider in get_available_providers(): | |||
for opt_level in [1, 2, 3, 4]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
from mqt.bench.devices import Device, Provider | ||
|
||
|
||
class CachedCompiler: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this needed? Do we really need to have this definition in our code and cannot use something from BQSKit?
"cx": CNOTGate(), | ||
"cz": CZGate(), | ||
"ecr": ECRGate(), | ||
"xx_plus_yy": XXPlusYYGate(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you also make sure that this gate is implemented for TKET as well in the tket_helper.py
file? Same for the cp
gate.
except Exception as e: | ||
print("BQSKit Exception Indep: ", e) | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the BQSKit compilation happening? I don't see it here.
print("BQSKit Exception NativeGates: ", e) | ||
return False | ||
|
||
gate_set = provider.get_native_gates() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all those compilation commands should be within the try
block
@@ -70,15 +73,18 @@ def sample_filenames() -> list[str]: | |||
"ae_indep_qiskit_10.qasm", | |||
"ghz_nativegates_rigetti_qiskit_opt3_54.qasm", | |||
"ae_indep_tket_93.qasm", | |||
"ae_indep_bqskit_93.qasm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe a smaller circuit would be better suited for BQSKit because of their runtime (especially for optimization levels >2)
("indep", 2), | ||
("mapped", 9), | ||
("indep", 3), | ||
("mapped", 11), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have the test case sizes changed?
|
This PR addresses #282. In summary, a new module called
bsqkit_helper
is created to integrate BSQKit into MQTBench. There are some open issues. Namely, QASM generation of the benchmark is not working at the moment and the test cases currently doesn’t test for QASM generation. There are also other bugs as highlighted below. Numpy was also used in the module which is open for discussion as I saw Numpy is not a dependency in MQTBench currently. Test coverage might be lower as I didn’t add new test cases for the compiler cache and custom gates (ECR and XXPlusYY). Transpilation to only QASM 2.0 gates using Qiskit is needed before converting to bqskit circuit as not all Qiskit circuit gates that is used in the benchmark has an equivalent in bqskit, e.g:mcx
gate. Without the transpilation, bsqkit converts the unsupported gate to arbitrarily large block of custom gate which then fails to compile. Runtime for test cases seems to have increased quite considerably with the introduction of bqskit. More details as below:Bugs in bqskit
QASM string representation
cry
gate bugcry
gate(s) execute as following:pricingcall
test case executes indefinitelypricingput
andrandom
test case sometimes works and sometimes face the same problem of indefinite execution aspricingcall
. Forrandom
, since it is a random circuit from Qiskit, I suspect when there are multiplecry
gates, the test cases starts to go into indefinite executionNew improvements
Custom gates
DifferentiableUnitary
andLocallyOptimizableUnitary
. ADifferentiableUnitary
can be used in instantiation calls that use a gradient based optimization subroutine. On the other hand,LocallyOptimizableUnitary
can be used in instantiation calls that use a tensor-network based approach like QFactor. More info at hereget_unitary
andget_grad
is correct. Obtained unitary from Qiskit documentation for XXPlusYY gate. As for the gradient, I derived manually and verified with WolframAlpha.get_grad
function. However, numpy is not listed as dependency inpyproject.toml
. I think it gets installed with other library. Should we make it a dependency in MQTBench? if we agree on using numpy, then, some functionality that is usingcmath
andmath
module inbsqkit_helper
can be replaced with numpyCPhase gate
Cache for compiler
compile
function creates resources to parallelize the compilation across the processors in the system. Hence, there is a waiting time for the setup to occur. Bqskit documentation suggested caching the compiler instance for repeated call of thecompile
function which is implemented in theCacheCompiler
class using the singleton design patternatexit
module to close it when the script exits__new__
method asruff
was throwing error for the return type which seems to be correct from my point of viewRuntime of test case
time pytest -k 'test_quantumcircuit_native_and_mapped_levels'
for only bqskit, minus the circuits mentioned in thecry
bug section above. It takes ~54 minutes to run this one test function in my laptop. The other test functions execution time seems reasonableCode structure
The
bsqkit_helper
class seems to be doing a lot of things, managing cache for the compiler, creating custom gates and benchmark generation. Maybe it could be broken to different files. I didn’t want to change the structure of the repository, so I’ve put all of it in the helper class. Open for discussion.With that, looking forward to your kind review and discussions. 🙂