Skip to content

Commit

Permalink
Merge 2c8bd85 into c6dd605
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian-B committed Jul 15, 2019
2 parents c6dd605 + 2c8bd85 commit 15fd736
Show file tree
Hide file tree
Showing 9 changed files with 708 additions and 28 deletions.
70 changes: 70 additions & 0 deletions spinn_machine/full_wrap_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,76 @@ def get_global_xy(self, local_x, local_y, ethernet_x, ethernet_y):
global_y = (local_y + ethernet_y) % self._height
return global_x, global_y

@overrides(Machine.shortest_path_length)
def shortest_path_length(self, source, destination):
# Aliases for convenience
w, h = self._width, self._height

x_up = (destination[0] - source[0]) % w
x_down = x_up - w
y_right = (destination[1] - source[1]) % h
y_left = y_right - h

# Both possitve so greater
length = x_up if x_up > y_right else y_right

# negative x possitive y so sum of abs
negative_x = y_right - x_down
if negative_x < length:
length = negative_x

# possitive x negative Y so sum of abs
negative_y = x_up - y_left
if negative_y < length:
length = negative_y

# both negative so abs smaller (farthest from zero)
if x_down > y_left:
negative_xy = - y_left
else:
negative_xy = - x_down
if negative_xy < length:
return negative_xy
else:
return length

def shortest_path(self, source, destination):
# Aliases for convenience
w, h = self._width, self._height

x_up = (destination[0] - source[0]) % w
x_down = x_up - w
y_right = (destination[1] - source[1]) % h
y_left = y_right - h

# Both possitve so greater
length = x_up if x_up > y_right else y_right
dx = x_up
dy = y_right

# negative x possitive y so sum of abs
negative_x = y_right - x_down
if negative_x < length:
length = negative_x
dx = x_down

# possitive x negative Y so sum of abs
negative_y = x_up - y_left
if negative_y < length:
length = negative_y
dx = x_up
dy = y_left

# both negative so abs smaller (farthest from zero)
if x_down > y_left:
negative_xy = - y_left
else:
negative_xy = - x_down
if negative_xy < length:
return self._minimize_vector(x_down, y_left)
else:
return self._minimize_vector(dx, dy)

@property
@overrides(Machine.wrap)
def wrap(self):
Expand Down
60 changes: 60 additions & 0 deletions spinn_machine/horizontal_wrap_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,66 @@ def get_global_xy(self, local_x, local_y, ethernet_x, ethernet_y):
global_y = local_y + ethernet_y
return global_x, global_y

@overrides(Machine.shortest_path_length)
def shortest_path_length(self, source, destination):
# Aliases for convenience
w = self._width

x_right = (destination[0] - source[0]) % w
x_left = x_right - w
y = destination[1] - source[1]

if y > 0:
# Positive (x_right) + positive(y) use greater
if x_right > y:
len_right = x_right
else:
len_right = y
# Negative (x_left) and positive(y) sum of abs
len_left = y - x_left
else:
# Positive (x_right) + negative(y) use sum of abs
len_right = x_right - y
# Negative (x_left) + negative(y) use greater abs
if x_left > y:
len_left = - y
else:
len_left = - x_left
if len_right < len_left:
return len_right
else:
return len_left

@overrides(Machine.shortest_path)
def shortest_path(self, source, destination):
# Aliases for convenience
w = self._width

x_right = (destination[0] - source[0]) % w
x_left = x_right - w
y = destination[1] - source[1]

if y > 0:
# Positive (x_right) + positive(y) use greater
if x_right > y:
len_right = x_right
else:
len_right = y
# Negative (x_left) and positive(y) sum of abs
len_left = y - x_left
else:
# Positive (x_right) + negative(y) use sum of abs
len_right = x_right - y
# Negative (x_left) + negative(y) use greater abs
if x_left > y:
len_left = - y
else:
len_left = - x_left
if len_right < len_left:
return self._minimize_vector(x_right, y)
else:
return self._minimize_vector(x_left, y)

