def __add_fixed(self, partition, constraint):
        """
        Precomputes and caches FixedKeyAndMask for easier use later

        Saves a map of partition to the constraint records these in a dict by
        Partition so they can be found easier in future passes.

        Saves a list of the keys and their n_keys so these zones can be blocked

        :param pacman.model.graphs.AbstractEdgePartition partition:
        :param FixedKeyAndMaskConstraint constraint:
        """
        self.__fixed_partitions[partition] = constraint.keys_and_masks
        for key_and_mask in constraint.keys_and_masks:
            # Go through the mask sets and save keys and n_keys
            for key, n_keys in get_key_ranges(key_and_mask.key,
                                              key_and_mask.mask):
                self.__fixed_keys.append((key, n_keys))
    def _allocate_fixed_keys_and_masks(self, keys_and_masks, fixed_mask):
        """ Allocate fixed keys and masks.

        :param iterable(BaseKeyAndMask) keys_and_masks:
            the fixed keys and masks combos
        :param fixed_mask: fixed mask
        :type fixed_mask: int or None
        :rtype: None
        :raises PacmanRouteInfoAllocationException:
        """
        # If there are fixed keys and masks, allocate them
        for key_and_mask in keys_and_masks:
            # If there is a fixed mask, check it doesn't clash
            if fixed_mask is not None and fixed_mask != key_and_mask.mask:
                raise PacmanRouteInfoAllocationException(
                    "Cannot meet conflicting constraints")

            # Go through the mask sets and allocate
            for key, n_keys in get_key_ranges(key_and_mask.key,
                                              key_and_mask.mask):
                self._allocate_elements(key, n_keys)
    def _allocate_keys_and_masks(self,
                                 fixed_mask,
                                 fields,
                                 partition_n_keys,
                                 contiguous_keys=True):
        """
        :param fixed_mask:
        :type fixed_mask: int or None
        :param fields:
        :type fields: iterable(Field) or None
        :param int partition_n_keys:
        :param bool contiguous_keys:
        :rtype: list(BaseKeyAndMask)
        :raises PacmanRouteInfoAllocationException:
        """
        # If there isn't a fixed mask, generate a fixed mask based
        # on the number of keys required
        masks_available = [fixed_mask]
        if fixed_mask is None:
            masks_available = get_possible_masks(
                partition_n_keys, contiguous_keys=contiguous_keys)

        # For each usable mask, try all of the possible keys and
        # see if a match is possible
        mask_found = None
        key_found = None
        mask = None
        for mask in masks_available:
            logger.debug("Trying mask {} for {} keys", hex(mask),
                         partition_n_keys)

            key_found = None
            key_generator = KeyFieldGenerator(mask, fields,
                                              self._free_space_tracker)
            for key in key_generator:
                logger.debug("Trying key {}", hex(key))

                # Check if all the key ranges can be allocated
                matched_all = True
                index = 0
                for (base_key, n_keys) in get_key_ranges(key, mask):
                    logger.debug("Finding slot for {}, n_keys={}",
                                 hex(base_key), n_keys)
                    index = self._find_slot(base_key, lo=index)
                    logger.debug("Slot for {} is {}", hex(base_key), index)
                    if index is None:
                        matched_all = False
                        break
                    space = self._check_allocation(index, base_key, n_keys)
                    logger.debug("Space for {} is {}", hex(base_key), space)
                    if space is None:
                        matched_all = False
                        break

                if matched_all:
                    logger.debug("Matched key {}", hex(key))
                    key_found = key
                    break

            # If we found a matching key, store the mask that worked
            if key_found is not None:
                logger.debug("Matched mask {}", hex(mask))
                mask_found = mask
                break

        # If we found a working key and mask that can be assigned,
        # Allocate them
        if key_found is not None and mask_found is not None:
            for (base_key, n_keys) in get_key_ranges(key_found, mask):
                self._allocate_elements(base_key, n_keys)

            # If we get here, we can assign the keys to the edges
            return [BaseKeyAndMask(base_key=key_found, mask=mask)]

        raise PacmanRouteInfoAllocationException(
            "Could not find space to allocate keys")