Skip to content

Commit

Permalink
Adding release and Improving docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillermoAbadLopez committed Oct 31, 2024
1 parent 73eeced commit 0ce9a57
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 12 deletions.
53 changes: 53 additions & 0 deletions docs/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,59 @@

[#816](https://github.com/qilimanjaro-tech/qililab/pull/816)

- Added routing algorithms to `qililab` in function of the platform connectivity. This is done passing `Qibo` own `Routers` and `Placers` classes,
and can be called from different points of the stack.

The most common way to route, will be automatically through `qililab.execute_circuit.execute()`, or also from `qililab.platform.execute/compile()`. Another way, would be doing the transpilation/routing directly from an instance of the Transpiler, with: `qililab.digital.circuit_transpiler.transpile/route_circuit()` (with this last one, you can route with a different topology from the platform one, if desired, defaults to platform)

Example:

````
```python
from qibo import gates
from qibo.models import Circuit
from qibo.transpiler.placer import ReverseTraversal, Trivial
from qibo.transpiler.router import Sabre
from qililab import build_platform
from qililab.circuit_transpiler import CircuitTranspiler

# Create circuit:
c = Circuit(5)
c.add(gates.CNOT(1, 0))

### From execute_circuit:
# With defaults (ReverseTraversal placer and Sabre routing):
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml", placer= Trivial, router = Sabre, routing_iterations: int = 10,)
# Changing the placer to Trivial, and changing the number of iterations:
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml",

### From the platform:
# Create platform:
platform = build_platform(runcard="<path_to_runcard>")
# With defaults (ReverseTraversal placer, Sabre routing)
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000)
# With non-defaults, and specifying the router with kwargs:
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer= Trivial, router = (Sabre, {"lookahead": 2}), routing_iterations: int = 20))
# With a router instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the platform's one
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer=Trivial, router=router)

### Using the transpiler directly:
### (If using the routing from this points of the stack, you can route with a different topology from the platform one)
# Create transpiler:
transpiler = CircuitTranspiler(platform)
# Default Transpilation (ReverseTraversal, Sabre and Platform connectivity):
routed_circ, final_layouts = transpiler.route_circuit([c])
# With Non-Default Trivial placer, specifying the kwargs, for the router, and different coupling_map:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=(Sabre, {"lookahead": 2}, coupling_map=<some_different_topology>))
# Or finally, Routing with a concrete Routing instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the specified in the Transpiler:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=router, coupling_map=<connectivity_to_use>)
```
````

[#821](https://github.com/qilimanjaro-tech/qililab/pull/821)

### Improvements

- Legacy linting and formatting tools such as pylint, flake8, isort, bandit, and black have been removed. These have been replaced with Ruff, a more efficient tool that handles both linting and formatting. All configuration settings have been consolidated into the `pyproject.toml` file, simplifying the project's configuration and maintenance. Integration config files like `pre-commit-config.yaml` and `.github/workflows/code_quality.yml` have been updated accordingly. Several rules from Ruff have also been implemented to improve code consistency and quality across the codebase. Additionally, the development dependencies in `dev-requirements.txt` have been updated to their latest versions, ensuring better compatibility and performance. [#813](https://github.com/qilimanjaro-tech/qililab/pull/813)
Expand Down
8 changes: 4 additions & 4 deletions src/qililab/digital/circuit_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def route(self, circuit: Circuit, iterations: int = 10) -> tuple[Circuit, dict[s
# Create platform:
platform = build_platform(runcard="<path_to_runcard>")
coupling_map = platform.chip.get_topology()
coupling_map = platform.digital_compilation_settings.topology
# Create transpiler:
transpiler = CircuitTranspiler(platform)
Expand Down Expand Up @@ -247,7 +247,7 @@ def _build_router(cls, router: Router | type[Router] | tuple[type[Router], dict]
router.middle_qubit = cls._highest_degree_node(connectivity)
else:
router.connectivity = connectivity
logger.warning("Substituting the router connectivity by the platform one.")
logger.warning("Substituting the router connectivity by the transpiler/platform one.")
return router

# If the router is a Router subclass, we instantiate it:
Expand Down Expand Up @@ -298,7 +298,7 @@ def _build_placer(
placer.middle_qubit = self._highest_degree_node(connectivity)
else:
placer.connectivity = connectivity
logger.warning("Substituting the placer connectivity by the platform one.")
logger.warning("Substituting the placer connectivity by the transpiler/platform one.")
return placer

# If the placer is a Placer subclass, we instantiate it:
Expand Down Expand Up @@ -334,7 +334,7 @@ def _check_ReverseTraversal_routing_connectivity(
# If the placer is a ReverseTraversal instance, we update the connectivity to the platform one:
if isinstance(placer, ReverseTraversal):
placer.routing_algorithm.connectivity = connectivity
logger.warning("Substituting the ReverseTraversal router connectivity, by the platform one.")
logger.warning("Substituting the ReverseTraversal router connectivity, by the transpiler/platform one.")
return placer, kwargs

# Else is placer is not an instance, we need to check the routing algorithm:
Expand Down
7 changes: 5 additions & 2 deletions src/qililab/digital/circuit_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ def route_circuit(
) -> tuple[Circuit, dict[str, int]]:
"""Routes the virtual/logical qubits of a circuit, to the chip's physical qubits.
**Examples:**
If we instantiate some ``Circuit``, ``Platform`` and ``CircuitTranspiler`` objects like:
Expand All @@ -148,7 +150,7 @@ def route_circuit(
# Create platform:
platform = build_platform(runcard="<path_to_runcard>")
coupling_map = platform.chip.get_topology()
coupling_map = platform.digital_compilation_settings.topology
# Create transpiler:
transpiler = CircuitTranspiler(platform)
Expand All @@ -168,7 +170,8 @@ def route_circuit(
Args:
circuit (Circuit): circuit to route.
coupling_map (list[tuple[int, int]], optional): coupling map of the chip. Defaults to the platform topology.
coupling_map (list[tuple[int, int]], optional): coupling map of the chip to route. This topology will be the one that rules,
which will overwrite any other in an instance of router or placer. Defaults to the platform topology.
placer (Placer | type[Placer] | tuple[type[Placer], dict], optional): `Placer` instance, or subclass `type[Placer]` to
use, with optionally, its kwargs dict (other than connectivity), both in a tuple. Defaults to `ReverseTraversal`.
router (Router | type[Router] | tuple[type[Router], dict], optional): `Router` instance, or subclass `type[Router]` to
Expand Down
12 changes: 6 additions & 6 deletions tests/digital/test_circuit_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,15 @@ def test_build_placer(self, mock_logger_warning, mock_check_reverse):
assert isinstance(placer, Trivial)
assert placer.connectivity == linear_topology
assert hasattr(placer, "routing_algorithm") == False
mock_logger_warning.assert_has_calls([call("Substituting the placer connectivity by the platform one.")])
mock_logger_warning.assert_has_calls([call("Substituting the placer connectivity by the transpiler/platform one.")])

star_placer_instance = StarConnectivityPlacer(star_topology, middle_qubit=2)
mock_logger_warning.reset_mock()
placer = self.circuit_router._build_placer(star_placer_instance, self.circuit_router.router, star_topology)
assert isinstance(placer, StarConnectivityPlacer)
assert placer.middle_qubit == 0
assert hasattr(placer, "routing_algorithm") == hasattr(placer, "connectivity") == False
mock_logger_warning.assert_has_calls([call("Substituting the placer connectivity by the platform one.")])
mock_logger_warning.assert_has_calls([call("Substituting the placer connectivity by the transpiler/platform one.")])

reverse_traversal_instance = ReverseTraversal(linear_topology, self.circuit_router.router)
placer = self.circuit_router._build_placer(reverse_traversal_instance, self.circuit_router.router, linear_topology)
Expand All @@ -260,7 +260,7 @@ def test_build_placer(self, mock_logger_warning, mock_check_reverse):
router = self.circuit_router._build_placer((placer_instance,placer_kwargs),self.circuit_router.router, linear_topology)
assert hasattr(router, "lookahead") == False
mock_logger_warning.assert_has_calls([call("Ignoring placer kwargs, as the placer is already an instance."),
call("Substituting the placer connectivity by the platform one.")])
call("Substituting the placer connectivity by the transpiler/platform one.")])

@patch("qililab.digital.circuit_router.logger.warning")
def test_build_router(self, mock_logger_warning):
Expand Down Expand Up @@ -293,7 +293,7 @@ def test_build_router(self, mock_logger_warning):
router = self.circuit_router._build_router(sabre_instance, linear_topology)
assert isinstance(router, Sabre)
assert router.connectivity == linear_topology
mock_logger_warning.assert_has_calls([call("Substituting the router connectivity by the platform one.")])
mock_logger_warning.assert_has_calls([call("Substituting the router connectivity by the transpiler/platform one.")])


star_router_instance = StarConnectivityRouter(star_topology)
Expand All @@ -302,7 +302,7 @@ def test_build_router(self, mock_logger_warning):
assert isinstance(router, StarConnectivityRouter)
assert router.middle_qubit == 0
assert hasattr(router, "connectivity") == False
mock_logger_warning.assert_has_calls([call("Substituting the router connectivity by the platform one.")])
mock_logger_warning.assert_has_calls([call("Substituting the router connectivity by the transpiler/platform one.")])

# Test Router instance, with kwargs:
sabre_instance = Sabre(linear_topology, lookahead=2)
Expand All @@ -311,7 +311,7 @@ def test_build_router(self, mock_logger_warning):
router = self.circuit_router._build_router((sabre_instance,router_kwargs), linear_topology)
assert router.lookahead == 2
mock_logger_warning.assert_has_calls([call("Ignoring router kwargs, as the router is already an instance."),
call("Substituting the router connectivity by the platform one.")])
call("Substituting the router connectivity by the transpiler/platform one.")])

def test_check_reverse_traversal_routing_connectivity(self):
"""Test the _check_ReverseTraversal_routing_connectivity method."""
Expand Down

0 comments on commit 0ce9a57

Please sign in to comment.