def test_toolbox_metal_instantiation_qiskit_metal_design_error(self):
     """
     Test instantiation of QiskitMetalDesignError.
     """
     try:
         QiskitMetalDesignError("test message")
     except Exception:
         self.fail("QiskitMetalDesignError failed")
Example #2
0
    def connect_simple(self, start_pt: QRoutePoint,
                       end_pt: QRoutePoint) -> np.ndarray:
        """Try connecting start and end with single or 2-segment/S-shaped CPWs
        if possible.

        Args:
            start_pt (QRoutePoint): QRoutePoint of the start
            end_pt (QRoutePoint): QRoutePoint of the end

        Returns:
            List of vertices of a CPW going from start to end

        Raises:
            QiskitMetalDesignError: If the connect_simple() has failed.
        """
        avoid_collision = self.parse_options().advanced.avoid_collision

        start_direction = start_pt.direction
        start = start_pt.position
        end_direction = end_pt.direction
        end = end_pt.position

        # end_direction originates strictly from endpoint + leadout (NOT intermediate stopping anchors)
        self.assign_direction_to_anchor(start_pt, end_pt)
        stop_direction = end_pt.direction

        if (start[0] == end[0]) or (start[1] == end[1]):
            # Matching x or y coordinates -> check if endpoints can be connected with a single segment
            if mao.dot(start_direction, end - start) >= 0:
                # Start direction and end - start for CPW must not be anti-aligned
                if (end_direction is None) or (mao.dot(end - start,
                                                       end_direction) <= 0):
                    # If leadout + end has been reached, the single segment CPW must not be aligned with its direction
                    return np.empty((0, 2), float)
        else:
            # If the endpoints don't share a common x or y value:
            # designate them as 2 corners of an axis aligned rectangle
            # and check if both start and end directions are aligned with
            # the displacement vectors between start/end and
            # either of the 2 remaining corners ("perfect alignment").
            corner1 = np.array([start[0],
                                end[1]])  # x coordinate matches with start
            corner2 = np.array([end[0],
                                start[1]])  # x coordinate matches with end
            if avoid_collision:
                # Check for collisions at the outset to avoid repeat work
                startc1end = bool(
                    self.unobstructed([start, corner1])
                    and self.unobstructed([corner1, end]))
                startc2end = bool(
                    self.unobstructed([start, corner2])
                    and self.unobstructed([corner2, end]))
            else:
                startc1end = startc2end = True
            if (mao.dot(start_direction, corner1 - start) > 0) and startc1end:
                # corner1 is "in front of" the start_pt
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner1 - end) >= 0):
                    # corner1 is also "in front of" the end_pt
                    return np.expand_dims(corner1, axis=0)
            elif (mao.dot(start_direction, corner2 - start) >
                  0) and startc2end:
                # corner2 is "in front of" the start_pt
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner2 - end) >= 0):
                    # corner2 is also "in front of" the end_pt
                    return np.expand_dims(corner2, axis=0)
            # In notation below, corners 3 and 4 correspond to
            # the ends of the segment bisecting the longer rectangle formed by start and end
            # while the segment formed by corners 5 and 6 bisect the shorter rectangle
            if stop_direction[
                    0]:  # "Wide" rectangle -> vertical middle segment is more natural
                corner3 = np.array([(start[0] + end[0]) / 2, start[1]])
                corner4 = np.array([(start[0] + end[0]) / 2, end[1]])
                corner5 = np.array([start[0], (start[1] + end[1]) / 2])
                corner6 = np.array([end[0], (start[1] + end[1]) / 2])
            else:  # "Tall" rectangle -> horizontal middle segment is more natural
                corner3 = np.array([start[0], (start[1] + end[1]) / 2])
                corner4 = np.array([end[0], (start[1] + end[1]) / 2])
                corner5 = np.array([(start[0] + end[0]) / 2, start[1]])
                corner6 = np.array([(start[0] + end[0]) / 2, end[1]])
            if avoid_collision:
                startc3c4end = bool(
                    self.unobstructed([start, corner3])
                    and self.unobstructed([corner3, corner4])
                    and self.unobstructed([corner4, end]))
                startc5c6end = bool(
                    self.unobstructed([start, corner5])
                    and self.unobstructed([corner5, corner6])
                    and self.unobstructed([corner6, end]))
            else:
                startc3c4end = startc5c6end = True
            if (mao.dot(start_direction, stop_direction) < 0) and (mao.dot(
                    start_direction, corner3 - start) > 0) and startc3c4end:
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner4 - end) > 0):
                    # Perfectly aligned S-shaped CPW
                    return np.vstack((corner3, corner4))
            # Relax constraints and check if imperfect 2-segment or S-segment works,
            # where "imperfect" means 1 or more dot products of directions
            # between successive segments is 0; otherwise return an empty list
            if (mao.dot(start_direction, corner1 - start) >= 0) and startc1end:
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner1 - end) >= 0):
                    return np.expand_dims(corner1, axis=0)
            if (mao.dot(start_direction, corner2 - start) >= 0) and startc2end:
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner2 - end) >= 0):
                    return np.expand_dims(corner2, axis=0)
            if (mao.dot(start_direction, corner3 - start) >=
                    0) and startc3c4end:
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner4 - end) >= 0):
                    return np.vstack((corner3, corner4))
            if (mao.dot(start_direction, corner5 - start) >=
                    0) and startc5c6end:
                if (end_direction is None) or (mao.dot(end_direction,
                                                       corner6 - end) >= 0):
                    return np.vstack((corner5, corner6))
        raise QiskitMetalDesignError(
            "connect_simple() has failed. This might be due to one of two reasons. "
            f"1. Either one of the start point {start} or the end point {end} "
            "provided are inside the bounding box of another QComponent. "
            "Please move the point, or setup a \"lead\" to exit the QComponent area. "
            "2. none of the 4 routing possibilities of this algorithm "
            "(^|_, ^^|, __|, _|^) can complete. Please use Pathfinder instead")