Source code for pacman.model.graphs.common.slice
# Copyright (c) 2014 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 Any, Tuple, Union
import numpy
from numpy.typing import NDArray
from pacman.exceptions import PacmanValueError, PacmanTypeError
class Slice(object):
"""
Represents a simple single-dimensional slice of a vertex.
.. note::
Multi-dimensional slices are supported by :py:class:`MDSlice`.
"""
__slots__ = ("_lo_atom", "_n_atoms")
def __init__(self, lo_atom: int, hi_atom: int):
"""
:param int lo_atom: Index of the lowest atom to represent.
:param int hi_atom: Index of the highest atom to represent.
:raises PacmanTypeError: If non-integer arguments are used.
:raises PacmanValueError: If the bounds of the slice are invalid.
"""
if not isinstance(lo_atom, int):
raise PacmanTypeError("lo_atom needs to be a int")
if not isinstance(hi_atom, int):
raise PacmanTypeError("hi_atom needs to be a int")
if lo_atom < 0:
raise PacmanValueError('lo_atom < 0')
if hi_atom < lo_atom:
raise PacmanValueError(
f'hi_atom {hi_atom:d} < lo_atom {lo_atom:d}')
self._lo_atom = lo_atom
# Number of atoms represented by this slice
self._n_atoms = hi_atom - lo_atom + 1
@property
def lo_atom(self) -> int:
"""
The lowest atom represented in the slice.
:rtype: int
"""
return self._lo_atom
@property
def hi_atom(self) -> int:
"""
The highest atom represented in the slice.
.. note::
Use of this method is *not* recommended.
It fails for multi-dimensional slices and may be removed
:rtype: int
"""
return self._lo_atom + self._n_atoms - 1
@property
def n_atoms(self) -> int:
"""
The number of atoms represented by the slice.
:rtype: int
"""
return self._n_atoms
@property
def shape(self) -> Tuple[int, ...]:
"""
The shape of the atoms over multiple dimensions.
By default the shape will be 1-dimensional.
:rtype: tuple(int,...)
"""
return (self._n_atoms, )
@property
def start(self) -> Tuple[int, ...]:
"""
The start coordinates of the slice.
By default this will be `lo_atom` in 1 dimension.
:rtype: tuple(int,...)
"""
return (self._lo_atom, )
@property
def as_slice(self) -> slice:
"""
Converts the Slice to a standard slice object *if possible.*
.. note::
Use of this method is *not* recommended.
It fails for multi-dimensional slices and may be removed.
:return: a standard built-in slice object
:rtype: slice
:raises NotImplementedError: If called on a multi-dimensional slice
"""
# slice for accessing arrays of values
return slice(self._lo_atom, self._lo_atom + self._n_atoms)
[docs]
def get_slice(self, n: int) -> slice:
"""
Get a slice in the `n`'Th dimension.
:param int n: Must be 0
:type: slice
"""
if n == 0:
return slice(self._lo_atom, self._lo_atom + self._n_atoms)
raise IndexError(f"{n} is invalid for a 1 dimension Slice ")
@property
def dimension(self) -> Tuple[slice, ...]:
"""
Get directions or edges as slices for every dimension
This is the width and if available height, depth, etc., of the
Slice/Grid as represented as slices form the origin along in that
direction.
:rtype: tuple(slice, ...)
"""
return (slice(self._lo_atom, self._lo_atom + self._n_atoms), )
@property
def end(self) -> Tuple[int, ...]:
"""
The end positions of the slice in each dimension
:rtype: tuple(int, ...)
"""
return (self._lo_atom + self._n_atoms, )
[docs]
def get_ids_as_slice_or_list(self) -> Union[slice, numpy.ndarray]:
"""
Returns the IDs as a built-in slice if possible,
otherwise as a list of IDs.
:return: a slice or list of IDs
:rtype: slice or list(int)
"""
return slice(self._lo_atom, self._lo_atom + self._n_atoms)
[docs]
def get_raster_ids(self) -> NDArray[numpy.integer]:
"""
Get the IDs of the atoms in the slice as they would appear in a
"raster scan" of the atoms over the whole shape.
:return: A list of the global raster IDs of the atoms in this slice
:rtype: ~numpy.ndarray
"""
return numpy.array(range(self._lo_atom, self._lo_atom + self._n_atoms))
def __str__(self) -> str:
return (f"({self.lo_atom}:{self.hi_atom})")
def __eq__(self, other: Any) -> bool:
if not isinstance(other, Slice):
return False
if self._lo_atom != other.lo_atom:
return False
# These checks are mainly to comparing to an extended slice
if self.shape != other.shape:
return False
if self.start != other.start:
return False
return self._n_atoms == other.n_atoms
def __hash__(self) -> int:
# Slices will generally only be hashed in sets for the same Vertex
return self._lo_atom
[docs]
@classmethod
def from_string(cls, as_str: str) -> Slice:
"""
Convert the string form of a :py:class:`Slice` into an object instance.
:param str as_str: The string to parse
:rtype: Slice
"""
if as_str[0] != "(":
raise NotImplementedError("Please use MDSlice method")
parts = as_str[1:-1].split(":")
lo_atom = int(parts[0])
hi_atom = int(parts[1])
return Slice(lo_atom, hi_atom)
[docs]
def get_relative_indices(self, app_vertex_indices: NDArray[numpy.integer]
) -> NDArray[numpy.integer]:
"""
Convert from raster indices to slice-level indices.
Note that no checking is done on the given indices; they should be
within this slice!
:param numpy.ndarray app_vertex_indices:
The raster application vertex indices to convert
:return: The local core-level indices relative to this slice
"""
return app_vertex_indices - self._lo_atom
[docs]
def get_raster_indices(self, relative_indices: NDArray[numpy.integer]
) -> NDArray[numpy.integer]:
"""
Convert from slice-level indices to raster indices.
Note that no checking is done on the given indices; they should be
within this slice!
:param numpy.ndarray relative_indices:
The local core-level indices relative to this slice
:return: The raster application vertex indices
"""
return relative_indices + self._lo_atom