Пример #1
0
def energy_gradient(
    local_energies: np.ndarray,
    logarithmic_derivatives: np.ndarray,
    weights: np.ndarray = None,
) -> np.ndarray:
    r"""Calculates the gradient of energy with respect to variational
    parameters: ``∂⟨ψ|H|ψ⟩/∂W``.

    :param local_energies: local energy estimators ``⟨σ|H|ψ⟩/⟨σ|ψ⟩``.
    :param logarithmic_derivatives: **centered** logarithmic derivatives of the
        wavefunction with respect to variational parameters.
    :param weights: if specified, it is assumed that {σ} span the whole
        Hilbert space basis. Then ``weights`` are **normalized** probabilities
        ``|⟨σ|ψ⟩|²/‖ψ‖₂``. If ``weights`` is ``None``, then it is assumed that
        {σ} come from Monte Carlo sampling and are distributed according to
        ``|⟨σ|ψ⟩|²/‖ψ‖₂``.
    """
    if weights is not None:
        assert np.isclose(np.sum(weights), 1.0)
        local_energies = weights * local_energies
        local_energies = local_energies.conj()
        local_energies = local_energies.reshape(1, -1)
        gradient = local_energies @ logarithmic_derivatives
    else:
        local_energies = local_energies.conj()
        local_energies = local_energies.reshape(1, -1)
        gradient = local_energies @ logarithmic_derivatives
        gradient /= logarithmic_derivatives.shape[0]
    return np.ascontiguousarray(2.0 * gradient.real.squeeze())
Пример #2
0
def primal_problem(q_a: np.ndarray, pperm: np.ndarray, num_reps: int) -> float:
    """
    Primal problem for counterfeit attack.

    As the primal problem takes longer to solve than the dual problem (as
    the variables are of larger dimension), the primal problem is only here
    for reference.

    :return: The optimal value of performing a counterfeit attack.
    """
    num_spaces = 3

    sys = list(range(1, num_spaces * num_reps))
    sys = [elem for elem in sys if elem % num_spaces != 0]

    # The dimension of each subsystem is assumed to be of dimension 2.
    dim = 2 * np.ones((1, num_spaces * num_reps)).astype(int).flatten()
    dim = dim.tolist()

    x_var = cvxpy.Variable((8**num_reps, 8**num_reps), hermitian=True)
    if num_reps == 1:
        objective = cvxpy.Maximize(
            cvxpy.trace(cvxpy.real(q_a.conj().T @ x_var)))
    else:
        objective = cvxpy.Maximize(
            cvxpy.trace(
                cvxpy.real(pperm @ q_a.conj().T @ pperm.conj().T @ x_var)))
    constraints = [
        partial_trace(x_var, sys, dim) == np.identity(2**num_reps),
        x_var >> 0,
    ]
    problem = cvxpy.Problem(objective, constraints)

    return problem.solve()
