Skip to content

Commit

Permalink
Expand unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillermoAbadLopez committed Oct 29, 2024
1 parent 4263571 commit 8ccd3cb
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 3 deletions.
32 changes: 29 additions & 3 deletions src/qililab/digital/circuit_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,19 @@ def _if_star_algorithms_for_nonstar_connectivity(connectivity: nx.Graph, placer:
)

@staticmethod
def _build_router(router: Router | type[Router] | tuple[type[Router], dict], connectivity: nx.Graph) -> Router:
def _highest_degree_node(connectivity: nx.Graph) -> int:
"""Returns the node with the highest degree in the connectivity graph.
Args:
connectivity (nx.Graph): Chip connectivity.
Returns:
int: Node with the highest degree in the connectivity graph.
"""
return max(dict(connectivity.degree()).items(), key=lambda x: x[1])[0]

@classmethod
def _build_router(cls, router: Router | type[Router] | tuple[type[Router], dict], connectivity: nx.Graph) -> Router:
"""Build a `Router` instance, given the pass router in whatever format and the connectivity graph.
Args:
Expand All @@ -203,13 +215,20 @@ def _build_router(router: Router | type[Router] | tuple[type[Router], dict], con
if isinstance(router, Router):
if kwargs:
logger.warning("Ignoring router kwargs, as the router is already an instance.")
router.connectivity = connectivity
if isinstance(router, StarConnectivityRouter):
# For star-connectivity placers, we only care about which is the middle qubit (highest degree):
router.middle_qubit = cls._highest_degree_node(connectivity)
else:
router.connectivity = connectivity
logger.warning("Substituting the router connectivity by the platform one.")
return router

# If the router is a Router subclass, we instantiate it:
with contextlib.suppress(TypeError, ValueError):
if issubclass(router, Router):
if issubclass(router, StarConnectivityRouter):
# For star-connectivity placers, we only care about which is the middle qubit (highest degree):
kwargs["middle_qubit"] = cls._highest_degree_node(connectivity)
return router(connectivity, **kwargs)

raise TypeError(
Expand Down Expand Up @@ -247,13 +266,20 @@ def _build_placer(
if isinstance(placer, Placer):
if kwargs:
logger.warning("Ignoring placer kwargs, as the placer is already an instance.")
placer.connectivity = connectivity
if isinstance(placer, StarConnectivityPlacer):
# For star-connectivity placers, we only care about which is the middle qubit (highest degree):
placer.middle_qubit = self._highest_degree_node(connectivity)
else:
placer.connectivity = connectivity
logger.warning("Substituting the placer connectivity by the platform one.")
return placer

# If the placer is a Placer subclass, we instantiate it:
with contextlib.suppress(TypeError, ValueError):
if issubclass(placer, Placer):
if issubclass(placer, StarConnectivityPlacer):
# For star-connectivity placers, we only care about which is the middle qubit (highest degree):
kwargs["middle_qubit"] = self._highest_degree_node(connectivity)
return placer(connectivity, **kwargs)

raise TypeError(
Expand Down
131 changes: 131 additions & 0 deletions tests/digital/test_circuit_router.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from unittest.mock import call, patch
import pytest
import networkx as nx
Expand Down Expand Up @@ -155,3 +156,133 @@ def test_if_star_algorithms_for_nonstar_connectivity(self):
assert False == circ_router._if_star_algorithms_for_nonstar_connectivity(self.linear_topology, Trivial(), circ_router.router)
assert False == circ_router._if_star_algorithms_for_nonstar_connectivity(self.star_topology, Trivial(), StarConnectivityRouter())
assert False == circ_router._if_star_algorithms_for_nonstar_connectivity(self.star_topology, circ_router.placer, circ_router.router)

def test_highest_degree_node(self):
"""Test the _highest_degree_node method."""
# Test new edited linear topology
edited_linear_topology = nx.Graph(linear_connectivity)
edited_linear_topology.add_edges_from([(2,3),(2,4)])
assert self.circuit_router._highest_degree_node(edited_linear_topology) == 2

# Test the star topology with the 0 as central
assert self.circuit_router._highest_degree_node(self.star_topology) == 0

@patch("qililab.digital.circuit_router.CircuitRouter._check_ReverseTraversal_routing_connectivity")
def test_build_placer(self, mock_check_reverse):
"""Test the _build_placer method."""

# Test default placer (ReverseTraversal)
placer = self.circuit_router._build_placer(None, self.circuit_router.router, self.linear_topology)
assert isinstance(placer, ReverseTraversal)
assert (placer.connectivity, placer.routing_algorithm) == (self.linear_topology, self.circuit_router.router)

# Test Trivial placer
placer = self.circuit_router._build_placer(Trivial, self.circuit_router.router, self.linear_topology)
assert isinstance(placer, Trivial)
assert placer.connectivity == self.linear_topology
assert hasattr(placer, "routing_algorithm") == False

# Test StarConnectivityPlacer with kwargs
placer = self.circuit_router._build_placer((StarConnectivityPlacer, {"middle_qubit": 0}), self.circuit_router.router, self.star_topology)
assert isinstance(placer, StarConnectivityPlacer)
assert placer.middle_qubit == 0
assert hasattr(placer, "routing_algorithm") == hasattr(placer, "connectivity") == False

# Test ReverseTraversal with kwargs
mock_check_reverse.return_value = (ReverseTraversal, {"routing_algorithm": self.circuit_router.router})
placer = self.circuit_router._build_placer((ReverseTraversal, {"routing_algorithm": self.circuit_router.router}), self.circuit_router.router, self.linear_topology)
mock_check_reverse.assert_called_once_with(ReverseTraversal, {"routing_algorithm": self.circuit_router.router}, self.linear_topology, self.circuit_router.router)
assert isinstance(placer, ReverseTraversal)
assert (placer.connectivity, placer.routing_algorithm) == (self.linear_topology, self.circuit_router.router)

# Test invalid placer type
with pytest.raises(TypeError, match="`placer` arg"):
self.circuit_router._build_placer("invalid_placer", self.circuit_router.router, self.linear_topology)

# Test Placer instance, instead than subclass:
trivial_placer_instance = Trivial(self.linear_topology)
placer = self.circuit_router._build_placer(trivial_placer_instance, self.circuit_router.router, self.linear_topology)
assert isinstance(placer, Trivial)
assert placer.connectivity == self.linear_topology
assert hasattr(placer, "routing_algorithm") == False

star_placer_instance = StarConnectivityPlacer(self.star_topology, middle_qubit=2)
placer = self.circuit_router._build_placer(star_placer_instance, self.circuit_router.router, self.star_topology)
assert isinstance(placer, StarConnectivityPlacer)
assert placer.middle_qubit == 0
assert hasattr(placer, "routing_algorithm") == hasattr(placer, "connectivity") == False

reverse_traversal_instance = ReverseTraversal(self.linear_topology, self.circuit_router.router)
placer = self.circuit_router._build_placer(reverse_traversal_instance, self.circuit_router.router, self.linear_topology)
assert isinstance(placer, ReverseTraversal)
assert (placer.connectivity, placer.routing_algorithm) == (self.linear_topology, self.circuit_router.router)

def test_build_router(self):
"""Test the _build_router method."""

# Test default router (Sabre)
router = self.circuit_router._build_router(None, self.linear_topology)
assert isinstance(router, Sabre)
assert router.connectivity == self.linear_topology

# Test StarConnectivityRouter
router = self.circuit_router._build_router(StarConnectivityRouter, self.star_topology)
assert isinstance(router, StarConnectivityRouter)
assert router.middle_qubit == 0
assert hasattr(router, "connectivity") == False

# Test Sabre router with kwargs
router = self.circuit_router._build_router((Sabre, {"lookahead": 2}), self.linear_topology)
assert isinstance(router, Sabre)
assert router.connectivity == self.linear_topology
assert router.lookahead == 2

# Test invalid router type
with pytest.raises(TypeError, match="`router` arg"):
self.circuit_router._build_router("invalid_router", self.linear_topology)

# Test Router instance, instead of subclass
sabre_instance = Sabre(self.linear_topology)
router = self.circuit_router._build_router(sabre_instance, self.linear_topology)
assert isinstance(router, Sabre)
assert router.connectivity == self.linear_topology

star_router_instance = StarConnectivityRouter(self.star_topology)
router = self.circuit_router._build_router(star_router_instance, self.star_topology)
assert isinstance(router, StarConnectivityRouter)
assert router.middle_qubit == 0
assert hasattr(router, "connectivity") == False

def test_check_reverse_traversal_routing_connectivity(self):
"""Test the _check_ReverseTraversal_routing_connectivity method."""
# Test for a linear topology
og_placer = ReverseTraversal
og_kwargs = {"routing_algorithm": Sabre}
router = Sabre

# Check with placer and routing algorithm both subclasses
placer, kwargs = self.circuit_router._check_ReverseTraversal_routing_connectivity(og_placer, og_kwargs, self.linear_topology, router)
assert (placer, kwargs) == (og_placer, og_kwargs)

# Test for a weird router of the reversal
og_kwargs = {"routing_algorithm": int, "lookahead": 2}
with pytest.raises(TypeError, match=re.escape("`routing_algorithm` `Placer` kwarg (<class 'int'>) must be a `Router` subclass or instance, in `execute()`, `compile()`, `transpile_circuit()` or `route_circuit()`.")):
self.circuit_router._check_ReverseTraversal_routing_connectivity(og_placer, og_kwargs, self.star_topology, router)

# Test that the routing_algorithm get automatically inserted:
og_kwargs = {"lookahead": 2}
placer, kwargs = self.circuit_router._check_ReverseTraversal_routing_connectivity(og_placer, og_kwargs, self.linear_topology, router)
assert (placer, kwargs) == (og_placer, og_kwargs | {"routing_algorithm": router})

# Test instance of Router, change to chips topology:
og_kwargs = {"routing_algorithm": Sabre(connectivity=None)}
placer, kwargs = self.circuit_router._check_ReverseTraversal_routing_connectivity(og_placer, og_kwargs, self.linear_topology, router)
og_kwargs["routing_algorithm"].connectivity = self.linear_topology
assert (placer, kwargs) == (og_placer, og_kwargs)

# Test subclass of Router, change to chips topology:
og_kwargs = {"routing_algorithm": Sabre(connectivity=None)}
og_placer = ReverseTraversal(connectivity=self.linear_topology, routing_algorithm=og_kwargs["routing_algorithm"])
placer, kwargs = self.circuit_router._check_ReverseTraversal_routing_connectivity(og_placer, og_kwargs, self.linear_topology, router)
assert og_placer.routing_algorithm.connectivity == self.linear_topology
assert (placer, kwargs) == (og_placer, og_kwargs)

0 comments on commit 8ccd3cb

Please sign in to comment.