Source code for pacman.operations.router_compressors.clash_compressor

# Copyright (c) 2017-2019 The University of Manchester
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from collections import defaultdict
from pacman.exceptions import MinimisationFailedError

from .abstract_compressor import AbstractCompressor
from .entry import Entry


[docs]class ClashCompressor(AbstractCompressor): __slots__ = [ "_all_entries", "_max_clashes" ]
[docs] def find_merge(self, an_entry, route_entries): for another in route_entries: m_key, m_mask, defaultable = self.merge(an_entry, another) clashers = [] for route in self._all_entries: for check in self._all_entries[route]: if self.intersect(check.key, check.mask, m_key, m_mask): if len(clashers) >= self._max_clashes: break else: clashers.append(check) if len(clashers) >= self._max_clashes: break if len(clashers) == 0: route_entries.remove(another) return Entry( m_key, m_mask, defaultable, an_entry.spinnaker_route) if len(clashers) <= self._max_clashes: for entry in clashers: entry.clashes += 1 return None
[docs] def compress_by_route(self, route_entries): results = [] while len(route_entries) > 1: an_entry = route_entries.pop() merged = self.find_merge(an_entry, route_entries) if merged is None: results.append(an_entry) else: route_entries.append(merged) if len(route_entries) == 1: results.append(route_entries.pop()) return results
[docs] def compress_ignore_clashers(self, router_table, top_entries): while True: self._all_entries = defaultdict(list) for mcr_entry in router_table.multicast_routing_entries: entry = Entry.from_MulticastRoutingEntry(mcr_entry) if entry not in top_entries: self._all_entries[entry.spinnaker_route].append(entry) if len(top_entries) + \ len(self._all_entries) > self.MAX_SUPPORTED_LENGTH: raise MinimisationFailedError("Too many top entries") results = [] all_routes = list(self._all_entries) for spinnaker_route in all_routes: if len(self._all_entries[spinnaker_route]) == 1: results.extend(self._all_entries.pop(spinnaker_route)) complex_routes = sorted( list(self._all_entries), key=lambda x: len(self._all_entries[x]) + 1/(self._all_entries[x][0].spinnaker_route+1), reverse=False) for spinnaker_route in complex_routes: compressed = self.compress_by_route( self._all_entries.pop(spinnaker_route)) results.extend(compressed) if len(top_entries) + len(results) < self._target_length: print("success!", len(top_entries) + len(results), len(top_entries), len(results)) answer = top_entries + results print("Good Results ", len(answer)) return answer clashers = [] for entry in results: if entry.clashes > 0: clashers.append(entry) print(len(top_entries) + len(results), len(top_entries), len(results), len(clashers)) if len(clashers) == 0: answer = top_entries + results print("Best Results ", len(answer)) if len(answer) > self.MAX_SUPPORTED_LENGTH: raise MinimisationFailedError("No clashers left") return answer clashers = sorted(clashers, key=lambda x: x.clashes, reverse=True) top_entries.extend(clashers[0:1])
[docs] def compress_table(self, router_table): # Split the entries into buckets based on spinnaker_route self._max_clashes = 1 try: results = self.compress_ignore_clashers(router_table, []) return results except Exception as ex: # pylint: disable=broad-except print(ex) self._problems += "(x:{},y:{})={} ".format( router_table.x, router_table.y, len(results)) return []