Пример #3
0
    def expand_to_hermitian(
            matrix: np.ndarray,
            vector: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """ Expand a non-hermitian matrix A to a hermitian matrix by
        [[0, A.H], [A, 0]] and expand vector b to [b.conj, b].

        Args:
            matrix: the input matrix
            vector: the input vector

        Returns:
            the expanded matrix, the expanded vector
        """
        #
        half_dim = matrix.shape[0]
        full_dim = 2 * half_dim
        new_matrix = np.zeros([full_dim, full_dim])
        new_matrix = np.array(new_matrix, dtype=complex)
        new_matrix[0:half_dim, half_dim:full_dim] = matrix[:, :]
        new_matrix[half_dim:full_dim, 0:half_dim] = matrix.conj().T[:, :]
        matrix = new_matrix
        new_vector = np.zeros((1, full_dim))
        new_vector = np.array(new_vector, dtype=complex)
        new_vector[0, :vector.shape[0]] = vector.conj()
        new_vector[0, vector.shape[0]:] = vector
        vector = new_vector.reshape(np.shape(new_vector)[1])
        return matrix, vector
Пример #4
0
 def correlation(data1: np.ndarray, data2: np.ndarray) -> float:
     """
     相关系数计算
     :param data1: 第一个序列
     :param data2: 第二个序列
     :return: 相关系数值
     """
     return np.abs(data1.dot(data2.conj())) / np.sqrt(
         (np.abs(data1.dot(data1.conj())))) / np.sqrt(
             (np.abs(data2.dot(data2.conj()))))
Пример #5
0
def calculate_pulse_correlation_filter_function(R: ndarray,
                                                which: str = 'fidelity'
                                                ) -> ndarray:
    r"""Compute pulse correlation filter function from the control matrix.

    Parameters
    ----------
    R: array_like, shape (n_pulses, n_nops, d**2, n_omega)
        The control matrix.

    Returns
    -------
    F_pc: ndarray, shape (n_pulses, n_pulses, n_nops, n_nops, [d**2, d**2], n_omega)  # noqa
        The pulse correlation filter functions for each pulse and noise
        operator correlations. The first two axes hold the pulse correlations,
        the second two the noise correlations.
    which : str, optional
        Which filter function to return. Either 'fidelity' (default) or
        'generalized' (see :ref:`Notes <notes>`).

    Notes
    -----
    The generalized pulse correlation filter function is given by

    .. math::

        F_{\alpha\beta,kl}^{(gg')}(\omega) = \bigl[
            \mathcal{Q}^{(g'-1)\dagger}\mathcal{R}^{(g')\dagger}(\omega)
        \bigr]_{k\alpha} \bigl[
            \mathcal{R}^{(g)}(\omega)\mathcal{Q}^{(g-1)}
        \bigr]_{\beta l} e^{i\omega(t_{g-1} - t_{g'-1})},

    with :math:`\mathcal{R}^{(g)}` the control matrix of the :math:`g`-th
    pulse. The fidelity pulse correlation function is obtained by tracing out
    the basis indices,

    .. math::

        F_{\alpha\beta}^{(gg')}(\omega) =
          \sum_{k} F_{\alpha\beta,kk}^{(gg')}(\omega)

    See Also
    --------
    calculate_control_matrix_from_scratch: Control matrix from scratch.
    calculate_control_matrix_from_atomic: Control matrix from concatenation.
    calculate_filter_function: Regular filter function.
    """
    if R.ndim != 4:
        raise ValueError('Expected R.ndim == 4.')

    if which == 'fidelity':
        return np.einsum('gako,hbko->ghabo', R.conj(), R)
    elif which == 'generalized':
        return np.einsum('gako,hblo->ghabklo', R.conj(), R)
Пример #6
0
def liouville_representation(U: ndarray, basis: _b.Basis) -> ndarray:
    r"""
    Get the Liouville representaion of the unitary U with respect to the
    basis.

    Parameters
    ----------
    U: ndarray, shape (..., d, d)
        The unitary.
    basis: Basis, shape (d**2, d, d)
        The basis used for the representation, e.g. a Pauli basis.

    Returns
    -------
    R: ndarray, shape (..., d**2, d**2)
        The Liouville representation of U.

    Notes
    -----
    The Liouville representation of a unitary quantum operation
    :math:`\mathcal{U}:\rho\rightarrow U\rho U^\dagger` is given by

    .. math::

        \mathcal{U}_{ij} = \mathrm{tr}(C_i U C_j U^\dagger)

    with :math:`C_i` elements of the basis spanning
    :math:`\mathbb{C}^{d\times d}` with :math:`d` the dimension of the
    Hilbert space.
    """
    U = np.asanyarray(U)
    if basis.btype == 'GGM' and basis.d > 12:
        # Can do closed form expansion and overhead compensated
        path = ['einsum_path', (0, 1), (0, 1)]
        conjugated_basis = np.einsum('...ba,ibc,...cd->...iad',
                                     U.conj(),
                                     basis,
                                     U,
                                     optimize=path)
        # If the basis is hermitian, the result will be strictly real so we can
        # drop the imaginary part
        R = _b.ggm_expand(conjugated_basis).real
    else:
        path = ['einsum_path', (0, 1), (0, 1), (0, 1)]
        R = np.einsum('...ba,ibc,...cd,jda',
                      U.conj(),
                      basis,
                      U,
                      basis,
                      optimize=path).real

    return R
 def get_initial_state_set(gate: np.ndarray) -> Iterator[np.ndarray]:
     """Yields all initial states in order depending on gate shape"""
     # First tensor product then pauli transfer matrix
     if gate.shape[0] == gate.shape[
             1] == 2:  # Pauli Transfer Matrix (single qubit)
         for observable in BasisUnitarySet.get_observable_set(dim=2):
             yield .5 * (gate @ (observable @ gate.conj().transpose()))
     elif gate.shape[0] == gate.shape[
             1] == 4:  # Pauli Transfer Matrix (double qubits)
         for observable in BasisUnitarySet.get_observable_set(dim=4):
             yield .25 * (gate @ (observable @ gate.conj().transpose()))
     else:
         raise NotImplemented
Пример #8
0
def is_skew_hermitian(H: np.ndarray, tol: float = 1e-8) -> bool:
    """Checks if H is a skew hermitian matrix."""

    if not is_square_matrix(H):
        return False

    if not np.allclose(-H, H.conj().T, rtol=0, atol=tol):
        if _logger.isEnabledFor(logging.DEBUG):
            norm = np.linalg.norm(-H - H.conj().T)
            _logger.debug(
                'Failed skew hermitian condition, ||H - H^d|| = %e' % norm, )
        return False

    return True
Пример #9
0
def compute_mismatch_statistics(waveforms: np.ndarray, reconstructions: np.ndarray) -> Dict[str, float]:
    """Compute statistics comparing the mismatch of values between two arrays.
    
    We compare the ratio of values for each length element (i.e. frequency bin)
    between the two arrays, following similar procedure to Green and Gair (2020).
    """
    norm1 = np.mean(np.abs(waveforms)**2, axis=1)
    norm2 = np.mean(np.abs(reconstructions)**2, axis=1)
    inner = np.mean(waveforms.conj()*reconstructions, axis=1).real

    # if ratio of values are similar matches should tend to 1.
    matches = inner / np.sqrt(norm1 * norm2)
    mismatches = 1 - matches

    statistics = {
        'mean': np.mean(mismatches),
        'std': np.std(mismatches),
        'max': np.max(mismatches),
        'median': np.median(mismatches),
        'perc99': np.percentile(mismatches, 99.),
        'perc99.9': np.percentile(mismatches, 99.9),
        'perc99.99': np.percentile(mismatches, 99.99),
    }

    return statistics
Пример #10
0
def calculate_canonical_filter_function_derivative(
        R: ndarray, deriv_R: ndarray) -> ndarray:
    r"""
    Compute the filter function derivative from the control matrix.

    Parameters
    ----------
    R : array_like, shape (n_nops, d**2, n_omega)
        The control matrix.
    deriv_R: array_like, shape (n_nops, d**2, n_t, n_ctrl, n_omega)
        The derivative of the control matrix.

    Returns
    -------
    deriv_filter_function : ndarray, shape (n_nops, n_dt, n_ctrl, n_omega)
        The regular filter functions' derivatives for variation in each control
        contribution
        :math:`\frac{\partial F_\alpha(\omega)}{\partial u_h(t_{g'})}`.
        The array's indexing has shape :math:`(\alpha,g^\prime,h,\omega)`.

    Notes
    -----
    The filter function derivative is calculated according to

    .. math ::

        \frac{\partial F_\alpha(\omega)}{\partial u_h(t_{g'})}
                    = 2 \mathrm{Re} \left( \sum_k R_{\alpha k}^\ast(\omega)
                    \frac{\partial R_{\alpha k}(\omega)}
                    {\partial u_h(t_{g'})} \right)
    """
    summe = np.einsum('ako,aktho->atho', R.conj(), deriv_R)
    return 2 * summe.real
Пример #11
0
def concurrence(rho: np.ndarray) -> float:
    r"""
    Calculate the concurrence of a bipartite state.

    The concurrence of a bipartite state :math:`\rho` is defined as

    .. math::
        \max(0, \lambda_1 - \lambda_2 - \lambda_3 - \lambda_4),

    where :math:`\lambda_1, \ldots, \lambda_4` are the eigenvalues in
    decreasing order of the matrix.

    References:
        [1] Wikipedia page for concurrence (quantum computing)
        https://en.wikipedia.org/wiki/Concurrence_(quantum_computing)

    :param rho: The bipartite system specified as a matrix.
    :return: The concurrence of the bipartite state :math:`\rho`.
    """
    if rho.shape != (4, 4):
        raise ValueError(
            "InvalidDim: Concurrence is only defined for bipartite"
            " systems.")

    sigma_y = pauli("Y", False)
    sigma_y_y = np.kron(sigma_y, sigma_y)

    rho_hat = np.matmul(np.matmul(sigma_y_y, rho.conj().T), sigma_y_y)

    eig_vals = np.linalg.eigvalsh(np.matmul(rho, rho_hat))
    eig_vals = np.sort(np.sqrt(eig_vals))[::-1]
    return max(0, eig_vals[0] - eig_vals[1] - eig_vals[2] - eig_vals[3])
Пример #12
0
    def _expectation_from_wavefunction_no_validation(
            self, state: np.ndarray, qubit_map: Mapping[raw_types.Qid,
                                                        int]) -> float:
        """Evaluate the expectation of this PauliString given a wavefunction.

        This method does not provide input validation. See
        `PauliString.expectation_from_wavefunction` for function description.

        Args:
            state: An array representing a valid wavefunction.
            qubit_map: A map from all qubits used in this PauliString to the
            indices of the qubits that `state` is defined over.

        Returns:
            The expectation value of the input state.
        """
        if len(state.shape) == 1:
            num_qubits = state.shape[0].bit_length() - 1
            state = np.reshape(state, (2, ) * num_qubits)

        ket = np.copy(state)
        for qubit, pauli in self.items():
            buffer = np.empty(ket.shape, dtype=state.dtype)
            args = protocols.ApplyUnitaryArgs(target_tensor=ket,
                                              available_buffer=buffer,
                                              axes=(qubit_map[qubit], ))
            ket = protocols.apply_unitary(pauli, args)

        return self.coefficient * (np.tensordot(
            state.conj(), ket, axes=len(ket.shape)).item())
Пример #13
0
def pauli_decompose_hermitian(matrix: np.ndarray,
                              qubits: Qubits = None) -> Pauli:
    """Decompose a Hermitian matrix into an element of the Pauli algebra.

    This works because tensor products of Pauli matrices form an orthonormal
    basis in the linear space of all 2^N×2^N matrices under Hilbert-Schmidt
    inner product.
    """
    # TODO: This should work for any matrix, not just Hermitian?
    #       Generalize: remove hermitian check and coercing coefficients to real.

    if not np.ndim(matrix) == 2:
        raise ValueError("Must be square matrix")

    # TODO: Wait is this true?
    if not np.allclose(matrix.conj().T, matrix):
        raise ValueError("Matrix must be Hermitian")

    N = int(np.log2(np.size(matrix))) // 2
    if not 2**(2 * N) == np.size(matrix):
        raise ValueError("Matrix dimensions must be power of 2")

    if qubits is None:
        qubits = list(range(N))
    else:
        assert len(qubits) == N

    terms = []
    for ops in product("IXYZ", repeat=N):
        P = Pauli.term(qubits, "".join(ops)).asoperator(qubits=qubits)
        coeff = np.real(np.trace(P @ matrix) / (2**N))
        term = Pauli.term(qubits, "".join(ops), coeff)
        terms.append(term)

    return pauli_sum(*terms)
Пример #14
0
    def from_rotation_matrix(matrix: np.ndarray):
        # This method assumes row-vector and postmultiplication of that vector
        m = matrix.conj().transpose()
        if m[2, 2] < 0:
            if m[0, 0] > m[1, 1]:
                t = 1 + m[0, 0] - m[1, 1] - m[2, 2]
                q = [
                    m[1, 2] - m[2, 1], t, m[0, 1] + m[1, 0], m[2, 0] + m[0, 2]
                ]
            else:
                t = 1 - m[0, 0] + m[1, 1] - m[2, 2]
                q = [
                    m[2, 0] - m[0, 2], m[0, 1] + m[1, 0], t, m[1, 2] + m[2, 1]
                ]
        else:
            if m[0, 0] < -m[1, 1]:
                t = 1 - m[0, 0] - m[1, 1] + m[2, 2]
                q = [
                    m[0, 1] - m[1, 0], m[2, 0] + m[0, 2], m[1, 2] + m[2, 1], t
                ]
            else:
                t = 1 + m[0, 0] + m[1, 1] + m[2, 2]
                q = [
                    t, m[1, 2] - m[2, 1], m[2, 0] - m[0, 2], m[0, 1] - m[1, 0]
                ]

        q = np.array(q).astype('float64')
        q *= 0.5 / np.sqrt(t)
        return Quaternion(*q)
Пример #15
0
def a_sat(input_signal: np.ndarray, IBO_dB: int = 0) -> float:
    ibo = 10**(IBO_dB / 10)  # IBOをもとにアンプの飽和電力を決める
    P_in = np.sum(
        (input_signal *
         input_signal.conj()).real) / input_signal.shape[0]  # nで割るべき?
    A = np.sqrt(P_in * ibo)
    return A
Пример #16
0
    def __init__(self, mat: np.ndarray):
        """
        Initiliaze object of class.
        :param mat: np.ndarray[L,N]
        Matrix representation of the linear operator.
        """
        # Check mat
        try:
            mat = np.asarray(mat)
        except ValueError:
            print("Input matrix must be a numpy array.")
        # Init from super class
        super(LinearOperatorFromMatrix, self).__init__(shape=mat.shape,
                                                       dtype=mat.dtype)

        # Matrix corresponding to the linear operator
        self.mat = mat

        # Adjoint
        self.adjoint = mat.conj().transpose()

        # Corresponding Gram matrix
        self.gram = self.adjoint @ mat

        # Spectral norm, Lipschitz constant
        self.norm = self.lipschitz_cst = np.sqrt(
            spsparse.eigs(self.gram,
                          k=1,
                          which='LM',
                          return_eigenvectors=False,
                          maxiter=int(5e4)))
Пример #17
0
def negative_log_likelihood_gradient(choi_predictor: np.ndarray,
                                     observation_vec: np.ndarray,
                                     choi: np.ndarray) -> np.ndarray:
    r"""Calculate the derivative of the log-likelihood
    :math:`\mathcal{L}(C_\mathcal{E})` around the given Choi matrix
    :math:`C_\mathcal{E}`.

    See :func:`negative_log_likelihood` for computing the value at a given point.

    :return: A matrix giving the gradient :math:`\nabla \mathcal{L}(C_\mathcal{E}) =
        \frac{\partial\mathcal{L}(C_\mathcal{E})}{\partial C_\mathcal{E}}`, in the usual
        element-wise matrix calculus sense.
    """

    probability_vec = np.real(choi_predictor @ mat2vec(choi))

    # Fudge predictions away from 0 to avoid stalling as suggested in
    # [KBLG18] appendix D.
    mask_small = probability_vec < 1e-16
    if np.any(mask_small):
        warnings.warn("{} very small probabilities encountered".format(
            np.sum(mask_small)))
    probability_vec[mask_small] = 1e-16
    probability_vec /= np.sum(probability_vec)

    # See e.g. [AL12] eq. 13 and [KBLG18] eq. 6.
    # [KBLG18] suggests the equivalent of `-choi_predictor.conj().T @ vec2mat(...)` in
    # appendix A but that doesn't work out in terms of dimensions.
    return -vec2mat(choi_predictor.conj().T @ (observation_vec / probability_vec))
Пример #18
0
def is_unitary(matrix: np.ndarray) -> bool:
    """
    Check if the passed in matrix of size (n times n) is unitary.

    Arguments:
    matrix: the matrix which is checked

    Return:
    unitary: True if the matrix is unitary
    """
    unitary = True
    # TODO: check that F is unitary, if not return false
    n = matrix.shape[0]
    
    identity_matrix = np.identity(n)
    
    conjugate_transpose = matrix.conj().T
    
    mult = np.dot(matrix, conjugate_transpose)
    
    if np.allclose(mult, identity_matrix):
        unitary = True
    else:
        unitary = False

    return unitary
Пример #19
0
def stacked_fit_linear_background(data: numpy.ndarray,
                                  signal_index: int,
                                  rcond=1e-10) -> numpy.ndarray:
    """Return the linear background using least squares for an ndarray with signal in last index.

    The outline for this implementation comes from:
    http://stackoverflow.com/questions/30442377/how-to-solve-many-overdetermined-systems-of-linear-equations-using-vectorized-co
    """

    assert signal_index == -1
    signal_length = data.shape[signal_index]

    # using equation y = Ap where A = [[x 1]] and p = [[m], [c]], solve for p.
    linear = numpy.arange(signal_length)
    ones = numpy.ones((signal_length, ))
    A = numpy.vstack([linear, ones]).T

    # solve for p using svd. p will have the shape (n, 2) where n is the dimensions of the non-signal indexes of the data.
    u, s, v = numpy.linalg.svd(A, full_matrices=False)
    s_max = numpy.amax(s, axis=-1, keepdims=True)
    s_min = rcond * s_max
    inv_s = numpy.zeros_like(s)
    inv_s[s >= s_min] = 1 / s[s >= s_min]
    x = numpy.einsum('...ji,...j->...i', v,
                     inv_s * numpy.einsum('...ji,...j->...i', u, data.conj()))
    return numpy.conj(x, x)
Пример #20
0
    def solve_pure(self,
                   y1: ndarray,
                   ngrid: int = 11,
                   debug: bool = False) -> PureSolutionInterface:
        """Solves time depepdent Schrödinger equation for pure inital state
        """
        start = self.offset["normalized_time"][0]
        end = self.offset["normalized_time"][1]
        interval = np.linspace(start, end, ngrid)

        sol = PureSolutionInterface(y1)

        for jj in range(ngrid - 1):
            y1 = y1 / (np.sqrt(np.absolute(y1.conj().T @ y1)))
            tempsol = solve_ivp(
                fun=self._apply_H,
                t_span=[interval[jj], interval[jj + 1]],
                y0=y1,
                t_eval=np.linspace(*self.offset["normalized_time"], num=100),
                **self.solver,
            )
            y1 = tempsol.y[:, tempsol.t.size - 1]
            sol.t = np.hstack((sol.t, tempsol.t))
            sol.y = np.hstack((sol.y, tempsol.y))

        if debug:
            print(
                "final total prob",
                (np.absolute(sol.y[:, -1].conj().dot(sol.y[:, -1])))**2,
            )
        return sol
def gradient_descent(X: np.ndarray, y: np.ndarray, theta: float, alpha: float,
                     iters: int):
    '''
    Implements gradient descent to the update given theta

    Parameters
    ----------
    X : Numpy ndarray
        Training data
    y : Numpy ndarray
        Target data
    theta : float
        The Parameter to update
    alpha : float
        Learning rate
    iters : int
        Number of iterations to run
    '''
    m = len(y)
    history = []
    for _ in range(iters):
        h_x = np.dot(theta, X)
        errors = h_x - y

        # Update the parameter
        theta_ch = (alpha * np.dot(X.conj().T, errors)) / m

        theta = theta - theta_ch

        # Capture history for plotting
        history.append((cf.calculate_cost(X, y, theta), theta))

    return history, theta
Пример #22
0
def unitary_entanglement_fidelity(U_actual: np.ndarray,
                                  U_ideal: np.ndarray) -> np.ndarray:
    r"""Entanglement fidelity between two unitaries.

    For unitary matrices, this is related to the average unitary fidelity F
    as

    :math:`F = \frac{F_e d + 1}{d + 1}`
    where d is the matrix dimension.

    Args:
        U_actual : Matrix whose fidelity to U_ideal will be computed. This may
            be a non-unitary matrix, i.e. the projection of a larger unitary
            matrix into the computational subspace.
        U_ideal : Unitary matrix to which U_actual will be compared.

    Both arguments may be vectorized, in that their shapes may be of the form
    (...,M,M) (as long as both shapes can be broadcast together).

    Returns:
        The entanglement fidelity between the two unitaries. For inputs with
        shape (...,M,M), the output has shape (...).

    """
    U_actual = np.asarray(U_actual)
    U_ideal = np.asarray(U_ideal)
    assert (U_actual.shape[-1] == U_actual.shape[-2]
            ), "Inputs' trailing dimensions must be equal (square)."

    dim = U_ideal.shape[-1]

    prod_trace = np.einsum('...ba,...ba->...', U_actual.conj(), U_ideal)

    return np.real((np.abs(prod_trace)) / dim)**2
Пример #23
0
def music(x: np.ndarray, pos, f, c, aziang, eleang, nsignals):
    # a = bf.covariance(x)
    R = np.dot(x, x.conj().T) / 1000
    D, V = np.linalg.eigh(R)
    idx = D.argsort()[::-1]
    eigenvals = D[idx]  # Sorted vector of eigenvalues
    eigenvects = V[:, idx]  # Eigenvectors rearranged accordingly
    noise_eigenvects = eigenvects[:, nsignals:len(
        eigenvects)]  # Noise eigenvectors
    # 计算迭代次数,最小化计算开销
    len_az = len(aziang)
    len_el = len(eleang)
    pattern_shape = (len_el, len_az)
    scan_az, scan_el = np.meshgrid(aziang, eleang)
    scan_angles = np.vstack(
        (scan_az.reshape(-1, order='F'),
         scan_el.reshape(-1, order='F')))  # shape=(2, len_el*len_az)

    num_iter = min(len_el, len_az)
    scan_angle_block_size = max(len_el, len_az)
    scan_angle_block_index = np.arange(scan_angle_block_size)
    # scan
    pattern = np.zeros(len_az * len_el)
    for i in range(num_iter):
        cur_idx = scan_angle_block_index + i * scan_angle_block_size
        cur_angles = scan_angles[:, cur_idx]
        time_delay = bf.steering_plane_wave(pos, c, np.deg2rad(cur_angles.T)).T
        a = np.exp(-1j * 2 * np.pi * f * time_delay)
        # 两种方法一样
        # A = a.conj().T.dot(noise_eigenvects).dot(noise_eigenvects.conj().T).dot(a)
        # D = np.diag(A)
        D = np.sum(np.abs((a.T.dot(noise_eigenvects)))**2, 1)
        pattern[cur_idx] = 1 / D
    scan_pattern = np.sqrt(pattern).reshape(pattern_shape, order='F')
    return scan_pattern
Пример #24
0
def weak_coin_flipping(rho: np.ndarray) -> float:
    """
    Weak coin flipping protocol [MS]_.

    Examples
    ==========

    References
    ==========
    .. [MS] Ganz, Maor and Sattath, Or
        Quantum coin hedging, and a counter measure
        https://arxiv.org/pdf/1703.03887.pdf
    """
    dims = rho.shape
    id_dim = int(np.sqrt(dims[0]))

    sdp_var = cvxpy.Variable(dims, PSD=True)
    objective = cvxpy.Maximize(cvxpy.trace(rho.conj().T @ sdp_var))
    constraints = [
        partial_trace_cvx(sdp_var) == 1 / id_dim * np.identity(id_dim)
    ]
    problem = cvxpy.Problem(objective, constraints)
    sol_default = problem.solve()

    return sol_default
Пример #25
0
def tlphcoh(wt1: ndarray,
            wt2: ndarray,
            freq: ndarray,
            fs: float,
            wsize: int = 10) -> ndarray:
    """
    Time-localized phase coherence.

    Parameters
    ----------
    wt1 : ndarray
        [2D array, complex] Wavelet transform of the first signal.
    wt2 : ndarray
        [2D array, complex] Wavelet transform of the second signal. Must be the same shape as `wt1`.
    freq : ndarray
        [1D array] Frequencies at which the wavelet transforms wt1 and wt2 were calculated.
    fs : float
        Sampling frequency of the signals.
    wsize : int, optional
         (Default value = 10) The window size.

    Returns
    -------
    tpc : ndarray
        [2D array] The time-localized wavelet phase coherence.
    """
    NF, L = wt1.shape

    ipc = np.exp(1j * np.angle(wt1 * wt2.conj()))
    zpc = ipc.copy()
    zpc[np.isnan(zpc)] = 0

    zeros = np.zeros((NF, 1), np.complex64)
    csum = np.cumsum(zpc, axis=1)

    cum_pc = np.hstack((zeros, csum))
    tpc = np.zeros((NF, L), np.complex64) * np.NaN

    for fn in range(NF):
        cs = ipc[fn, :]
        cumcs = cum_pc[fn, :]

        f = np.nonzero(~np.isnan(cs))[0]
        window = np.round(wsize / freq[fn] * fs)
        window += 1 - np.mod(window, 2)

        hw = np.floor(window / 2)

        if len(f) >= 2:
            tn1 = f[0]
            tn2 = f[-1]
            if window <= tn2 - tn1:
                window = np.int(window)
                hw = np.int(hw)

                locpc = (np.abs(cumcs[tn1 + window:tn2 + 1 + 1] -
                                cumcs[tn1:tn2 - window + 1 + 1]) / window)
                tpc[fn, tn1 + hw:tn2 - hw + 1] = locpc

    return tpc  # TODO: implement 'under_sample' from matlab version?
Пример #26
0
def fft_flip(
        fftarray: np.ndarray,
        axes: Sequence[int] = (-1, ),
) -> np.ndarray:
    """
    Swap positive/negative frequencies and complex conjugate Fourier transform.

    Result is the Fourier transform of the complex conjugate of the inverse
    transform of the input array.
    If the input array is from a real Fourier transform the final axis should
    be excluded, as it doesn't contain negative frequencies.

    Parameters
    ----------
    fftarray : np.ndarray
        Fourier transform.
    axes : Sequence[int], optional
        Which axes were Fourier transformed? Default = (-1,).
        Exclude final axis for a real Fourier transform.

    Returns
    -------
    rfftarray : np.ndarray
        Fourier transform with frequencies flipped, complex conjugated.
    """
    fftconj = fftarray.conj()
    return np.roll(np.flip(fftconj, axes), 1, axes)
def proj_choi_to_unitary(choi: np.ndarray, check_finite: bool = True) -> np.ndarray:
    """
    Compute the unitary closest to a quantum process specified by a Choi matrix.

    This function enforces Hermiticity of the Choi matrix. See [IntQC]_ for more details:

    .. [IntQC] Interference of Quantum Channels.
        Daniel K. L. Oi.
        Phys. Rev. Lett. 91, 067902 (2003).
        https://doi.org/10.1103/PhysRevLett.91.067902
        https://arxiv.org/abs/quant-ph/0303178

    :param choi: the Choi representation of a quantum process.
    :param check_finite: check that the input matrices contain only finite numbers.
    :return: choi matrix corresponding to the closest unitary
    """
    dim = int(np.sqrt(choi.shape[0]))
    hermitian_choi = (choi + choi.conj().T) / 2  # enforce Hermiticity
    vals, vs = linalg.eigh(hermitian_choi, check_finite=check_finite)

    # vec corresponding to largest eval =  Kraus OP with largest norm
    large_eigen_vec = vs[:, np.argmax(vals)].reshape((dim * dim, 1))
    kraus = unvec(large_eigen_vec)

    U, s, V = linalg.svd(kraus)
    unitary = U @ V
    # pick a global phase convention, we choose the first element
    phase = np.angle(unitary[0, 0])
    return kraus2choi(np.exp(-1j * phase) * unitary)
Пример #28
0
def ssq(x: np.ndarray, axis=None):
    """
    sum-of-squares
        this method is ~10% faster than (abs(x)**2).sum()
    """
    x = np.asarray(x)
    return (x * x.conj()).real.sum(axis)
Пример #29
0
    def __init__(
            self,
            matrix: np.ndarray,
            vector: np.ndarray,
            truncate_powerdim: bool = False,
            truncate_hermitian: bool = False,
            eigs: Optional[Eigenvalues] = None,
            init_state: Optional[InitialState] = None,
            reciprocal: Optional[Reciprocal] = None,
            num_q: int = 0,
            num_a: int = 0,
            orig_size: Optional[int] = None
    ) -> None:
        """
        Constructor.

        Args:
            matrix: the input matrix of linear system of equations
            vector: the input vector of linear system of equations
            truncate_powerdim: flag indicating expansion to 2**n matrix to be truncated
            truncate_hermitian: flag indicating expansion to hermitian matrix to be truncated
            eigs: the eigenvalue estimation instance
            init_state: the initial quantum state preparation
            reciprocal: the eigenvalue reciprocal and controlled rotation instance
            num_q: number of qubits required for the matrix Operator instance
            num_a: number of ancillary qubits for Eigenvalues instance
            orig_size: The original dimension of the problem (if truncate_powerdim)
        Raises:
            ValueError: invalid input
        """
        super().__init__()
        if matrix.shape[0] != matrix.shape[1]:
            raise ValueError("Input matrix must be square!")
        if matrix.shape[0] != len(vector):
            raise ValueError("Input vector dimension does not match input "
                             "matrix dimension!")
        if not np.allclose(matrix, matrix.conj().T):
            raise ValueError("Input matrix must be hermitian!")
        if np.log2(matrix.shape[0]) % 1 != 0:
            raise ValueError("Input matrix dimension must be 2**n!")
        if truncate_powerdim and orig_size is None:
            raise ValueError("Truncation to {} dimensions is not "
                             "possible!".format(orig_size))

        self._matrix = matrix
        self._vector = vector
        self._truncate_powerdim = truncate_powerdim
        self._truncate_hermitian = truncate_hermitian
        self._eigs = eigs
        self._init_state = init_state
        self._reciprocal = reciprocal
        self._num_q = num_q
        self._num_a = num_a
        self._circuit = None
        self._io_register = None
        self._eigenvalue_register = None
        self._ancilla_register = None
        self._success_bit = None
        self._original_dimension = orig_size
        self._ret = {}
Пример #30
0
def is_normal(mat: np.ndarray,
              rtol: float = 1e-05,
              atol: float = 1e-08) -> bool:
    r"""
    Determine if a matrix is normal.

    A matrix is normal if it commutes with its adjoint

    .. math::
        \begin{equation}
            [X, X^*] = 0,
        \end{equation}

    or, equivalently if

    .. math::
        \begin{equation}
            X^* X = X X^*.
        \end{equation}

    References:
        [1] Wikipedia: Normal matrix.
        https://en.wikipedia.org/wiki/Normal_matrix

    :param mat: The matrix to check.
    :param rtol: The relative tolerance parameter (default 1e-05).
    :param atol: The absolute tolerance parameter (default 1e-08).
    :return: Returns True if the matrix is normal and False otherwise.
    """
    return np.allclose(np.matmul(mat,
                                 mat.conj().T),
                       np.matmul(mat.conj().T, mat),
                       rtol=rtol,
                       atol=atol)