コード例 #1
0
ファイル: permutation.py プロジェクト: BQSKit/bqskit
    def from_qubit_location(
        num_qubits: int,
        location: Sequence[int],
    ) -> PermutationMatrix:
        """
        Creates the permutation matrix specified by arguments.

        The resulting matrix will move the first len(location) qubits
        into positions defined by location.

        Args:
            num_qubits (int): Total number of qubits

            location (Sequence[int]): The desired locations to swap
                the starting qubits to.

        Returns:
            (PermutationMatrix): A 2**num_qubits by 2**num_qubits permutation
                matrix.

        Examples:
            calc_permutation_matrix( 2, (0, 1) ) =
                [ [ 1, 0, 0, 0 ],
                  [ 0, 1, 0, 0 ],
                  [ 0, 0, 1, 0 ],
                  [ 0, 0, 0, 1 ] ]

            Here the 4x4 identity is returned because there are 2 total
            qubits, specified by the first parameter, and the desired
            permutation is [0, 1] -> [0, 1].

            calc_permutation_matrix( 2, (1,) ) = # Also equals
            calc_permutation_matrix( 2, (1, 0) ) =
                [ [ 1, 0, 0, 0 ],
                [ 0, 0, 1, 0 ],
                [ 0, 1, 0, 0 ],
                [ 0, 0, 0, 1 ] ]
            This is a more interesting example. The swap gate is returned
            here since we are working with 2 qubits and want the permutation
            that swaps the two qubits, giving by the permutation [0] -> [1]
            or in the second case [0, 1] -> [1, 0]. Both calls produce
            identical permutations.
        """

        if not isinstance(num_qubits, int):
            raise TypeError(
                'Expected integer num_qudits'
                ', got %s.' % type(num_qubits), )

        if num_qubits <= 0:
            raise ValueError(
                'Expected positive num_qudits'
                ', got %d.' % num_qubits, )

        if not CircuitLocation.is_location(location, num_qubits):
            raise TypeError('Invalid location.')

        matrix = calc_permutation_matrix(num_qubits, location)
        return PermutationMatrix(matrix)
コード例 #2
0
ファイル: operation.py プロジェクト: BQSKit/bqskit
    def __init__(
        self, gate: Gate,
        location: CircuitLocationLike,
        params: Sequence[float] = [],
    ) -> None:
        """
        Operation Constructor.
s
        Args:
            gate (Gate): The cell's gate.

            location (CircuitLocationLike):  The set of qudits this gate
                affects.

            params (Sequence[float]): The parameters for the gate.

        Raises:
            ValueError: If `gate`'s size doesn't match `location`'s length.

            ValueError: If `gate`'s size doesn't match `params`'s length.
        """

        if not isinstance(gate, Gate):
            raise TypeError('Expected gate, got %s.' % type(gate))

        if not CircuitLocation.is_location(location):
            raise TypeError('Invalid location.')

        location = CircuitLocation(location)

        if len(location) != gate.get_size():
            raise ValueError('Gate and location size mismatch.')

        self.num_params = gate.get_num_params()
        self.radixes = gate.get_radixes()
        self.size = gate.get_size()

        if len(params) == 0 and self.get_num_params() != 0:
            params = [0.0] * self.get_num_params()

        self.check_parameters(params)

        self._gate = gate
        self._location = location
        self._params = list(params)
コード例 #3
0
ファイル: machine.py プロジェクト: BQSKit/bqskit
    def get_subgraph(
            self,
            location: CircuitLocationLike,
            renumbering: dict[int, int] = None,  # type: ignore
    ) -> list[tuple[int, int]]:
        """Returns the sub_coupling_graph with qudits in location."""
        if not CircuitLocation.is_location(location, self.num_qudits):
            raise TypeError('Invalid location.')

        location = CircuitLocation(location)
        if renumbering is None:
            renumbering = {x: x for x in range(self.num_qudits)}

        subgraph = []
        for q0, q1 in self.coupling_graph:
            if q0 in location and q1 in location:
                subgraph.append((renumbering[q0], renumbering[q1]))
        return subgraph
コード例 #4
0
ファイル: machine.py プロジェクト: BQSKit/bqskit
    def _location_search(
        self,
        locations: set[CircuitLocation],
        path: set[int],
        vertex: int,
        limit: int,
    ) -> None:
        """
        Add paths with length equal to limit to the `locations` set.

        Args:
            locations (set[CircuitLocation]): A list that contains all paths
                found so far of length equal to `limit`.

            path (set[int]): The qudit vertices currently included in
                the path.

            vertex (int): The vertex in the graph currently being examined.

            limit (int): The desired length of paths in the `locations`
                list.
        """
        if vertex in path:
            return

        curr_path = path.copy()
        curr_path.add(vertex)

        if len(curr_path) == limit:
            locations.add(CircuitLocation(curr_path))
            return

        frontier: set[int] = {
            qudit
            for node in curr_path for qudit in self._adjacency_list[node]
            if qudit not in curr_path
        }

        for neighbor in frontier:
            self._location_search(locations, curr_path, neighbor, limit)
