Source code for pacman.model.routing_info.fixed_machine_vertex_routing_info
# Copyright (c) 2026 The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from typing import Optional, Tuple, TYPE_CHECKING
from spinn_utilities.overrides import overrides
from pacman.utilities.constants import BITS_IN_KEY
from pacman.exceptions import IrregularFixedMaskException
from pacman.utilities.utility_calls import can_shift, first_one, last_one
from .machine_vertex_routing_info import MachineVertexRoutingInfo
if TYPE_CHECKING:
from .base_key_and_mask import BaseKeyAndMask
from pacman.model.graphs.machine import MachineVertex
class FixedMachineVertexRoutingInfo(MachineVertexRoutingInfo):
"""
Associates a machine vertex and partition identifier to its routing
information (keys and masks).
This is used then the Vertex has fixed masks
even if they are the global ones.
"""
__slots__ = (
# Records this has app keys overlap
"__app_key_overlap",
"__app_key",
"__global_app_mask",
"__global_machine_mask"
)
def __init__(self, key_and_mask: BaseKeyAndMask, partition_id: str,
machine_vertex: MachineVertex, index: int,
app_key_and_mask: BaseKeyAndMask):
"""
:param key_and_mask:
The key and mask associated to the partition
:param partition_id: The partition to set the keys for
:param machine_vertex: The vertex to set the keys for
:param index: The index of the machine vertex
:param app_key_and_mask: The application key and mask
"""
super().__init__(key_and_mask, partition_id, machine_vertex, index,
app_key_and_mask.mask)
self.__app_key_overlap = False
self.__app_key = app_key_and_mask.key
self.__global_app_mask: Optional[int] = None
self.__global_machine_mask: Optional[int] = None
if not can_shift(app_key_and_mask.mask):
raise IrregularFixedMaskException(
f"{machine_vertex} has a fixed app_mask "
f"{hex(app_key_and_mask.mask)} which is not shiftable")
@property
@overrides(MachineVertexRoutingInfo.has_global_app_masks)
def has_global_app_masks(self) -> bool:
# The allocator will try to use the fixed masks as the global ones
return self.app_mask == self.global_app_mask
@property
@overrides(MachineVertexRoutingInfo.has_global_machine_masks)
def has_global_machine_masks(self) -> bool:
# The allocator will try to use the fixed masks as the global ones
return self.machine_mask == self.global_machine_mask
@property
@overrides(MachineVertexRoutingInfo.has_app_keys_overlap)
def has_app_keys_overlap(self) -> bool:
return self.__app_key_overlap
[docs]
@overrides(MachineVertexRoutingInfo.set_app_keys_overlap)
def set_app_keys_overlap(self) -> None:
self.__app_key_overlap = True
@property
@overrides(MachineVertexRoutingInfo.has_fixed_keys)
def has_fixed_keys(self) -> bool:
return True
[docs]
def get_atom_bits_needed_range(self) -> Tuple[int, int]:
"""
The range of atom bit values that this info can support.
Based on the Application and Machine keys it may be able to alter the
Application Mask without changing now results.
The number of atom bits will be large enough
to not blank out any ones in the application key
but also small enough to blank out the machine index.
(The part of the Machine key that are not also application key)
:return: Smallest and largest application zone supportable
"""
# If app and machine the same allow the split anywhere
if (self.machine_mask == self.app_mask and
self.key == self.__app_key):
return 0, BITS_IN_KEY - self.machine_shift
last_app_one = last_one(self.__app_key)
machine_index_bit = self.key - self.__app_key
first_machine_one = first_one(machine_index_bit)
if first_machine_one == -1:
return last_app_one + 1, BITS_IN_KEY
else:
return last_app_one + 1, first_machine_one
[docs]
@overrides(MachineVertexRoutingInfo.set_global_masks)
def set_global_masks(self, app_mask: int, machine_mask: int) -> None:
self.__global_app_mask = app_mask
self.__global_machine_mask = machine_mask
@property
@overrides(MachineVertexRoutingInfo.global_app_mask)
def global_app_mask(self) -> int:
if self.__global_app_mask is None:
raise IrregularFixedMaskException("No global app mask set")
return self.__global_app_mask
@property
@overrides(MachineVertexRoutingInfo.global_machine_mask)
def global_machine_mask(self) -> int:
if self.__global_machine_mask is None:
raise IrregularFixedMaskException("No global machine mask set")
return self.__global_machine_mask