Ejemplo n.º 1
0
def is_hermitian(matrix: np.array) -> bool:
    """
    Whether matrix is Hermitian

    Args:
        matrix (np.ndarray): matrix to verify

    Return:
        bool: If matrix is Hermitian
    """
    return np.allclose(matrix, matrix.conj().T)
Ejemplo n.º 2
0
    def add_operator(
            self,
            op: np.array,
            qubits: typing.Optional[typing.Sequence[int]] = None) -> None:
        """
        Apply an operator to the density matrix
        :param op:
        :param qubits:
        :return:
        """

        if isinstance(qubits, int):
            qubits = [qubits]

        num_qubits, ndim = _get_dimensions(op)
        if qubits is None:
            qubits = np.arange(num_qubits)

        assert len(qubits) == num_qubits

        sum_indices_1 = list(qubits)
        new_indices_1 = list(
            range(2 * self.num_qubits, 2 * self.num_qubits + len(qubits)))
        sum_indices_2 = list(self.num_qubits + i for i in qubits)
        new_indices_2 = list(
            range(2 * self.num_qubits + len(qubits),
                  2 * self.num_qubits + 2 * len(qubits)))
        old_indices = list(range(2 * self.num_qubits))
        out_indices = list(range(2 * self.num_qubits))
        for i, ind in enumerate(sum_indices_1):
            out_indices[sum_indices_1[i]] = new_indices_1[i]
        for i, ind in enumerate(sum_indices_2):
            out_indices[sum_indices_2[i]] = new_indices_2[i]

        m = np.reshape(self.density_matrix, 2 * self.num_qubits * [2])
        op = np.reshape(op, 2 * len(qubits) * [2])
        m = np.einsum(
            op.conj(),
            sum_indices_1 + new_indices_1,
            m,
            old_indices,
            op,
            sum_indices_2 + new_indices_2,
            out_indices,
        )
        self._density_matrix = m.reshape(2**self.num_qubits, -1)
def is_hermitian(matrix: np.array) -> bool:
    r"""
    Whether matrix is Hermitian

    A square matrix :math:`U` is Hermitian if

    .. math:: U = U^\dagger

    where :math:`U^\dagger` is the conjugate transpose of :math:`U`.

    Args:
        matrix (np.ndarray): matrix to verify

    Return:
        bool: If matrix is Hermitian
    """
    return np.allclose(matrix, matrix.conj().T)
Ejemplo n.º 4
0
    def correlations_from_samples(beamformed_samples_1: np.array,
                                  beamformed_samples_2: np.array,
                                  record: OrderedDict) -> np.array:
        """
        Correlate two sets of beamformed samples together. Correlation matrices are used and
        indices corresponding to lag pulse pairs are extracted.

        Parameters
        ----------
        beamformed_samples_1: ndarray [num_slices, num_beams, num_samples]
            The first beamformed samples.
        beamformed_samples_2: ndarray [num_slices, num_beams, num_samples]
            The second beamformed samples.
        record: OrderedDict
            hdf5 record containing bfiq data and metadata

        Returns
        -------
        values: np.array
            Array of correlations for each beam, range, and lag
        """

        # beamformed_samples_1: [num_beams, num_samples]
        # beamformed_samples_2: [num_beams, num_samples]
        # correlated:           [num_beams, num_samples, num_samples]
        correlated = xp.einsum('jk,jl->jkl', beamformed_samples_1,
                               beamformed_samples_2.conj())

        if cupy_available:
            correlated = xp.asnumpy(correlated)

        values = []
        if record['lags'].size == 0:
            values.append(xp.array([]))
            return values

        # First range offset in samples
        sample_off = record['first_range_rtt'] * 1e-6 * record['rx_sample_rate']
        sample_off = xp.int32(sample_off)

        # Helpful values converted to units of samples
        range_off = xp.arange(record['num_ranges'],
                              dtype=xp.int32) + sample_off
        tau_in_samples = record['tau_spacing'] * 1e-6 * record['rx_sample_rate']
        lag_pulses_as_samples = xp.array(record['lags'],
                                         xp.int32) * xp.int32(tau_in_samples)

        # [num_range_gates, 1, 1]
        # [1, num_lags, 2]
        samples_for_all_range_lags = (range_off[..., xp.newaxis, xp.newaxis] +
                                      lag_pulses_as_samples[xp.newaxis, :, :])

        # [num_range_gates, num_lags, 2]
        row = samples_for_all_range_lags[..., 1].astype(xp.int32)

        # [num_range_gates, num_lags, 2]
        column = samples_for_all_range_lags[..., 0].astype(xp.int32)

        # [num_beams, num_range_gates, num_lags]
        values = correlated[:, row, column]

        # Find the sample that corresponds to the second pulse transmitting
        second_pulse_sample_num = xp.int32(
            tau_in_samples) * record['pulses'][1] - sample_off - 1

        # Replace all ranges which are contaminated by the second pulse for lag 0
        # with the data from those ranges after the final pulse.
        values[:, second_pulse_sample_num:,
               0] = values[:, second_pulse_sample_num:, -1]

        return values