@property
@overrides(Machine.wrap)
def wrap(self):
Expand Down
8 changes: 4 additions & 4 deletions spinn_machine/json_machine.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
try:
from collections.abc import defaultdict, namedtuple, OrderedDict
except ImportError:
from collections import defaultdict, namedtuple, OrderedDict
import logging

from .chip import Chip
from .processor import Processor
from .router import Router
from .sdram import SDRAM
from .link import Link
try:
from collections.abc import defaultdict, namedtuple, OrderedDict
except ImportError:
from collections import defaultdict, namedtuple, OrderedDict
import json
from .machine_factory import machine_from_size

Expand Down
101 changes: 101 additions & 0 deletions spinn_machine/machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,69 @@ def get_global_xy(self, local_x, local_y, ethernet_x, ethernet_y):
:return: global (x,y) coordinates of the chip
"""

@abstractmethod
def shortest_path_length(self, source, destination):
"""
Get the mathematical length of a shortest path from source to
destination
This method does not check if the chips and links it assumes to take
actually exist.
For example long paths along a none wrapping edge may well travel
through the missing area.
This method does take wrap-arounds into consideration as applicable.
From https://github.com/project-rig/rig/blob/master/rig/geometry.py
Described in http://jhnet.co.uk/articles/torus_paths
On full wrap-around machines (before minization) the vectors can have
any of the 4 combinations of possitive and negative x and y
The possitive one is: destination - source % dimension
The negative one is: possitive - dimension
If source is less than dimension the negative one is the wrap around
If destination is greater than source the possitive one wraps
One no wrap or part wrap boards the x/y that does not wrap is just
destination - source
The length of vectors where both x and y have the same sign will be
max(abs(x), abs(y)) As the z direction can be used in minization
The length of vectors where x and y have opposite signs will be
abs(x) and abs(y) as these are alread minimum so z is not used.
GIGO: This method does not check if input parameters make sense,
:param source: (x,y) coordinates of the source chip
:type source: (int, int)
:param destination: (x,y) coordinates of the destination chip
:return: The distantance in steps
"""

@abstractmethod
def shortest_path(self, source, destination):
"""
Get a mathematical shortest path from source to destination
This method does not check if the chips and links it assumes to take
actually exist.
For example long paths along a none wrapping edge may well travel
through the missing area.
This method does take wrap-arounds into consideration as applicable.
From https://github.com/project-rig/rig/blob/master/rig/geometry.py
Described in http://jhnet.co.uk/articles/torus_paths
Use the same algorithm as shortest_path_length
using the best x, y pair as minimize(x, y, 0)
:param source: (x,y) coordinates of the source chip
:type source: (int, int)
:param destination: (x,y) coordinates of the destination chip
:return:
"""

def validate(self):
"""
Validates the machine and raises an exception in unexpected conditions.
Expand Down Expand Up @@ -846,6 +909,44 @@ def one_way_links(self):
link.destination_x, link.destination_y, back):
yield chip.x, chip.y, out

def _minimize_vector(self, x, y):
"""
Minimizes an x, y, 0 vector.
When vectors are minimised, (1,1,1) is added or subtracted from them.
This process does not change the range of numbers in the vector.
When a vector is minimal,
it is easy to see that the range of numbers gives the
magnitude since there are at most two non-zero numbers (with opposite
signs) and the sum of their magnitudes will also be their range.
This can be farther optimised with then knowledge that z is always 0
:param x:
:param y:
:return: (x, y, z) vector
"""
if x > 0:
if y > 0:
# delta is the smaller of x or y
if x > y:
return (x - y, 0, -y)
else:
return (0, y - x, -x)
else:
# two non-zero numbers (with opposite signs)
return (x, y, 0)
else:
if y > 0:
# two non-zero numbers (with opposite signs)
return (x, y, 0)
else:
# delta is the greater (nearest to zero) of x or y
if x > y:
return (0, y - x, -x)
else:
return (x - y, 0, -y)

@property
def virtual_chips(self):
return itervalues(self._virtual_chips)
Expand Down
Loading

0 comments on commit 15fd736

Please sign in to comment.