Skip to content
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

Allow different partitions #578

Merged
merged 16 commits into from
Oct 14, 2024
155 changes: 143 additions & 12 deletions pacman/model/routing_info/routing_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Dict, Iterator, Optional, Tuple, TYPE_CHECKING
from collections import defaultdict
from typing import Dict, Iterator, Optional, Iterable, Set, TYPE_CHECKING
from deprecated import deprecated
from pacman.exceptions import PacmanAlreadyExistsException
if TYPE_CHECKING:
from .vertex_routing_info import VertexRoutingInfo
Expand All @@ -29,8 +31,8 @@ class RoutingInfo(object):
def __init__(self) -> None:
# Partition information indexed by edge pre-vertex and partition ID
# name
self._info: Dict[
Tuple[AbstractVertex, str], VertexRoutingInfo] = dict()
self._info: Dict[AbstractVertex,
Dict[str, VertexRoutingInfo]] = defaultdict(dict)

def add_routing_info(self, info: VertexRoutingInfo):
"""
Expand All @@ -41,46 +43,175 @@ def add_routing_info(self, info: VertexRoutingInfo):
:raise PacmanAlreadyExistsException:
If the partition is already in the set of edges
"""
key = (info.vertex, info.partition_id)
if key in self._info:
if (info.vertex in self._info and
info.partition_id in self._info[info.vertex]):
raise PacmanAlreadyExistsException(
"Routing information", str(info))

self._info[key] = info
self._info[info.vertex][info.partition_id] = info

@deprecated(reason="This method is unsafe, since it doesn't determine "
"whether the info is missing because there is no "
"outgoing edge, or if the outgoing edge is in another "
"partition and the name is wrong. "
"Use a combination of "
"get_info_from, "
"get_partitions_from, "
"has_info_from, "
"or get_single_info_from")
def get_routing_info_from_pre_vertex(
self, vertex: AbstractVertex,
partition_id: str) -> Optional[VertexRoutingInfo]:
"""
Get routing information for a given partition_id from a vertex.

:param AbstractVertex vertex: The vertex to search for
:param str partition_id:
The ID of the partition for which to get the routing information
:rtype: VertexRoutingInfo or None
"""
return self._info[vertex].get(partition_id)

def get_info_from(
self, vertex: AbstractVertex,
partition_id: str) -> VertexRoutingInfo:
"""
Get routing information for a given partition_id from a vertex.

:param AbstractVertex vertex: The vertex to search for
:param str partition_id:
The ID of the partition for which to get the routing information
:rtype: VertexRoutingInfo
:raise KeyError:
If the vertex/partition_id combination is not in the routing
information
"""
return self._info.get((vertex, partition_id))
return self._info[vertex][partition_id]

@deprecated(reason="This method is unsafe, since it doesn't determine "
"whether the info is missing because there is no "
"outgoing edge, or if the outgoing edge is in another "
"partition and the name is wrong. "
"Use a combination of "
"get_key_from, "
"get_partitions_from, "
"has_info_from, "
"or get_single_key_from")
def get_first_key_from_pre_vertex(
self, vertex: AbstractVertex, partition_id: str) -> Optional[int]:
"""
Get the first key for the partition starting at a vertex.

:param AbstractVertex vertex: The vertex which the partition starts at
:param str partition_id:
The ID of the partition for which to get the routing information
:return: The routing key of the partition
:rtype: int or None
"""
if vertex not in self._info:
return None
info = self._info[vertex]
if partition_id not in info:
return None
return info[partition_id].key

def get_key_from(
self, vertex: AbstractVertex, partition_id: str) -> int:
"""
Get the first key for the partition starting at a vertex.

:param AbstractVertex vertex: The vertex which the partition starts at
:param str partition_id:
The ID of the partition for which to get the routing information
:return: The routing key of the partition
:rtype: int
:raise KeyError:
If the vertex/partition_id combination is not in the routing
information
"""
return self._info[vertex][partition_id].key

def get_partitions_from(
self, vertex: AbstractVertex) -> Iterable[str]:
"""
Get the outgoing partitions from a vertex.

:param AbstractVertex vertex: The vertex to search for
"""
return self._info[vertex].keys()

def has_info_from(
self, vertex: AbstractVertex, partition_id: str) -> bool:
"""
Check if there is routing information for a given vertex.

:param AbstractVertex vertex: The vertex to search for
:param str partition_id:
The ID of the partition for which to get the routing information
:rtype: bool
"""
if vertex not in self._info:
return False
info = self._info[vertex]
return partition_id in info

def check_info_from(
Christian-B marked this conversation as resolved.
Show resolved Hide resolved
self, vertex: AbstractVertex,
allowed_partition_ids: Set[str]):
"""
Check that the partition ids for a vertex are in the allowed set.

:param AbstractVertex vertex: The vertex to search for
:param set[str] allowed_partition_ids: The allowed partition ids
:raise KeyError: If the vertex has an unknown partition ID
"""
if vertex not in self._info:
return
info = self._info[vertex]
for partition_id in info:
if partition_id not in allowed_partition_ids:
raise KeyError(
f"Vertex {vertex} has unknown partition ID {partition_id}")

