Skip to content

Commit

Permalink
Merge pull request #578 from SpiNNakerManchester/allow_different_part…
Browse files Browse the repository at this point in the history
…itions

Allow different partitions
  • Loading branch information
rowleya authored Oct 14, 2024
2 parents 0383253 + 210d8e9 commit 0195977
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 48 deletions.
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(
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

0 comments on commit 0195977

Please sign in to comment.