def test_area_to_rect_bad(area, bound_width, bound_height, min_ratio):
    with pytest.raises(ValueError):
        area_to_rect(area, bound_width, bound_height, min_ratio)
def test_area_to_rect(area, bound_width, bound_height, min_ratio, wh):
    assert area_to_rect(area, bound_width, bound_height, min_ratio) == wh
    def _alloc_boards_possible(self, boards, min_ratio=0.0,
                               max_dead_boards=None, max_dead_links=None,
                               require_torus=False):
        """Is it guaranteed that the specified allocation *could* succeed if
        enough of the machine is free?

        This function may be conservative. If the specified request would fail
        when no resources have been allocated, we return False, even if some
        circumstances the allocation may succeed. For example, if one board in
        each of the four corners of the machine is dead, no allocation with
        max_dead_boards==0 can succeed when the machine is empty but may
        succeed if some other allocation has taken place.

        Parameters
        ----------
        boards : int
            The *minimum* number of boards, must be at least 1. Note that if
            only 1 board is required, :py:class:`._alloc_board` would be a more
            appropriate function since this function may return as many as
            three boards when only a single one is requested.
        min_ratio : float
            The aspect ratio which the allocated region must be 'at least as
            square as'. Set to 0.0 for any allowable shape.
        max_dead_boards : int or None
            The maximum number of broken or unreachable boards to allow in the
            allocated region. If None, any number of dead boards is permitted,
            as long as the board on the bottom-left corner is alive (Default:
            None).
        max_dead_links : int or None
            The maximum number of broken links allow in the allocated region.
            When require_torus is True this includes wrap-around links,
            otherwise peripheral links are not counted.  If None, any number of
            broken links is allowed. (Default: None).
        require_torus : bool
            If True, only allocate blocks with torus connectivity. In general
            this will only succeed for requests to allocate an entire machine
            (when the machine is otherwise not in use!). (Default: False)

        Returns
        -------
        bool

        See Also
        --------
        alloc_possible : The (public) wrapper which also supports checking
                         triad allocations.
        """
        # Convert number of boards to number of triads (rounding up...)
        triads = int(ceil(boards / 3.0))

        # Sanity check: can't be a non-machine
        if triads <= 0:
            return False

        # Special case: If a torus is required this is only deliverable when
        # the requirements match the size of the machine exactly.
        if require_torus and (triads != self.width * self.height):
            return False

        # If no region of the right shape can be made, just fail
        wh = area_to_rect(triads, self.width, self.height, min_ratio)
        if wh is None:
            return False
        width, height = wh

        # Test to see whether the allocation could succeed in the idle machine
        cf = _CandidateFilter(self.width, self.height,
                              self.dead_boards, self.dead_links,
                              max_dead_boards, max_dead_links, require_torus,
                              boards)
        for x, y in set([(0, 0),
                         (self.width - width, 0),
                         (0, self.height - height),
                         (self.width - width, self.height - height)]):
            if cf(x, y, width, height):
                return True

        # No possible allocation could be made...
        return False
def test_area_to_rect_bad(area, bound_width, bound_height, min_ratio):
    with pytest.raises(ValueError):
        area_to_rect(area, bound_width, bound_height, min_ratio)
def test_area_to_rect(area, bound_width, bound_height, min_ratio, wh):
    assert area_to_rect(area, bound_width, bound_height, min_ratio) == wh
    def alloc_area(self, area, min_ratio=0.0, candidate_filter=None):
        """Attempt to allocate a rectangular region with at least the specified
        area which is 'at least as square' as the specified aspect ratio.

        Parameters
        ----------
        area : int
            The *minimum* area to allocate, must be at least 1.
        min_ratio : float
            The aspect ratio which the allocated region must be 'at least as
            square as'. Set to 0.0 for any allowable shape.
        candidate_filter : None or function(x, y, w, h) -> bool
            A function which will be called with candidate allocations. If the
            function returns False, the allocation is rejected and the
            allocator will attempt to find another. If the function returns
            True, the allocator will then create the allocation. This function
            may, for example, check that the suggested region is fully
            connected or does not have too many faults.

            If this argument is None (the default) the first candidate
            allocation found will be returned.

        Returns
        -------
        allocation : (x, y, w, h) or None
            If the allocation request was met, a tuple giving the position of
            the bottom-left corner, width and height of the allocation is
            returned.

            If the request could not be met, None is returned and no allocation
            is made.
        """
        # If this node is already populated, give up
        if self.allocated:
            return None

        # Allocation simply can't fit fail fast
        if area > self.width * self.height:
            return None

        # If this node is split (i.e. has children), try inserting into the
        # children.
        if self.children is not None:
            # Try the smallest child first
            for child in sorted(self.children,
                                key=(lambda c: c.width * c.height)):
                allocation = child.alloc_area(area, min_ratio,
                                              candidate_filter)
                if allocation:
                    return allocation
            else:
                # No child could fit the allocation, fail
                return None

        # This is a child node, try to work out a suitable size for the
        # allocation if possible
        rect = area_to_rect(area, self.width, self.height, min_ratio)
        if not rect:
            return None

        # Try allocating that size
        width, height = rect
        allocation = self.alloc(width, height, candidate_filter)
        if allocation:
            x, y = allocation
            return (x, y, width, height)
        else:
            return None