コード例 #5
0
ファイル: vlg.py プロジェクト: BQSKit/bqskit
    def __init__(
        self,
        gate: Gate,
        locations: Sequence[CircuitLocationLike],
        radixes: Sequence[int],
    ) -> None:
        """
        Create a gate that has parameterized location.

        Args:
            gate (Gate): The gate to parameterize location for.

            locations (Sequence[CircuitLocationLike]): A sequence of locations.
                Each location represents a valid placement for gate.

            radixes (Sequence[int]): The number of orthogonal
                states for each qudit. Defaults to qubits.

        Raises:
            ValueError: If there are not enough locations or the locations
                are incorrectly sized.

        Notes:
            The locations are calculated in their own space and are not
            relative to a circuit. This means you should consider the
            VariableLocationGate as its own circuit when deciding the
            locations. For example, if you want to multiplex the (2, 3)
            and (3, 5) placements of a CNOT on a 6-qubit circuit, then
            you would give the VariableLocationGate the (0, 1) and (1, 2)
            locations and place the VariableLocationGate on qubits
            (2, 3, 5) on the circuit.
        """
        if not isinstance(gate, Gate):
            raise TypeError('Expected gate object, got %s' % type(gate))

        if not all(CircuitLocation.is_location(l) for l in locations):
            raise TypeError('Expected a sequence of valid locations.')

        locations = [CircuitLocation(l) for l in locations]

        if not all(len(l) == gate.get_size() for l in locations):
            raise ValueError('Invalid sized location.')

        if len(locations) < 1:
            raise ValueError('VLGs require at least 1 locations.')

        self.gate = gate
        self.name = 'VariableLocationGate(%s)' % gate.get_name()
        self.locations = list(locations)

        if radixes is None:
            # Calculate radixes
            radix_map: dict[int,
                            int | None] = {i: None
                                           for i in range(self.size)}
            for l in locations:
                for radix, qudit_index in zip(gate.get_radixes(), l):
                    if radix_map[qudit_index] is None:
                        radix_map[qudit_index] = radix
                    elif radix_map[qudit_index] != radix:
                        raise ValueError(
                            'Gate cannot be applied to all locations'
                            ' due to radix mismatch.', )

            self.radixes = tuple(radix_map.values())
        else:
            for l in locations:
                for radix, qudit_index in zip(gate.get_radixes(), l):
                    if radixes[qudit_index] != radix:
                        raise ValueError(
                            'Gate cannot be applied to all locations'
                            ' due to radix mismatch.', )

            self.radixes = tuple(radixes)

        self.size = len(self.radixes)
        self.num_params = self.gate.get_num_params() + len(locations)

        self.extension_size = self.size - self.gate.get_size()
        # TODO: This needs to changed for radixes
        self.I = np.identity(2**self.extension_size)
        self.perms = np.array([
            PermutationMatrix.from_qubit_location(self.size, l)
            for l in self.locations
        ])
コード例 #6
0
ファイル: unitarybuilder.py プロジェクト: BQSKit/bqskit
    def apply_right(
        self, utry: UnitaryMatrix,
        location: Sequence[int], inverse: bool = False,
    ) -> None:
        """
        Apply the specified unitary on the right of this UnitaryBuilder.

             .-----.   .------.
          0 -|     |---|      |-
          1 -|     |---| utry |-
             .     .   '------'
             .     .
             .     .
        n-1 -|     |------------
             '-----'

        Args:
            utry (UnitaryMatrix): The unitary to apply.

            location (Sequence[int]): The qudits to apply the unitary on.

            inverse (bool): If true, apply the inverse of the unitary.

        Notes:
            Applying the unitary on the right is equivalent to multiplying
            the unitary on the left of the tensor. This operation is
            performed using tensor contraction.
        """

        if not isinstance(utry, UnitaryMatrix):
            raise TypeError('Expected UnitaryMatrix, got %s', type(utry))

        if not CircuitLocation.is_location(location, self.get_size()):
            raise TypeError('Invalid location.')

        if len(location) != utry.get_size():
            raise ValueError('Unitary and location size mismatch.')

        for utry_radix, bldr_radix_idx in zip(utry.get_radixes(), location):
            if utry_radix != self.get_radixes()[bldr_radix_idx]:
                raise ValueError('Unitary and location radix mismatch.')

        left_perm = list(location)
        mid_perm = [x for x in range(self.get_size()) if x not in location]
        right_perm = [x + self.get_size() for x in range(self.get_size())]

        left_dim = int(np.prod([self.get_radixes()[x] for x in left_perm]))

        utry = utry.get_dagger() if inverse else utry
        utry_np = utry.get_numpy()

        perm = left_perm + mid_perm + right_perm
        self.tensor = self.tensor.transpose(perm)
        self.tensor = self.tensor.reshape((left_dim, -1))
        self.tensor = utry_np @ self.tensor

        shape = list(self.get_radixes()) * 2
        shape = [shape[p] for p in perm]
        self.tensor = self.tensor.reshape(shape)
        inv_perm = list(np.argsort(perm))
        self.tensor = self.tensor.transpose(inv_perm)
コード例 #7
0
ファイル: region.py プロジェクト: BQSKit/bqskit
 def location(self) -> CircuitLocation:
     return CircuitLocation(sorted(self.keys()))