Skip to content

Conversation

@d1ssk
Copy link
Contributor

@d1ssk d1ssk commented Mar 31, 2025

Before submitting, please check the following:

  • Make sure you have tests for the new code and that test passes (run tox)
  • format added code by black -l 120 <filename>
  • If applicable, add a line to the [unreleased] part of CHANGELOG.md, following keep-a-changelog.

Then, please fill in below:

Context (if applicable):
This PR aligns with the refactored backend interface structure introduced in graphix PR /#261

Description of the change:

  • Implemented IBMQBackend.
  • Implemented IBMQJob.
  • Refactored and separated concerns:
    • compiler.py: converts Pattern to QuantumCircuit
    • executor.py: handles both real hardware execution and Aer simulation
    • job.py: manages submitted job.
    • result_utils.py: extracts and formats output from raw IBMQ results
    • compile_options.py: defines IBMQCompileOptions dataclass for type-safe parameter handling
  • backend.py: orchestrates the entire workflow from compile → submit → retrieve

Related issue:

also see that checks (github actions) pass.
If lint check keeps failing, try installing black==22.8.0 as behavior seems to vary across versions.

@shinich1 shinich1 requested a review from thierry-martinez May 12, 2025 11:25
@d1ssk d1ssk requested a review from shinich1 May 26, 2025 12:11
@@ -0,0 +1,56 @@
import pytest

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly recommend you add type annotations, at least to newly-added files.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not omit return type annotations.

setup.py Outdated
exec(fp.read(), version)

requirements = [requirement.strip() for requirement in open("requirements.txt").readlines()]
# requirements = [requirement.strip() for requirement in open("requirements.txt").readlines()]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this line removed in favor of the explicit definition of requirements in the following line? I think the previous version of the code, where requirements was obtained from the contents of requirements.txt, was preferable, since it allows us not to duplicate the list of the dependencies in both setup.py and requirements.txt.

Note that there is already an inconsistency resulting from this duplication: graphix is listed here but is missing in requirements.txt.

I think we should plan, probably not in this PR, but in a subsequent PR, to move the declarative contents of setup.py to pyproject.toml and remove setup.py.

Copy link

@thierry-martinez thierry-martinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some fixes should be made for this PR to work, now that TeamGraphix/graphix#261 has been merged.

setup.py Outdated
exec(fp.read(), version)

requirements = [requirement.strip() for requirement in open("requirements.txt").readlines()]
# requirements = [requirement.strip() for requirement in open("requirements.txt").readlines()]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this line removed in favor of the explicit definition of requirements in the following line? I think the previous version of the code, where requirements was obtained from the contents of requirements.txt, was preferable, since it allows us not to duplicate the list of the dependencies in both setup.py and requirements.txt.

Note that there is already an inconsistency resulting from this duplication: graphix is listed here but is missing in requirements.txt.

I think we should plan, probably not in this PR, but in a subsequent PR, to move the declarative contents of setup.py to pyproject.toml and remove setup.py.

numpy
qiskit>=1.0
qiskit_ibm_runtime
qiskit-aer

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

graphix is probably missing here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comments. I had temporarily modified the code to use a specific branch of graphix and forgot to revert it; I’ve now fixed it in 9cade0e.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the plan to make other PR to move the declarative contents of setup.py into pyproject.toml and remove setup.py.

tox.ini Outdated
description = Run the unit tests
deps =
-r {toxinidir}/requirements.txt
git+https://github.com/TeamGraphix/graphix@device_interface_abc#egg=graphix

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the branch device_interface_abc no longer exists since TeamGraphix/graphix#261 was merged.

Whether or not we rely on a particular branch of graphix, I think the dependency on graphix should not be made explicit here, but in requirements.txt, since users could want to install dependencies directly with pip install -r, and not necessarily with tox.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9cade0e