def get_single_info_from(
self, vertex: AbstractVertex) -> Optional[VertexRoutingInfo]:
"""
Get routing information for a given vertex. Fails if the vertex has
more than one outgoing partition.

:param AbstractVertex vertex: The vertex to search for
:rtype: VertexRoutingInfo or None
:raise KeyError: If the vertex has more than one outgoing partition
"""
if vertex not in self._info:
return None
info = self._info[vertex]
if len(info) != 1:
raise KeyError(
f"Vertex {vertex} has more than one outgoing partition")
return next(iter(info.values()))

def get_single_key_from(
self, vertex: AbstractVertex) -> Optional[int]:
"""
Get the first key for the partition starting at a vertex. Fails if
the vertex has more than one outgoing partition.

:param AbstractVertex vertex: The vertex which the partition starts at
:rtype: int or None
:raise KeyError: If the vertex has more than one outgoing partition
"""
key = (vertex, partition_id)
if key in self._info:
return self._info[key].key
return None
info = self.get_single_info_from(vertex)
if info is None:
return None
return info.key

def __iter__(self) -> Iterator[VertexRoutingInfo]:
"""
Gets an iterator for the routing information.

:return: a iterator of routing information
"""
return iter(self._info.values())
for vertex_info in self._info.values():
for info in vertex_info.values():
yield info
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,13 @@ def validate_routes(routing_tables: MulticastRoutingTables):
if isinstance(m_vertex, AbstractVirtual):
continue
placement = PacmanDataView.get_placement_of_vertex(m_vertex)
r_info = routing_infos.get_routing_info_from_pre_vertex(
r_info = routing_infos.get_info_from(
m_vertex, partition.identifier)

# search for these destinations
if r_info:
_search_route(
placement, destinations[m_vertex], r_info.key_and_mask,
routing_tables, m_vertex.vertex_slice.n_atoms)
_search_route(
placement, destinations[m_vertex], r_info.key_and_mask,
routing_tables, m_vertex.vertex_slice.n_atoms)


def _search_route(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,8 @@ def __create_routing_table(
sources_by_key_mask: Dict[BaseKeyAndMask,
Tuple[AbstractVertex, str]] = dict()
for source_vertex, partition_id in partitions_in_table:
r_info = routing_infos.get_routing_info_from_pre_vertex(
r_info = routing_infos.get_info_from(
source_vertex, partition_id)
# Should be there; skip if not
if r_info is None:
continue
entry = partitions_in_table[source_vertex, partition_id]
if r_info.key_and_mask in sources_by_key_mask:
if (sources_by_key_mask[r_info.key_and_mask]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from spinn_utilities.progress_bar import ProgressBar
from spinn_machine import MulticastRoutingEntry, RoutingEntry
from pacman.data import PacmanDataView
from pacman.exceptions import PacmanRoutingException
from pacman.model.routing_tables import (
UnCompressedMulticastRoutingTable, MulticastRoutingTables)
from pacman.model.graphs.application import ApplicationVertex
Expand Down Expand Up @@ -70,10 +69,8 @@ def __create_routing_table(
iterator = _IteratorWithNext(partitions_in_table.items())
while iterator.has_next:
(vertex, part_id), entry = iterator.pop()
r_info = routing_info.get_routing_info_from_pre_vertex(vertex, part_id)
if r_info is None:
raise PacmanRoutingException(
f"Missing Routing information for {vertex}, {part_id}")
r_info = routing_info.get_info_from(
vertex, part_id)

if r_info.key_and_mask in sources_by_key_mask:
if (sources_by_key_mask[r_info.key_and_mask] != (vertex, part_id)):
Expand Down Expand Up @@ -102,7 +99,7 @@ def __create_routing_table(
continue

# This has to be AppVertexRoutingInfo!
app_r_info = routing_info.get_routing_info_from_pre_vertex(
app_r_info = routing_info.get_info_from(
vertex.app_vertex, part_id)
assert isinstance(app_r_info, AppVertexRoutingInfo)

Expand All @@ -112,7 +109,7 @@ def __create_routing_table(
while __match(iterator, vertex, part_id, r_info, entry, routing_info,
app_r_info):
(vertex, part_id), entry = iterator.pop()
r_info = routing_info.get_routing_info_from_pre_vertex(
r_info = routing_info.get_info_from(
vertex, part_id)
if r_info is not None:
assert isinstance(r_info, MachineVertexRoutingInfo)
Expand All @@ -139,11 +136,8 @@ def __match(
return False
if __mask_has_holes(r_info.mask):
return False
next_r_info = routing_info.get_routing_info_from_pre_vertex(
next_r_info = routing_info.get_info_from(
next_vertex, next_part_id)
if next_r_info is None:
raise KeyError(
f"No routing info found for {next_vertex}, {next_part_id}")
if next_r_info.index != r_info.index + 1:
return False
app_src = vertex.app_vertex
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ include_package_data = True
install_requires =
jsonschema
typing_extensions
deprecated
SpiNNUtilities == 1!7.3.1
SpiNNMachine == 1!7.3.1

Expand All @@ -73,6 +74,7 @@ test =
pylint
testfixtures
types-jsonschema
types-Deprecated
# How to make
# [Reports]
# draw_placements=True
Expand Down
Loading
Loading