示例#1
0
 def _normalize_state(self):
     """
         Normalizes psi_t by dividing by its trace. Internal normalization. Can be overloaded for
         tracking purposes. Is only called during the propagation
     :return:
     """
     self.psi_t /= mp.trace(self.psi_t)
示例#2
0
def bures_mps(rho, sigma):
    """
    Computes the Bures angle for two matrix product states. Requires
    rho and sigma to be pure and input as MPOs
    """
    fid = mp.trace(mp.dot(rho, sigma))

    return np.arccos(np.clip(np.sqrt(fid), 0.0, 1.0))
示例#3
0
 def _normalize_state(self):
     """
         Normalizes psi_t by dividing by the trace. Is only called during the propagation.
         Tracks the trace of the density matrix during propagation
     :return:
     """
     curr_trace = mp.trace(self.psi_t)
     if self.trace_track:
         self.trace_list.append(np.abs(curr_trace))
     self.psi_t /= curr_trace
示例#4
0
文件: mixed.py 项目: gharib85/py-tmps
def get_maximally_mixed_mpo(dims, normalized=False):
    """
        Generates a maximally mixed state as mpo embedded on a chain with physical dimensions specified by dims.
    :param dims: iterable of site local physical leg dimensions of the chain in which to embed
    :param normalized: Set True to return a normalized state
    :return: maximally mixed state as MPO
    """
    mm_mpo = mp.eye(len(dims), dims)
    if not normalized:
        return mm_mpo
    else:
        return mm_mpo / mp.trace(mm_mpo)
示例#5
0
def sandwich(op, propagator, startsite=0):
    """
        Calculates the expectation value of an operator in mpo form with a reduced state: <psi_t_red| mpo |psi_t_red>.
        nof_sites can be inferred from len(mpo) here
    :param op: Operator for which to take expectation value as mpo
    :param propagator: TMPSPropagator object. The reduced state |psi_red> is generated from propagator.psi_t
    :param startsite: first site of the reduced state (may be negative, indexing works like for python lists)
    :return: expectation value <psi_t_red| mpo |psi_t_red>
    """
    reduced = reduction(propagator, startsite=startsite, nof_sites=len(op))
    # TODO: maybe compress first after dot?
    return mp.trace(mp.dot(op, reduced))
示例#6
0
def sandwich_mpa(op, psi, mpa_type):
    """
        Calculates <op>_{psi} = tr(op*psi) for a state of specified mpa_type
    """
    if mpa_type == 'mps':
        psi = mp.mps_to_mpo(psi)
    elif mpa_type == 'pmps':
        psi = mp.pmps_to_mpo(psi)
    elif mpa_type == 'mpo':
        pass
    else:
        raise AssertionError('Unknown mpa_type')
    return mp.trace(mp.dot(op, psi))
示例#7
0
def normalize(state, method):
    """
    Normalize a state.

    Args:
        state (mpnum.MPArray): The state to be normalized
        method (str): Whether it is a MPS, MPO or PMPS state

    Returns:
        mpnum.MPArray: The normalized state
    """
    if method == 'pmps' or method == 'mps':
        state = state / mp.norm(state)
    if method == 'mpo':
        state = state / mp.trace(state)
    return state
示例#8
0
def sandwich_state(op, psi, mpa_type, startsite=0):
    """
        Calculates the expectation value of an operator in mpo form with a reduced state: <psi_red| mpo |psi_red>.
        nof_sites can be inferred from len(mpo) here
    :param op: Operator for which to take expectation value as mpo
    :param psi: State from which to generate reduced state |psi_red>
    :param startsite: first site of the reduced state
    :param mpa_type: mpa type of psi (mps, pmo or pmps)
    :return: expectation value <psi_red| mpo |psi_red>
    """
    reduced = state_reduction(psi,
                              mpa_type,
                              startsite=startsite,
                              nof_sites=len(op))
    # TODO: maybe compress first after dot?
    return mp.trace(mp.dot(op, reduced))
示例#9
0
def angle_estimate(stabilisers, state, N, shots=500):
    """
    Compute Bures angle given the perturbed state and the stabilisers for the True state
    """

    # initialise total
    stab_sum = 0.0
    # iterate over stabilisers
    for stab in stabilisers:
        # compute out probability given perturbed state
        prob = (1 + mp.trace(mp.dot(stab, state))) / 2
        stab_sum += mle(rand_res([1 - prob, prob], num=int(shots)))

    theta = theta_compute(stab_sum, N=N)
    # TODO: Fix this uncertainty calculation issue
    uncert = 0  # np.sqrt(var(theta, stab_sum, int(N)))
    return theta, uncert
示例#10
0
def normalize(state, method):
    """
    Normalize a state (hopefully in place)

    .. todo::
       Check if state is mutable and this operation in place. Then clear docstring

    Args:
        state (mpnum.MPArray): The state to be normalized
        method (str): Whether it is a MPS, MPO or PMPS state

    Returns:
        mpnum.MPArray: The normalized state
    """
    if method == 'pmps' or method == 'mps':
        state = state / mp.norm(state)
    if method == 'mpo':
        state = state / mp.trace(state)
    return state