from qiskit import transpile
from qiskit_aer import AerSimulator
from graphix_ibmq.compiler import IBMQPatternCompiler
import random_circuit as rc

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random_circuit no longer exists: you probably want to use graphix.random_objects.

matrix:
os: ['ubuntu-latest', 'windows-2022', 'macos-latest']
python: ['3.8', '3.9', '3.10', '3.11']
python: ['3.9', '3.10', '3.11', '3.12']

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These versions of Python are not really used: regardless of the version of Python we test here, tox installs and tests Python 3.9, 3.10, and 3.11 in its own environments. That means we run the exact same set of tests four times, and each time we test the three versions of Python listed in tox.ini. We probably want to test only one version of Python at this level (and probably even without explicitly specifying a particular version), and let tox run the tests in its multiple environments.

Copy link
Contributor Author

@d1ssk d1ssk Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment, but actually I don't think the current setup runs every tox env four times. Each github actions job only invokes its corresponding tox environment (e.g. the 3.10 runner only runs py310, the 3.11 runner only runs py311, etc.), although running tox in local environment indeed execute tests in all the versions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, sorry: I was mistaken, you're right. That is the purpose of the [gh-actions] section in tox.ini. Then everything is fine!

"""IBMQ backend implementation for compiling and executing quantum patterns."""

_options: IBMQCompileOptions
_compiled_circuit: QuantumCircuit | None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_compiled_circuit and _compiler should not be part of the internal state of the backend, because we may want to compile several circuits with the same backend instance without losing the previous circuits each time we compile a new one. It would be better if we had a class to represent IBMQCompiledCircuit, and the method compile would return an instance of this class rather than storing the circuit in the internal state of the backend.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comment. Refactored accordingly in d2b6035

from graphix_ibmq.compiler import IBMQPatternCompiler


class IBMQJob:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class could be implemented as a dataclass.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comment. Refactored accordingly in d2b6035

def __init__(
self,
job: LocalRuntimeJob | RuntimeJobV2,
compiler: IBMQPatternCompiler,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to know the compiler at this level; we only need to know the pattern and the register dictionary used by retrieve_result.

Copy link
Contributor Author

@d1ssk d1ssk Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comment. Refactored in d2b6035 so that IBMQJob class has IBMQCompliedCircuit instance instead of compiler instance to access pattern or register dictionary information.

Copy link

@thierry-martinez thierry-martinez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks.

matrix:
os: ['ubuntu-latest', 'windows-2022', 'macos-latest']
python: ['3.8', '3.9', '3.10', '3.11']
python: ['3.9', '3.10', '3.11', '3.12']

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, sorry: I was mistaken, you're right. That is the purpose of the [gh-actions] section in tox.ini. Then everything is fine!

@EarlMilktea
Copy link

@d1ssk

General comments:

  • I'm seeing trivial type errors that can be resolved readily with mypy / pyright. I suggest resolving them early in refactoring steps.
  • Using None as default values in class is, I believe, in general bad because you need to write is None or similar type narrowing branches each time you want to do something meaningful. Why not initialize them in __init__ ?
  • Input type annotations must be thoroughly expressed in collections.abc instances rather than dict / list etc.
  • Please do not define get_xxx or set_xxx : use @property instead. If your set_xxx has additional arguments it might also be a bad design as setting something is inherently free from additional information.
  • Please do not omit argument/return type annotations even when they are just plain -> None .

@d1ssk
Copy link
Contributor Author

d1ssk commented Jul 28, 2025

@EarlMilktea Thank you for the review. I implemented your suggestions.

  • Resolved type errors: All type errors previously reported by mypy have been resolved.
  • Refactored IBMQBackend to eliminate None initialization and set_xxx methods.
    • Replaced the set_simulator() and set_hardware() methods with factory classmethods (from_simulator() and from_hardware()).
  • Use of collections.abc instances for Inputs
  • Completed Type Annotations

Also, I replaced all print() with the standard logging module.

@d1ssk d1ssk merged commit b995d07 into master Sep 22, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants