Example #1
0
    def __init__(self, size: int, radixes: Sequence[int] = []) -> None:
        """
        Creates an VariableUnitaryGate, defaulting to a qubit gate.

        Args:
            size (int) The number of qudits this gate acts on.

            radixes (Sequence[int]): The number of orthogonal
                states for each qudit. Defaults to qubits.
        """
        if size <= 0:
            raise ValueError('Expected positive integer, got %d' % size)

        if len(radixes) == 0:
            radixes = [2] * size

        if not is_valid_radixes(radixes, size):
            raise TypeError('Invalid radixes.')

        self.size = size
        self.radixes = tuple(radixes)
        self.dim = int(np.prod(self.radixes))
        self.shape = (self.dim, self.dim)
        self.num_params = 2 * self.dim**2
        self.name = 'VariableUnitaryGate(%d)' % self.get_size()
Example #2
0
    def random(size: int, radixes: Sequence[int] = []) -> UnitaryMatrix:
        """
        Sample a random unitary from the haar distribution.

        Args:
            size (np.ndarray): The number of qudits for the matrix. This
                is not the dimension.

            radixes (Sequence[int]): The radixes for the Unitary.

        Returns:
            (UnitaryMatrix): A random unitary matrix.
        """

        if not is_integer(size):
            raise TypeError('Expected int for size, got %s.' % type(size))

        if size <= 0:
            raise ValueError('Expected positive number for size.')

        radixes = tuple(radixes if len(radixes) > 0 else [2] * size)

        if not is_valid_radixes(radixes):
            raise TypeError('Invalid qudit radixes.')

        if len(radixes) != size:
            raise ValueError(
                'Expected length of radixes to be equal to size:'
                ' %d != %d' % (len(radixes), size), )

        U = unitary_group.rvs(int(np.prod(radixes)))
        return UnitaryMatrix(U, radixes, False)
Example #3
0
    def __init__(self, vec: StateLike, radixes: Sequence[int] = []) -> None:
        """
        Constructs a StateVector with the supplied vector.

        Args:
            vec (StateLike): The state vector.

            radixes (Sequence[int]): A sequence with its length equal to
                the number of qudits this StateVector represents. Each
                element specifies the base, number of orthogonal states,
                for the corresponding qudit. By default, the constructor
                will attempt to calculate `radixes` from `vec`.

        Raises:
            TypeError: If `radixes` is not specified and the constructor
                cannot determine `radixes`.
        """
        # Copy Constructor
        if isinstance(vec, StateVector):
            self.vec = vec.get_numpy()
            self.dim = vec.get_dim()
            self.radixes = vec.get_radixes()
            self.size = vec.get_size()
            return

        np_vec = np.array(vec, dtype=np.complex128)

        if not StateVector.is_pure_state(np_vec):
            raise TypeError('Expected valid state vector.')

        self.vec = np_vec
        self.dim = self.vec.shape[0]

        if radixes:
            self.radixes = tuple(radixes)

        # Check if unitary dimension is a power of two
        elif self.dim & (self.dim - 1) == 0:
            self.radixes = tuple([2] * int(np.round(np.log2(self.dim))))

        # Check if unitary dimension is a power of three
        elif 3 ** int(np.round(np.log(self.dim) / np.log(3))) == self.dim:
            radixes = [3] * int(np.round(np.log(self.dim) / np.log(3)))
            self.radixes = tuple(radixes)

        else:
            raise TypeError(
                'Unable to determine radixes'
                ' for UnitaryMatrix with dim %d.' % self.dim,
            )

        if not is_valid_radixes(self.radixes):
            raise TypeError('Invalid qudit radixes.')

        if np.prod(self.radixes) != self.dim:
            raise ValueError('Qudit radixes mismatch with dimension.')

        self.size = len(self.radixes)
Example #4
0
    def __init__(
        self,
        gate: Gate,
        num_controls: int = 1,
        radixes: Sequence[int] = [],
    ) -> None:
        """Construct a ControlledGate."""

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

        if not is_integer(num_controls):
            raise TypeError(
                'Expected integer for num_controls, got %s.'
                % type(num_controls),
            )

        if num_controls < 1:
            raise ValueError(
                'Expected positive integer for num_controls, got %d.'
                % num_controls,
            )

        if len(radixes) != 0 and not is_valid_radixes(radixes, num_controls):
            raise TypeError('Invalid radixes.')

        self.gate = gate
        self.size = gate.get_size() + num_controls
        self.num_controls = num_controls
        self.radixes = tuple(radixes or [2] * self.size) + gate.get_radixes()
        self.name = '%d-Controlled(%s)' % (num_controls, gate.get_name())
        self.num_params = gate.get_num_params()

        self.Ic = np.identity(2 ** num_controls)  # TODO: General radix support
        self.It = np.identity(gate.get_dim())
        self.OneProj = np.zeros(self.Ic.shape)
        self.OneProj[-1, -1] = 1
        self.left = np.kron((self.Ic - self.OneProj), self.It)

        # If input is a constant gate, we can cache the unitary.
        if self.num_params == 0:
            U = self.gate.get_unitary()
            right = np.kron(self.OneProj, U)
            self.utry = UnitaryMatrix(self.left + right, self.get_radixes())
Example #5
0
    def __init__(self, size: int = 1, radixes: Sequence[int] = []) -> None:
        """
        Creates an IdentityGate, defaulting to a single-qubit identity.

        Args:
            size (int) The number of qudits this gate acts on.

            radixes (Sequence[int]): The number of orthogonal
                states for each qudit. Defaults to qubits.
        """
        if size <= 0:
            raise ValueError('Expected positive integer, got %d' % size)
        if len(radixes) != 0 and not is_valid_radixes(radixes, size):
            raise TypeError('Invalid radixes.')

        self.size = size
        self.radixes = tuple(radixes or [2] * size)
        self.utry = UnitaryMatrix.identity(int(np.prod(self.radixes)))
        self.qasm_name = 'identity%d' % self.size
Example #6
0
    def __init__(self, size: int, radixes: Sequence[int] = []) -> None:
        """
        UnitaryBuilder constructor.

        Args:
            size (int): The number of qudits to build a Unitary for.

            radixes (Sequence[int]): A sequence with its length equal
                to `size`. Each element specifies the base of a
                qudit. Defaults to qubits.

        Raises:
            ValueError: if size is nonpositive.

        Examples:
            >>> builder = UnitaryBuilder(4)  # Creates a 4-qubit builder.
        """

        if not is_integer(size):
            raise TypeError('Expected int for size, got %s.' % type(size))

        if size <= 0:
            raise ValueError('Expected positive number for size.')

        self.size = size
        self.radixes = tuple(radixes if len(radixes) > 0 else [2] * self.size)

        if not is_valid_radixes(self.radixes):
            raise TypeError('Invalid qudit radixes.')

        if len(self.radixes) != self.size:
            raise ValueError(
                'Expected length of radixes to be equal to size:'
                ' %d != %d' % (len(self.radixes), self.size),
            )

        self.num_params = 0
        self.dim = int(np.prod(self.radixes))
        self.tensor = np.identity(self.get_dim())
        self.tensor = self.tensor.reshape(self.radixes * 2)
Example #7
0
 def test_value(self, r6_qudit_circuit: Circuit) -> None:
     assert is_valid_radixes(r6_qudit_circuit.get_radixes(), 6)
Example #8
0
    def __init__(
        self,
        utry: UnitaryLike,
        radixes: Sequence[int] = [],
        check_arguments: bool = True,
    ) -> None:
        """
        Constructs a UnitaryMatrix with the supplied unitary matrix.

        Args:
            utry (UnitaryLike): The unitary matrix.

            radixes (Sequence[int]): A sequence with its length equal to
                the number of qudits this UnitaryMatrix can act on. Each
                element specifies the base, number of orthogonal states,
                for the corresponding qudit. By default, the constructor
                will attempt to calculate `radixes` from `utry`.

        Raises:
            TypeError: If `radixes` is not specified and the constructor
                cannot determine `radixes`.

        Examples:
            >>> UnitaryMatrix(
            ...     [
            ...         [0, 1],
            ...         [1, 0],
            ...     ],
            ... )  # Creates a single-qubit Pauli X unitary matrix.
        """

        # Copy Constructor
        if isinstance(utry, UnitaryMatrix):
            self.utry = utry.get_numpy()
            self.dim = utry.get_dim()
            self.num_params = utry.get_num_params()
            self.radixes = utry.get_radixes()
            self.size = utry.get_size()
            return

        np_utry = np.array(utry, dtype=np.complex128)

        if check_arguments and not is_unitary(np_utry):
            raise TypeError('Expected unitary matrix.')

        self.utry = np_utry
        self.dim = self.utry.shape[0]
        self.num_params = 0

        if radixes:
            self.radixes = tuple(radixes)

        # Check if unitary dimension is a power of two
        elif self.dim & (self.dim - 1) == 0:
            self.radixes = tuple([2] * int(np.round(np.log2(self.dim))))

        # Check if unitary dimension is a power of three
        elif 3**int(np.round(np.log(self.dim) / np.log(3))) == self.dim:
            radixes = [3] * int(np.round(np.log(self.dim) / np.log(3)))
            self.radixes = tuple(radixes)

        else:
            raise TypeError(
                'Unable to determine radixes'
                ' for UnitaryMatrix with dim %d.' % self.dim, )

        if check_arguments and not is_valid_radixes(self.radixes):
            raise TypeError('Invalid qudit radixes.')

        if check_arguments and np.prod(self.radixes) != self.dim:
            raise ValueError('Qudit radixes mismatch with dimension.')

        self.size = len(self.radixes)