示例#11
0
def calculate_expectation_values(states, observable):
    """
    Calculates the expectation values :math:`\\langle M \\rangle_i` of the the
    ``observable`` :math:`M` with respect to the ``states``
    :math:`\\{\\rho\\}`

    .. math::
        \\langle M \\rangle_i = \\text{tr}(\\rho_i M)

    For this function to work, the observable has to have the same dimension
    as the density matrix which represents the state, i.e. all states must
    have the same dimensions. This function is meant to work with a list of
    evolved states of the same system at different times.

    Args:
        states (list[mpnum.MPArray]): List of states :math:`\\{\\rho\\}`.
            They are assumed to be MPOs and already normalized
        observable (numpy.ndarray): The matrix representing the observable
            :math:`M` in global form (as opposed to local form. Global form
            is just the usual form to write matrices in QM. For more
            information, see the ``mpnum`` documentation.)

    Returns:
        list[mpnum.MPArray.dtype]: List of expectation values for the states
    """
    if not all(state.shape == states[0].shape for state in states):
        raise ValueError("The states in the provided list are not all of the "
                         "same shape.")
    if len(observable) != np.prod(np.array([_[0] for _ in states[0].shape])):
        raise ValueError("Observable dimensions and state dimensions do not "
                         "fit")
    expct_values = [
        mp.trace(
            mp.dot(
                state,
                tmps.matrix_to_mpo(observable, [[_[0]] * 2
                                                for _ in state.shape])))
        for state in states
    ]
    return expct_values
示例#12
0
 def normalize_state(self):
     """
         Normalizes psi_t by dividing by its trace
     :return:
     """
     self.psi_t /= mp.trace(self.psi_t)
示例#13
0
def UniU_error(U, N, perturbations=100, exact=True, shots=8000):
    """
    Check estimation error for an input U, number of perturbations and wether to use exact or finite sampling.
    """

    # generate entangled states
    rho = bell_gen(N=N)

    # generate Bell state stabilisers
    bell_gstab = bell_stab_gen(N=N)

    # convert to MPO if required
    if type(U) != mp.mparray.MPArray:
        try:
            U = mp.MPArray.from_array_global(U.reshape([2] * N * 2), ndims=2)
        except ValueError:
            # catch operator dimension mismatch
            raise ValueError(
                "Cannot reshape unitary into MPO, check dimensions")

    # apply to entangled state
    rho = mp.dot(U, rho)

    # evolve generators under unitary
    gstab = [mp.dot(mp.dot(U, stb), U.adj()) for stb in bell_gstab]

    # generate stabiliser set
    stabilisers = operator_find(gstab, N=N)

    # apply to entangled state and convert to MPO for measurement phase
    rho = mp.mpsmpo.mps_to_mpo(rho)

    # calculate the estimation error for requested number of perturbations
    error = []

    # initialise random unitary generator
    U_perturb = random_MPUgen(N)

    for i in range(0, perturbations):
        print("Now computing unitary perturbation {}\r".format(i),
              end="",
              flush=True)

        # make a copy
        rho_c = rho.copy()

        # compute a local perturbation using generator
        U_p = next(U_perturb)

        # apply to Choi state
        rho_c = mp.dot(mp.dot(U_p, rho_c), U_p.adj())

        # compute expectation values exactly or with finite samples
        if exact:
            Q = 0.0

            # iterate over stabiliser measurements
            for stab_proj in stabilisers:
                # add to Q sum
                Q += (1 + mp.trace(mp.dot(stab_proj, rho_c))) / 2
                print(Q)

            # estimate angle
            a_est = theta_compute(Q, N=N)

        else:
            # estimate expectation values from finite number of outcomes
            a_est, a_uncert = angle_estimate(stabilisers,
                                             rho_c,
                                             N=N,
                                             shots=shots)

            if np.abs(np.real(bures_mps(rho, rho_c) - a_est)) > 0.5:
                print(
                    "High estimation error: {:.3f}, something has gone wrong".
                    format(a_est))
                continue

        # compute angle estimate error
        error.append(np.real(bures_mps(rho, rho_c) - a_est))

    if exact:
        # output average estimation error - should always be small (<1e-4 depending on MPO compression)
        print("Average estimation error for {} perturbations: {:.3f}".format(
            perturbations, np.real(np.mean(error))))
    else:
        # plot errors as histogram
        n, bins, patches = plt.hist(x=error,
                                    bins=len(error) // 10,
                                    alpha=0.65,
                                    color='red',
                                    histtype='step')
        plt.xlabel("Error")
        plt.ylabel("Counts")
        plt.title("Error distribution for {} qubit Clifford+T unitary".format(
            N // 2))
        plt.show()