-
Notifications
You must be signed in to change notification settings - Fork 6
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
Develop #97
base: master
Are you sure you want to change the base?
Conversation
* some first benchmarking metrics for InitialMapping and Routing + tests (still failing) * progress, still some fixes needed. * some metrics * more routing metrics + isort + black * Cleanup * Improved performance * First shot at benchmarking workflow * 'fix' pytest * addd tests and docstrings * Happify mypy * Initial idea qiskit MapperWrapper * Documentation * Docstrings * Add tests for qiskit_utils * bugfix * Add tests for MaxCutQAOA generator * Happify pylint * Update qgym/generators/qiskit_circuit.py Co-authored-by: Roberto Turrado Camblor <rturrado@gmail.com> * Update qgym/generators/qiskit_circuit.py Co-authored-by: Roberto Turrado Camblor <rturrado@gmail.com> * Apply suggestions * Implement suggestions * Implement suggestions * Happify mypy and pylint * Implement suggestions --------- Co-authored-by: Willem de kok <willem.dekok@tno.nl> Co-authored-by: Roberto Turrado Camblor <rturrado@gmail.com>
* Refactor * Add AgentMapperWrapper * Tests for AgentMapperWrapper * Drop support for python38 * Happify pylint * black & isort * Happify mypy * Update workflow * Test uv workflow * Bugfix workflow * test * bugfix * Dufferent mypy call * test * test * Change order * Add venv * Reset workflow * Update qgym/benchmarks/metrics/initial_mapping_metrics.py Co-authored-by: Willem de Kok <102517616+Willem-de-kok@users.noreply.github.com> * Update qgym/wrappers/initial_mapping.py Co-authored-by: Willem de Kok <102517616+Willem-de-kok@users.noreply.github.com> * Hapify linters * Isort * Update mypy workflow * Happify mypy * HAPPIFY MYPY --------- Co-authored-by: Willem de Kok <102517616+Willem-de-kok@users.noreply.github.com>
* Add get_interaction_circuit * First attempt swap adder * Add tests for swap instertion method * Add tests for routing wrappers * Replace qreg_to_int with qiskit Layout * Test uv for mypy action * version 312 * Workflow * UV pylint * Bugfix * No venv for uv * UV for pytest * Add python313 to compatibility * Use CPU wheel for torch * Remove 313 compaitibility * Style * Add wrapper templates * Style * fix test * fix black * fix test * Remove breakpoint() * Add support for python 313 * Use unsage index strategy * fix black * Finish routing metrics * Add tests * Add RoutingBenchmaker * Linters * Make Circuit and CircuitLike as benchmark input * Pylint * mypy? * mypy? * Happify mypy? * mypy? * mypy
* Add get_interaction_circuit * First attempt swap adder * Add tests for swap instertion method * Add tests for routing wrappers * Replace qreg_to_int with qiskit Layout * Test uv for mypy action * version 312 * Workflow * UV pylint * Bugfix * No venv for uv * UV for pytest * Add python313 to compatibility * Use CPU wheel for torch * Remove 313 compaitibility * Style * Add wrapper templates * Style * fix test * fix black * fix test * Remove breakpoint() * Add support for python 313 * Use unsage index strategy * fix black * Finish routing metrics * Add tests * Add RoutingBenchmaker * Linters * Make Circuit and CircuitLike as benchmark input * Pylint * mypy? * mypy? * Happify mypy? * mypy? * mypy * Add safe fixes * Happify ruff * pydocstyle * pylint * Fix mypy issues (numpy bug) * Happify MYPY * Update github actions * Happify ruff
* First attempt swap adder * Add tests for swap instertion method * Remove 313 compaitibility * Add support for python 313 * Add RoutingBenchmaker * Linters * Make Circuit and CircuitLike as benchmark input * Pylint * mypy? * Happify mypy? * mypy? * mypy * Add safe fixes * Happify ruff * pydocstyle * pylint * Fix mypy issues (numpy bug) * Happify MYPY * Update github actions * Happify ruff * format * tst * Update workflow * mypy? * mypy
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.
Great work!
Mainly found some spelling corrections. And some questions about a couple of choices.
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.
The supported python versions needs to be updated in the ReadMe
computing domain. It's main purpose is to easily create RL environments for the | ||
different passes of the OpenQL framework, by simply initializing an environment class. | ||
This abstraction of the environment allows RL developers to develop RL agents to improve | ||
the OpenQL framework, without requiring prior knowledge of OpenQL. |
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.
Do we still want to explicitly mention the OpenQL framework? Maybe we should leave that out...
@@ -131,8 +135,8 @@ def reset( | |||
Args: | |||
seed: Seed for the random number generator, should only be provided | |||
(optionally) on the first reset call, i.e., before any learning is done. | |||
circuit: Optional list of tuples of ints that the interaction gates via the | |||
qubits the gates are acting on. | |||
interaction_circuit: Optional 2D-Array of ints that the interaction 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.
quite hard-to-read docstring.
@runtime_checkable | ||
class RoutingMetric(Protocol): | ||
"""Protocol that a metric for qubit routing should follow.""" | ||
|
||
@abstractmethod | ||
def compute(self, input_circuit: CircuitLike, routed_circuit: CircuitLike) -> float: | ||
"""Compute the metric for the provided `input_circuit` and `routed_circuit`.""" | ||
|
||
|
||
class InteractionRatioLoss(RoutingMetric): | ||
"""The :class:`InteractionRatioLoss` class.""" | ||
|
||
def __init__(self, swap_penalty: SupportsInt = 3) -> None: | ||
"""Init of :class:`InteractionRatioLoss`. | ||
|
||
Args: | ||
swap_penalty: Number of gates to use to decompose the SWAP gate. Since a | ||
SWAP gate is often decomposed using 3 CNOT gates, the default is 3. | ||
""" | ||
self.swap_penalty = check_int(swap_penalty, "swap_penalty", l_bound=1) | ||
|
||
def compute(self, input_circuit: CircuitLike, routed_circuit: CircuitLike) -> float: | ||
"""Method to calculate the ratio of the input and output circuit. | ||
|
||
The ratio loss is defined by the number of 2 qubit gates in the `output_circuit` | ||
devided by the number of 2 qubit gates in the `input_circut`. A score of 1 is | ||
thus a perfect score and the lowest value that can be returned. | ||
|
||
Args: | ||
input_circuit: Input circuit before routing was performed. | ||
routed_circuit: Routed version of the input circuit. | ||
|
||
Returns: | ||
The routing solution quality ratio. | ||
""" | ||
input_n_iteractions = self.get_num_interactions(input_circuit) | ||
routed_n_iteractions = self.get_num_interactions(routed_circuit) | ||
try: | ||
return float(routed_n_iteractions / input_n_iteractions) | ||
except ZeroDivisionError: | ||
if not routed_n_iteractions: | ||
return 1.0 | ||
return float("inf") | ||
|
||
def get_num_interactions(self, circuit: CircuitLike) -> int: | ||
"""Get the number of interactions from the `circuit`. | ||
|
||
Args: | ||
circuit: Circuit to count the number of interactions from. | ||
|
||
Returns: | ||
Number of 2 qubit interactions, where each SWAP gate is counted | ||
`swap_penalty` times. | ||
""" | ||
circuit = Circuit(circuit) | ||
return sum( | ||
self.swap_penalty if gate.name == "swap" else 1 | ||
for gate in circuit.dag.two_qubit_ops() | ||
) | ||
|
||
|
||
class RoutingBenchmarker: | ||
"""The :class:`RoutingBenchmarker` class.""" | ||
|
||
def __init__( | ||
self, | ||
generator: Iterator[CircuitLike], | ||
metrics: Iterable[RoutingMetric], | ||
) -> None: | ||
"""Init of the :class:`RoutingBenchmarker` class. | ||
|
||
Args: | ||
generator: Circuit generator. Currently only the ``MaxCutQAOAGenerator`` is | ||
supported. | ||
metrics: Metrics to compute. | ||
""" | ||
self.generator = generator | ||
self.metrics = tuple(metrics) | ||
|
||
def run(self, router: Router, max_iter: int = 1000) -> BenchmarkResult: | ||
"""Run the benchmark. | ||
|
||
Args: | ||
router: Router to benchmark. | ||
max_iter: Maximum number of iterations to benchmark. | ||
|
||
Returns: | ||
:class:`~qgym.benchmarks.metrics.BenchmarkResult` containing the results | ||
from the benchmark. | ||
""" | ||
results: list[deque[float]] = [deque() for _ in self.metrics] | ||
for i, circuit in enumerate(self.generator, start=1): | ||
routed_circuit = router.compute_routing(circuit) | ||
for metric, result_que in zip(self.metrics, results): | ||
result_que.append(metric.compute(circuit, routed_circuit)) | ||
|
||
if i >= max_iter: | ||
break | ||
|
||
return BenchmarkResult(results) |
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.
I like the with a RoutingMetric class and any RoutingMetric inheriting from that class and the RoutingBenchmarker outputting based on a number of RoutingMetrics.
@@ -32,9 +36,11 @@ def __init__(self) -> None: | |||
self._decoding_dct: dict[int, str] = {} |
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 decoding_dct
and not decoding_dict
? Same holds for encoding_dct
furtheron in the file.
"""Insert the provided swap gates in the quantum circuit. | ||
|
||
Args: | ||
swaps_inserted: Swap gated to insert. Iterable of tuples (g_idx, q1, q2). |
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.
swaps_inserted: Swap gated to insert. Iterable of tuples (g_idx, q1, q2). | |
swaps_inserted: Swap gates to insert. Iterable of tuples (g_idx, q1, q2). |
): | ||
"""Wrap a trained stable baselines 3 agent. | ||
|
||
The agent shoul inherit from |
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.
The agent shoul inherit from | |
The agent should inherit from |
Args: | ||
agent: agent trained on the initial mapping environment. | ||
env: environment the agent was trained on. | ||
max_steps: maximum number steps the `agent` can take to compute the mapping. |
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.
max_steps: maximum number steps the `agent` can take to compute the mapping. | |
max_steps: maximum number of steps the `agent` can take to compute the mapping. |
"""Wrap any qiskit mapper (Layout algorithm). | ||
|
||
This wrapper ensures that the mapper becomes compatible with the qgym framework. | ||
This class wraps the qiskit mapper, such that it is compatible with the qgym |
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.
This class wraps the qiskit mapper, such that it is compatible with the qgym | |
This class wraps the qiskit mapper, such that it is compatible with the qgym |
qiskit_mapper = SabreLayout(coupling_map) | ||
mapper = QiskitMapperWrapper(qiskit_mapper) | ||
mapper.compute_mapping(circuit) | ||
|
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.
no assertions here?
This pull request contains following:
uv
and a precompiled cpu version oftorch
)