def add_edge(self, edge, graph_code): """ Add an edge to the edge partition. .. note:: This method should only be called by the ``add_edge`` method of the graph that owns the partition. Calling it from anywhere else, even with the correct graph_code, will lead to unsupported inconsistency. :param AbstractEdge edge: the edge to add :param int graph_code: A code to check the correct graph is calling this method :raises PacmanInvalidParameterException: If the edge does not belong in this edge partition """ if graph_code != self._graph_code: raise PacmanConfigurationException( "Only one graph should add edges") if self._graph_code is None: raise PacmanConfigurationException( "Only Graphs can add edges to partitions") # Check for an incompatible edge if not isinstance(edge, self._allowed_edge_types): raise PacmanInvalidParameterException( "edge", str(edge.__class__), "Edges of this graph must be one of the following types:" " {}".format(self._allowed_edge_types)) self._edges.add(edge)
def add_edge(self, edge): # Check for an incompatible edge if not isinstance(edge, self._allowed_edge_types): raise PacmanInvalidParameterException( "edge", edge.__class__, "Edges of this graph must be one of the following types:" " {}".format(self._allowed_edge_types)) # Check for an incompatible pre vertex if self._pre_vertex is None: self._pre_vertex = edge.pre_vertex elif edge.pre_vertex != self._pre_vertex: raise PacmanConfigurationException( "A partition can only contain edges with the same" "pre_vertex") # Check for an incompatible traffic type if self._traffic_type is None: self._traffic_type = edge.traffic_type elif edge.traffic_type != self._traffic_type: raise PacmanConfigurationException( "A partition can only contain edges with the same" " traffic_type") self._edges.add(edge)
def __call__(self, extended_machine, placements, allocations, constraints, vertex_by_id): """ :param placements: :param allocations: :param extended_machine: :param constraints: """ # load the json files file_placements, core_allocations, constraints = \ self._load_json_files(placements, allocations, constraints) # validate the json files against the schemas self._validate_file_read_data(file_placements, core_allocations, constraints) memory_placements = Placements() # process placements for vertex_id in file_placements: if str(vertex_id) not in vertex_by_id: if text_type(vertex_id) not in core_allocations: raise PacmanConfigurationException( "I don't recognise this pattern of constraints for" " a vertex which does not have a placement") else: raise PacmanConfigurationException( "Failed to locate the vertex in the " "graph with id {}".format(vertex_id)) if text_type(vertex_id) in core_allocations: memory_placements.add_placement( Placement(x=file_placements[vertex_id][0], y=file_placements[vertex_id][1], p=core_allocations[vertex_id][0], vertex=vertex_by_id[str(vertex_id)])) else: # virtual chip or tag chip external_device_constraints = \ self._valid_constraints_for_external_device( self._locate_constraints(vertex_id, constraints)) if external_device_constraints: placements.add( self._make_virtual_placement( extended_machine, vertex_by_id[str(vertex_id)], external_device_constraints)) # return the file format return memory_placements
def add_edge(self, edge, graph_code): if self._sdram_base_address is not None: raise PacmanConfigurationException( "Illegal attempt to add an edge after sdram_base_address set") super().check_edge(edge) # safety check if self._pre_vertex != edge.pre_vertex: raise PacmanConfigurationException( "The destination segmented SDRAM partition only accepts " "1 pre-vertex") # add super().add_edge(edge, graph_code)
def sort_objects_by_constraint_authority(objects): """ Takes the subverts of a subgraph and orders them into a list\ with a order based off rank on the constraint\ :param objects: The objects to be sorted. need to have a constraints :type objects: iterable of soem object with constraints :return: A list of ordered objects :rtype: list of objects :raise None: this method does not raise any known exceptions """ objects_with_rank = list() for current_object in objects: if not hasattr(current_object, "constraints"): raise PacmanConfigurationException( "the object given to the " "sort_objects_by_constraint_authority method does not " "contain constraints. Every object must have at least a " "max atoms per core constraint") max_rank_so_far = 0 for constraint in current_object.constraints: # only store ranks for placer contraints and ones that are better # than already seen if (isinstance(constraint, AbstractPlacerConstraint) and constraint.get_rank() >= max_rank_so_far): max_rank_so_far = constraint.get_rank() objects_with_rank.append((current_object, max_rank_so_far)) ordered_objects = sorted(objects_with_rank, key=lambda cur_item: cur_item[1], reverse=True) return [item[0] for item in ordered_objects]
def _get_machine(self, url, n_chips, n_boards, total_run_time): """ :param str url: :param int n_chips: :param int n_boards: :param int total_run_time: :rtype: dict """ if n_boards: get_machine_request = requests.get(url, params={ "nBoards": n_boards, "runTime": total_run_time }) elif n_chips: get_machine_request = requests.get(url, params={ "nChips": n_chips, "runTime": total_run_time }) else: raise PacmanConfigurationException( "At least one of n_chips or n_boards must be provided") get_machine_request.raise_for_status() return get_machine_request.json()
def add_outgoing_edge_partition(self, edge_partition): if self.__frozen: raise PacmanConfigurationException( "Please add partitions via simulator not directly to this " "graph") super(_FrozenApplicationGraph, self).add_outgoing_edge_partition(edge_partition)
def get_total_sdram(self, n_timesteps): if n_timesteps is not None: return (self._fixed_sdram + self._per_timestep_sdram * n_timesteps) if self._per_timestep_sdram == 0: return self._fixed_sdram raise PacmanConfigurationException( "Unable to run forever with a variable SDRAM cost")
def _locate_destination( ethernet_chip_x, ethernet_chip_y, destination_class, placements): """ Locate destination vertex on Ethernet connected chip to send\ fixed data to :param ethernet_chip_x: chip x to search :param ethernet_chip_y: chip y to search :param destination_class: the class of vertex to search for :param placements: the placements objects :return: processor ID as a int, or None if no valid processor found :rtype: int or None """ for processor_id in range(0, Machine.MAX_CORES_PER_CHIP): # only check occupied processors if placements.is_processor_occupied( ethernet_chip_x, ethernet_chip_y, processor_id): # verify if vertex correct one if isinstance( placements.get_vertex_on_processor( ethernet_chip_x, ethernet_chip_y, processor_id), destination_class): return processor_id raise PacmanConfigurationException( "no destination vertex found on Ethernet chip {}:{}".format( ethernet_chip_x, ethernet_chip_y))
def __init__(self, keys_and_masks, key_list_function=None): """ :param keys_and_masks: The key and mask combinations to fix :type keys_and_masks: \ iterable(:py:class:`pacman.model.routing_info.BaseKeyAndMask`) :param key_list_function: Optional function which will be called to\ translate the keys_and_masks list into individual keys. If\ missing, the keys will be generated by iterating through the \ keys_and_masks list directly. The function parameters are: * An iterable of keys and masks * A machine edge * Number of keys to generate (may be None) :type key_list_function: iterable(\ :py:class:`pacman.model.routing_info.BaseKeyAndMask`,\ :py:class:`pacman.model.graphs.machine.MachineEdge`,\ int) -> iterable(int) """ for keys_and_mask in keys_and_masks: if not isinstance(keys_and_mask, BaseKeyAndMask): raise PacmanConfigurationException( "the keys and masks object contains a object that is not" "a key_and_mask object") self._keys_and_masks = keys_and_masks self._key_list_function = key_list_function
def _get_inputs(self, inputs): """ Get the required and optional inputs out of the inputs :param dict(str,...) inputs: A dict of input type to value :return: A dict of parameter name to value :rtype: dict(str,...) :raises PacmanConfigurationException: """ matches = dict() # Add required inputs, failing if they don't exist for required_input in self._required_inputs: match = required_input.get_inputs_by_name(inputs) if match is None: raise PacmanConfigurationException( "Missing required input {} of type {} for algorithm {}". format(required_input.name, required_input.param_types, self._algorithm_id)) matches.update(match) # Add optional inputs if they exist for optional_input in self._optional_inputs: match = optional_input.get_inputs_by_name(inputs) if match is not None: matches.update(match) return matches
def __locate_common_edge_type( self, pre_edge_types, post_edge_types, src_machine_vertex, dest_machine_vertex): """ searches the sets of edge types and finds the common one. if more\ than one common, is biased towards the destination common and the\ order of the list. :param pre_edge_types: the edge types the pre vertex can support for transmission :param post_edge_types: the edge types the post vertex can support for reception. :param MachineVertex src_machine_vertex: used for error message :param MachineVertex dest_machine_vertex: used for error message :return: MachineEdge class :rtype: type :raises PacmanConfigurationException: If we can't find a workable class """ for post_edge_type in post_edge_types: if post_edge_type in pre_edge_types: return post_edge_type # if iterated over the post edge types and not found a common type. # Blow up coz no way these two can communicate with each other. raise PacmanConfigurationException( self.__ERROR_MESSAGE_OF_NO_COMMON_EDGE_TYPE.format( src_machine_vertex, dest_machine_vertex))
def check_types_of_edge_constraint(machine_graph): """ Go through the graph for operations and checks that the constraints\ are compatible. :param MachineGraph machine_graph: the graph to search through :raises PacmanConfigurationException: if a problem is found """ for partition in machine_graph.outgoing_edge_partitions: if partition.traffic_type != EdgeTrafficType.MULTICAST: continue fixed_key = locate_constraints_of_type( partition.constraints, FixedKeyAndMaskConstraint) fixed_mask = locate_constraints_of_type( partition.constraints, FixedMaskConstraint) fixed_field = locate_constraints_of_type( partition.constraints, FixedKeyFieldConstraint) if len(fixed_key) > 1 or len(fixed_field) > 1 or len(fixed_mask) > 1: raise PacmanConfigurationException( "There are multiple constraint of the same type on partition " "{} starting at {}. Please fix and try again.".format( partition.identifier, partition.pre_vertex)) fixed_key = len(fixed_key) == 1 fixed_mask = len(fixed_mask) == 1 fixed_field = len(fixed_field) == 1 # check for fixed key and a fixed mask. as these should have been # merged before now if fixed_key and fixed_mask: raise PacmanConfigurationException( "The partition {} starting at {} has a fixed key and fixed " "mask constraint. These can be merged together, but is " "deemed an error here".format( partition.identifer, partition.pre_vertex)) # check for a fixed key and fixed field, as these are incompatible if fixed_key and fixed_field: raise PacmanConfigurationException( "The partition {} starting at {} has a fixed key and fixed " "field constraint. These may be merge-able together, but is " "deemed an error here".format( partition.identifer, partition.pre_vertex)) # check that a fixed mask and fixed field have compatible masks if fixed_mask and fixed_field: _check_masks_are_correct(partition)
def _check_allowed_elements(path, element, allowed): if any( sub.tag.split("}")[-1] not in allowed for sub in element.iterchildren()): raise PacmanConfigurationException( "Error in XML starting at line {} of {}: Only" " one of {} is allowed in {}".format(element.sourceline, path, allowed, element.tag))
def _get_algorithm_data(algorithm_names, algorithm_data_objects): algorithms = list() for algorithm_name in algorithm_names: if algorithm_name not in algorithm_data_objects: raise PacmanConfigurationException( "Cannot find algorithm {}".format(algorithm_name)) algorithms.append(algorithm_data_objects[algorithm_name]) return algorithms
def add_edge(self, edge, graph_code): # add super().check_edge(edge) super().add_edge(edge, graph_code) # check if len(self._destinations.keys()) != 1: raise PacmanConfigurationException( "The {} can only support 1 destination vertex".format( self._class_name)) if len(self._pre_vertices[edge.pre_vertex]) != 1: raise PacmanConfigurationException( "The {} only supports 1 edge from a given pre vertex.".format( self._class_name)) if self._sdram_base_address is not None: raise PacmanConfigurationException( "Illegal attempt to add an edge after sdram_base_address set")
def add_edge(self, edge, graph_code): # add AbstractMachineEdgePartition.check_edge(self, edge) AbstractMultiplePartition.add_edge(self, edge, graph_code) # check if len(self._destinations.keys()) != 1: raise PacmanConfigurationException( "The MultiSourcePartition can only support 1 destination " "vertex") if len(self._pre_vertices[edge.pre_vertex]) != 1: raise PacmanConfigurationException( "The MultiSourcePartition only supports 1 edge from a " "given pre vertex.") if self._sdram_base_address is not None: raise PacmanConfigurationException( "Illegal attempt to add an edge after sdram_base_address set")
def register_graph_code(self, graph_code): """ Allows the graph to register its code when the partition is added """ if self._graph_code is not None: raise PacmanConfigurationException( "Illegal attempt to add partition {} to a second " "graph".format(self)) self._graph_code = graph_code
def set_max_atoms_per_core(self, max_atoms_per_core, is_fixed_atoms): """ sets max atoms per core for this splitter object :param int max_atoms_per_core: max atoms per core for this splitter. :param bool is_fixed_atoms: is this a hard constraint or soft. :raises PacmanConfigurationException: If the new setting clash with a previous setting """ if self._is_fixed_atoms_per_core: # Already fixed so if is_fixed_atoms: # as new also fixed they must be the same if max_atoms_per_core != self._max_atoms_per_core: raise PacmanConfigurationException( self.FIX_ATOMS_RESET.format( max_atoms_per_core, self._max_atoms_per_core)) else: return # No change else: # as new a max make sure it is not lower than current fixed if max_atoms_per_core < self._max_atoms_per_core: raise PacmanConfigurationException( self.MAX_BELOW_FIXED.format( max_atoms_per_core, self._max_atoms_per_core)) else: return # OK to ignore the max above the fixed else: # Currently on a max so if is_fixed_atoms: # As new is fixed max sure it is not higher than max if max_atoms_per_core > self._max_atoms_per_core: raise PacmanConfigurationException( self.FIXED_ABOVE_MAX.format( max_atoms_per_core, self._max_atoms_per_core)) else: # Set the new fixed self._max_atoms_per_core = max_atoms_per_core self._is_fixed_atoms_per_core = True else: # Both max so only change if new max if lower if max_atoms_per_core < self._max_atoms_per_core: # Set the new max but leave fixed false self._max_atoms_per_core = max_atoms_per_core else: return # Ok to Ignore a higher or same max
def set_governed_app_vertex(self, app_vertex): super().set_governed_app_vertex(app_vertex) if not isinstance(app_vertex, LegacyPartitionerAPI): for abstractmethod in LegacyPartitionerAPI._abstract_methods(): check = getattr(app_vertex, abstractmethod, None) if not check: raise PacmanConfigurationException( self.NOT_SUITABLE_VERTEX_ERROR.format( app_vertex.label, self._splitter_name, abstractmethod)) logger.warning(self.NOT_API_WARNING)
def add_edge(self, edge, graph_code): if self._sdram_size is None: self._sdram_size = edge.sdram_size elif self._sdram_size != edge.sdram_size: raise SDRAMEdgeSizeException( "The edges within the constant sdram partition {} have " "inconsistent memory size requests.".format(self)) if self._sdram_base_address is None: AbstractSingleSourcePartition.add_edge(self, edge, graph_code) else: raise PacmanConfigurationException( "Illegal attempt to add an edge after sdram_base_address set")
def __call__(self, machine_graph, n_keys_map, graph_mapper=None): # check that this algorithm supports the constraints check_algorithm_can_support_constraints( constrained_vertices=machine_graph.outgoing_edge_partitions, supported_constraints=[ FixedMaskConstraint, FixedKeyAndMaskConstraint, ContiguousKeyRangeContraint, ShareKeyConstraint ], abstract_constraint_type=AbstractKeyAllocatorConstraint) # verify that no edge has more than 1 of a constraint ,and that # constraints are compatible utilities.check_types_of_edge_constraint(machine_graph) # final keys allocations routing_infos = RoutingInfo() # Get the edges grouped by those that require the same key (fixed_keys, shared_keys, fixed_masks, fixed_fields, flexi_fields, continuous, noncontinuous) = utilities.get_edge_groups(machine_graph, EdgeTrafficType.MULTICAST) # Even non-continuous keys will be continuous for group in noncontinuous: continuous.append(group) # Go through the groups and allocate keys progress = ProgressBar(machine_graph.n_outgoing_edge_partitions, "Allocating routing keys") # allocate the groups that have fixed keys for group in progress.over(fixed_keys, False): self._allocate_fixed_keys(group, routing_infos) for group in progress.over(fixed_masks, False): self._allocate_fixed_masks(group, n_keys_map, routing_infos) for group in progress.over(fixed_fields, False): self._allocate_fixed_fields(group, n_keys_map, routing_infos) if flexi_fields: raise PacmanConfigurationException( "MallocBasedRoutingInfoAllocator does not support FlexiField") for group in progress.over(shared_keys, False): self._allocate_share_key(group, routing_infos, n_keys_map) for group in continuous: self._allocate_continuous_groups(group, routing_infos, n_keys_map) progress.end() return routing_infos
def set_label(self, label): """ Changes the label for a vertex *not yet added* to a graph. :param str label: new value for the label :raises PacmanConfigurationException: If there is an attempt to change the label once the vertex has been added to a graph """ if self._added_to_graph: raise PacmanConfigurationException( "As Labels are also IDs they can not be changed.") self._label = label
def check_edge(self, edge): """ check a edge traffic type. :param AbstractEdge edge: the edge to check :raises PacmanInvalidParameterException: If the edge does not belong in this edge partition """ # Check for an incompatible traffic type if edge.traffic_type != self.traffic_type: raise PacmanConfigurationException( "A partition can only contain edges with the same " "traffic_type; trying to add a {} edge to a partition of " "type {}".format(edge.traffic_type, self.traffic_type))
def _check_allowed_elements(self, element, allowed): """ :param lxml.etree._Element element: :param set(str) allowed: :raises PacmanConfigurationException: """ if any( self.__name(sub) not in allowed for sub in self.__child_elems(element)): raise PacmanConfigurationException( "Error in XML starting at line {} of {}: Only" " one of {} is allowed in {}".format(element.sourceline, self._xml_path, allowed, element.tag))
def _get_algorithm_data(algorithm_names, algorithm_data_objects): """ :param iterable(str) algorithm_names: :param dict(str, AbstractAlgorithm) algorithm_data_objects: :rtype: list(AbstractAlgorithm) :raises PacmanConfigurationException: """ algorithms = list() for algorithm_name in algorithm_names: if algorithm_name not in algorithm_data_objects: raise PacmanConfigurationException( "Cannot find algorithm {}".format(algorithm_name)) algorithms.append(algorithm_data_objects[algorithm_name]) return algorithms
def _allocate_partition_route(self, edge, placements, graph, n_keys_map): destination = edge.post_vertex placement = placements.get_placement_of_vertex(destination) keys_and_masks = list([ BaseKeyAndMask(base_key=self._get_key_from_placement(placement), mask=self.MASK) ]) partition = graph.get_outgoing_edge_partition_starting_at_vertex( edge.pre_vertex) n_keys = n_keys_map.n_keys_for_partition(partition) if n_keys > self.MAX_KEYS_SUPPORTED: raise PacmanConfigurationException( "Only edges which require less than {} keys are" " supported".format(self.MAX_KEYS_SUPPORTED)) return PartitionRoutingInfo(keys_and_masks, edge)
def __init__(self, base_key, mask): """ :param int base_key: The routing key :param int mask: The routing mask :raise PacmanConfigurationException: If key & mask != key i.e. the key is not valid for the given mask """ self._base_key = base_key self._mask = mask if base_key & mask != base_key: raise PacmanConfigurationException( "This routing info is invalid as the mask {} and key {} " "together alters the key. This is deemed to be a error from " "SpiNNaker's point of view and therefore please rectify and " "try again".format(hex(base_key), hex(mask)))
def splitter(self, new_value): """ Sets the splitter object. Does not allow repeated settings. :param new_value: The new splitter object :type new_value: ~pacman.model.partitioner_interfaces.AbstractSplitterPartitioner :rtype: None """ if self._splitter == new_value: return if self._splitter is not None: raise PacmanConfigurationException( self.SETTING_SPLITTER_ERROR_MSG.format(self._label)) self._splitter = new_value self._splitter.set_governed_app_vertex(self) self._splitter.check_supported_constraints()
def _get_link_data(machine, vertex): if isinstance(vertex, AbstractFPGA): link_data = machine.get_fpga_link_with_id( vertex.fpga_id, vertex.fpga_link_id, vertex.board_address) if link_data is None: raise NoFPGALink(vertex) return link_data elif isinstance(vertex, AbstractSpiNNakerLink): link_data = machine.get_spinnaker_link_with_id( vertex.spinnaker_link_id, vertex.board_address) if link_data is None: raise NoSpiNNakerLink(vertex) return link_data else: # Ugh; this means we can't handle link data for arbitrary classes raise PacmanConfigurationException( "Unknown virtual vertex type {}".format(vertex.__class__))