Exemple #1
0
def Q(eq: SchrodingerEquation, dissipation):
    # Diagonalize Hamiltonian
    # Compute Q matrix elements
    eigval, eigvec = eq.eig()
    q = np.zeros((len(eigval), len(eigval)))
    jump_operators = np.array(dissipation.jump_operators)
    # For each pair of eigenvectors
    for pair in itertools.product(range(eigvec.shape[0]), repeat=2):
        # Compute the rate
        if pair[0] != pair[1]:
            eigvec1 = State(tools.outer_product(eigvec[pair[0]].T,
                                                eigvec[pair[0]].T),
                            is_ket=False,
                            IS_subspace=True,
                            graph=graph)
            eigvec2 = State(tools.outer_product(eigvec[pair[1]].T,
                                                eigvec[pair[1]].T),
                            is_ket=False,
                            IS_subspace=True,
                            graph=graph)

            rates = np.sum([
                np.trace(eigvec2 @ jump_operators[i] @ eigvec1
                         @ jump_operators[i].conj().T)
                for i in range(len(jump_operators))
            ])
            q[pair[1], pair[0]] = rates.real**2
            q[pair[0], pair[0]] = q[pair[0], pair[0]] - rates.real**2
    return q
Exemple #2
0
 def run(self, param, initial_state=None):
     if self.code.logical_code and initial_state is None:
         initial_state = State(tensor_product([self.code.logical_basis[1]] *
                                              self.N),
                               code=self.code)
     elif initial_state is None:
         if isinstance(self.cost_hamiltonian, HamiltonianMIS):
             initial_state = State(np.zeros(
                 (self.cost_hamiltonian.hamiltonian.shape[0], 1)),
                                   code=self.code)
             initial_state[-1, -1] = 1
         else:
             initial_state = State(
                 np.ones((self.cost_hamiltonian.hamiltonian.shape[0], 1)) /
                 np.sqrt(self.cost_hamiltonian.hamiltonian.shape[0]),
                 code=self.code)
     if not (self.noise_model is None or self.noise_model == 'monte_carlo'):
         # Initial s should be a density matrix
         initial_state = State(outer_product(initial_state, initial_state),
                               code=self.code)
     s = initial_state
     for j in range(self.depth):
         s = self.hamiltonian[j].evolve(s, param[j])
         if self.noise_model is not None:
             if self.noise[j] is not None:
                 s = self.noise[j].evolve(s, param[j])
     # Return the expected value of the cost function
     # Note that the codes's defined expectation function won't work here due to the shape of C
     return self.cost_hamiltonian.cost_function(s)
Exemple #3
0
    def k_beta(delta_r_bar):
        dt = 0.001
        overlap = 0
        for time in [0, 1-2*dt]:
            def normalize_phase(eig):
                where_nonzero = np.argwhere(np.absolute(eig) > 1e-9)[0]
                eig = np.e**(-1j*np.angle(eig[where_nonzero[0], where_nonzero[1]])) * eig
                # We can take the eigenvalues to be real for this Hamiltonian
                eig = eig.real
                return eig / np.linalg.norm(eig)

            schedule(time, 1, delta_r_bar=delta_r_bar)
            # Construct the first order transition matrix
            ground_energy, ground_state = SchrodingerEquation(hamiltonians=eq.hamiltonians).ground_state()
            ground_state = normalize_phase(ground_state)
            ham = scipy.sparse.csr_matrix((-ground_energy * np.ones(graph.num_independent_sets),
                                           (range(graph.num_independent_sets), range(graph.num_independent_sets))),
                                          shape=(graph.num_independent_sets, graph.num_independent_sets))
            for h in eq.hamiltonians:
                ham = ham + h.hamiltonian
            schedule(time+dt, 1, delta_r_bar=delta_r_bar)
            # Construct the first order transition matrix
            ground_energy_dt, ground_state_dt = SchrodingerEquation(hamiltonians=eq.hamiltonians).ground_state()
            ground_state_dt = normalize_phase(ground_state_dt)
            d_ground_state_dt = (ground_state_dt - ground_state) / dt
            # Construct a projector out of the ground subspace
            proj = np.identity(graph.num_independent_sets)
            proj = proj - tools.outer_product(ground_state, ground_state)
            if graph.degeneracy>1 and time == 0:
                # Project out of the ground subspace
                energies, states = SchrodingerEquation(hamiltonians=eq.hamiltonians).eig(k=graph.degeneracy)

                for i in range(graph.degeneracy-1):
                    proj = proj - tools.outer_product(states[i+1, np.newaxis].T, states[i+1, np.newaxis].T)
            d_ground_state_dt = proj @ d_ground_state_dt
            # Multiply by 1/(H-E_0)
            # If at the end, remove the rows corresponding to degeneracies
            if time != 0:
                d_ground_state_dt = d_ground_state_dt[graph.degeneracy:]
                ham = ham[graph.degeneracy:, graph.degeneracy:]
            else:
                d_ground_state_dt = d_ground_state_dt[:-1]
                ham = ham[:-1, :-1]
            res = scipy.sparse.linalg.spsolve(ham, d_ground_state_dt).real
            overlap += np.linalg.norm(res)**2
        return overlap
Exemple #4
0
    def channel(self,
                state: State,
                p: tuple,
                apply_to: Union[int, list] = None):
        """ Perform general Pauli channel on the i-th qubit of an input density matrix

        Input:
            rho = input density matrix (as numpy.ndarray)
            i = zero-based index of qubit location to apply pauli
            ps = a 3-tuple (px, py, pz) indicating the probability
                 of applying each Pauli operator

        Returns:
            (1-px-py-pz) * rho + px * Xi * rho * Xi
                               + py * Yi * rho * Yi
                               + pz * Zi * rho * Zi
        """
        try:
            assert len(p) == 3
        except AssertionError:
            print('Length of tuple must be 3.')
        # If the input s is a ket, convert it to a density matrix
        if state.is_ket:
            print('Converting ket to density matrix.')
            state = State(tools.outer_product(state, state))
        if apply_to is None:
            apply_to = list(range(state.number_physical_qudits))

        # Assume that apply_to is a list of integers
        if isinstance(apply_to, int):
            apply_to = [apply_to]

        if state.code.logical_code:
            # Assume that logical codes are composed of qubits
            code = self.code
        else:
            code = state.code
        # Handle apply_to recursively
        # Only apply to one qudit
        if len(apply_to) == 1:
            return state * (1 - sum(p)) + (
                p[0] * code.multiply(state, apply_to, ['X']) +
                p[1] * code.multiply(state, apply_to, ['Y']) +
                p[2] * code.multiply(state, apply_to, ['Z']))
        else:
            last_element = apply_to.pop()
            recursive_solution = self.channel(state, p, apply_to=apply_to)
            return recursive_solution * (1 - sum(p)) + p[0] * code.multiply(recursive_solution, [last_element], ['X']) \
                   + p[1] * code.multiply(recursive_solution, [last_element], ['Y']) + p[2] * \
                   code.multiply(recursive_solution, [last_element], ['Z'])
Exemple #5
0
    def channel(self,
                state: State,
                p: float,
                apply_to: Union[int, list] = None):
        """ Perform depolarizing channel on the i-th qubit of an input density matrix

                    Input:
                        rho = input density matrix (as numpy.ndarray)
                        i = zero-based index of qubit location to apply pauli
                        p = probability of depolarization, between 0 and 1
                """
        # If the input s is a ket, convert it to a density matrix
        if state.is_ket:
            print('Converting ket to density matrix.')
            state = State(tools.outer_product(state, state))
        if apply_to is None:
            apply_to = list(range(state.number_physical_qudits))
        # Assume that apply_to is a list of integers
        if isinstance(apply_to, int):
            apply_to = [apply_to]

        if state.code.logical_code:
            # Assume that logical codes are composed of qubits
            code = self.code
        else:
            code = state.code
        # Handle apply_to recursively
        # Only apply to one qudit
        if len(apply_to) == 1:
            return state * (
                1 - p) + p / 3 * (code.multiply(state, apply_to, ['X']) +
                                  code.multiply(state, apply_to, ['Y']) +
                                  code.multiply(state, apply_to, ['Z']))
        else:
            last_element = apply_to.pop()
            recursive_solution = self.channel(state, p, apply_to=apply_to)
            return recursive_solution * (1 - p) + p / 3 * (
                code.multiply(recursive_solution, [last_element], ['X']) +
                code.multiply(recursive_solution, [last_element], ['Y']) +
                code.multiply(recursive_solution, [last_element], ['Z']))
Exemple #6
0
 def evolve(self,
            state: State,
            time,
            threshold=.05,
            apply_to: Union[int, list] = None):
     if state.is_ket:
         print('Converting ket to density matrix.')
         state = State(tools.outer_product(state, state))
     if apply_to is None:
         apply_to = list(range(state.number_physical_qudits))
     # Assume that apply_to is a list of integers
     if isinstance(apply_to, int):
         apply_to = [apply_to]
     n = 1
     # Find a number of repetitions n small enough so that channel evolution is well approximated
     while (self.rates[0] * time)**2 / n > threshold:
         n += 1
     p = self.rates[0] * time / n
     s = state.copy()
     # Apply channel n times
     for i in range(n):
         s = self.channel(s, p, apply_to=apply_to)
     return s
Exemple #7
0
    def variational_grad(self, param, initial_state=None):
        """Calculate the objective function F and its gradient exactly
            Input:
                param = parameters of QAOA

            Output: (F, Fgrad)
               F = <HamC> for minimization
               Fgrad = gradient of F with respect to param
        """
        # TODO: make this work for continuous noise models
        if self.noise_model == 'continuous':
            raise NotImplementedError(
                'Variational gradient does not currently support continuous noise model'
            )
        param = np.asarray(param)
        # Preallocate space for storing copies of wavefunction - necessary for efficient computation of analytic
        # gradient
        if self.code.logical_code and initial_state is None:
            if isinstance(self.cost_hamiltonian, HamiltonianMIS):
                initial_state = State(tensor_product(
                    [self.code.logical_basis[1]] * self.N),
                                      code=self.code)
        elif initial_state is None:
            if isinstance(self.cost_hamiltonian, HamiltonianMIS):
                initial_state = State(np.zeros(
                    (self.cost_hamiltonian.hamiltonian.shape[0], 1)),
                                      code=self.code)
                initial_state[-1, -1] = 1
            else:
                initial_state = State(
                    np.ones((self.cost_hamiltonian.hamiltonian.shape[0], 1)) /
                    np.sqrt(self.cost_hamiltonian.hamiltonian.shape[0]),
                    code=self.code)
        if not (self.noise_model is None or self.noise_model == 'monte_carlo'):
            # Initial s should be a density matrix
            initial_state = State(outer_product(initial_state, initial_state),
                                  code=self.code)
        psi = initial_state
        if initial_state.is_ket:
            memo = np.zeros([psi.shape[0], 2 * self.depth + 2],
                            dtype=np.complex128)
            memo[:, 0] = np.squeeze(psi.T)
            tester = psi.copy()
        else:
            memo = np.zeros([psi.shape[0], psi.shape[0], self.depth + 1],
                            dtype=np.complex128)
            memo[..., 0] = np.squeeze(outer_product(psi, psi))
            tester = State(outer_product(psi, psi), code=self.code)
        # Evolving forward
        for j in range(self.depth):
            if initial_state.is_ket:
                tester = self.hamiltonian[j].evolve(tester, param[j])
                memo[:, j + 1] = np.squeeze(tester.T)
            else:
                self.hamiltonian[j].evolve(tester, param[j])
                # Goes through memo, evolves every density matrix in it, and adds one more in the j*m+i+1 position
                # corresponding to H_i*p
                s0_prenoise = memo[..., 0]
                for k in range(j + 1):
                    s = State(memo[..., k], code=self.code)
                    s = self.hamiltonian[j].evolve(s, param[j])
                    if k == 0:
                        s0_prenoise = s.copy()
                    if self.noise_model is not None:
                        if not (self.noise[j] is None):
                            s = self.noise[j].evolve(s, param[j])
                    memo[..., k] = s.copy()
                s0_prenoise = self.hamiltonian[j].left_multiply(s0_prenoise)
                if self.noise_model is not None:
                    if not (self.noise[j] is None):
                        s0_prenoise = self.noise[j].evolve(
                            s0_prenoise, param[j])
                memo[..., j + 1] = s0_prenoise.copy()

        # Multiply by cost_hamiltonian
        if initial_state.is_ket:
            memo[:, self.depth +
                 1] = self.cost_hamiltonian.hamiltonian @ memo[:, self.depth]

            s = State(np.array([memo[:, self.depth + 1]]).T, code=self.code)
        else:
            for k in range(self.depth + 1):
                s = memo[..., k]
                s = State(self.cost_hamiltonian.hamiltonian * s,
                          code=self.code)
                memo[..., k] = s

        # Evolving backwards, if ket:
        if initial_state.is_ket:
            for k in range(self.depth):
                s = self.hamiltonian[self.depth - k - 1].evolve(
                    s, -1 * param[self.depth - k - 1])
                memo[:, self.depth + k + 2] = np.squeeze(s.T)

        # Evaluating objective function
        if initial_state.is_ket:
            F = np.real(np.vdot(memo[:, self.depth], memo[:, self.depth + 1]))
        else:
            F = np.real(np.trace(memo[..., 0]))

        # Evaluating gradient analytically
        Fgrad = np.zeros(self.depth)
        for r in range(self.depth):
            if initial_state.is_ket:
                s = State(np.array([memo[:, 2 * self.depth + 1 - r]]).T,
                          code=self.code)
                s = self.hamiltonian[r].left_multiply(s)
                Fgrad[r] = -2 * np.imag(np.vdot(memo[:, r], np.squeeze(s.T)))
            else:
                Fgrad[r] = 2 * np.imag(np.trace(memo[..., r + 1]))
        return F, Fgrad
Exemple #8
0
    def channel(self,
                state: State,
                p: float,
                apply_to: Union[int, list] = None):
        """
        Applies ``povm`` homogeneously to the qudits identified in apply_to.

        :param p:
        :param apply_to:
        :param state: State to operate on.
        :type state: np.ndarray
        :return:
        """
        # If the input s is a ket, convert it to a density matrix
        if state.is_ket:
            print('Converting ket to density matrix.')
            state = State(tools.outer_product(state, state))
        if apply_to is None:
            apply_to = list(range(state.number_physical_qudits))

        # Assume that apply_to is a list of integers
        if isinstance(apply_to, int):
            apply_to = [apply_to]

        if state.code.logical_code:
            # Assume that logical codes are composed of qubits
            code = self.code
        else:
            code = state.code

        if self.IS_subspace:
            povm = self.povm(p)
            temp = state.copy()
            out = None
            for i in apply_to:
                out = State(np.zeros_like(state),
                            is_ket=state.is_ket,
                            code=state.code,
                            IS_subspace=state.IS_subspace,
                            graph=state.graph)
                for j in range(len(povm[i])):
                    out = out + povm[i][j] @ temp @ povm[i][j].conj().T
                temp = out
            return out
        # Handle apply_to recursively
        # Only apply to one qudit
        else:
            # Empty s to store the output
            out = State(np.zeros_like(state),
                        is_ket=state.is_ket,
                        code=state.code,
                        IS_subspace=state.IS_subspace,
                        graph=state.graph)

            if len(apply_to) == 1:
                povm = self.povm(p)
                for j in range(len(povm)):
                    out = out + code.multiply(state, apply_to, povm[j])
                return out
            else:
                last_element = apply_to.pop()
                recursive_solution = self.channel(state, p, apply_to=apply_to)
                povm = self.povm(p)
                for j in range(len(povm)):
                    out = out + code.multiply(recursive_solution,
                                              [last_element], povm[j])
                return out
Exemple #9
0
def k_beta(delta_r_bar, graph: Graph, verbose=False, mode='hybrid'):

    def schedule_hybrid(t, tf, delta_r_bar=0):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = (delta_r_bar * np.sin(phi) ** 2,)
        laser.omega_g = np.cos(phi)
        laser.omega_r = np.sin(phi)
        dissipation.omega_g = np.cos(phi)
        dissipation.omega_r = np.sin(phi)

    def schedule_adiabatic(t, tf, delta_r_bar=0):
        phi = (tf - t) / tf * np.pi / 2
        energy_shift.energies = ((delta_r_bar+1) * np.sin(phi) ** 2-np.cos(phi) ** 2,)
        laser.omega_g = np.sqrt(np.abs(np.cos(phi)*np.sin(phi)))
        laser.omega_r = np.sqrt(np.abs(np.cos(phi)*np.sin(phi)))
        dissipation.omega_g = np.sqrt(np.abs(np.cos(phi)*np.sin(phi)))
        dissipation.omega_r = np.sqrt(np.abs(np.cos(phi)*np.sin(phi)))


    if mode == 'hybrid':
        schedule = schedule_hybrid
    elif mode=='adiabatic':
        schedule = schedule_adiabatic

    laser = EffectiveOperatorHamiltonian(graph=graph, IS_subspace=True, energies=(1,), omega_g=1, omega_r=1)
    energy_shift = hamiltonian.HamiltonianEnergyShift(IS_subspace=True, graph=graph, index=0)
    dissipation = EffectiveOperatorDissipation(graph=graph, omega_r=1, omega_g=1, rates=(1,))
    eq = LindbladMasterEquation(hamiltonians=[laser, energy_shift], jump_operators=[dissipation])

    dt = 0.001
    overlap = 0
    for time in [0, 1-2*dt]:
        def normalize_phase(eig):
            where_nonzero = np.argwhere(np.absolute(eig) > 1e-9)[0]
            eig = np.e**(-1j*np.angle(eig[where_nonzero[0], where_nonzero[1]])) * eig
            # We can take the eigenvalues to be real for this Hamiltonian
            eig = eig.real
            return eig / np.linalg.norm(eig)

        schedule(time, 1, delta_r_bar=delta_r_bar)
        # Construct the first order transition matrix
        ground_energy, ground_state = SchrodingerEquation(hamiltonians=eq.hamiltonians).ground_state()
        ground_state = normalize_phase(ground_state)
        ham = scipy.sparse.csr_matrix((-ground_energy * np.ones(graph.num_independent_sets),
                                       (range(graph.num_independent_sets), range(graph.num_independent_sets))),
                                      shape=(graph.num_independent_sets, graph.num_independent_sets))
        for h in eq.hamiltonians:
            ham = ham + h.hamiltonian
        schedule(time+dt, 1, delta_r_bar=delta_r_bar)
        # Construct the first order transition matrix
        ground_energy_dt, ground_state_dt = SchrodingerEquation(hamiltonians=eq.hamiltonians).ground_state()
        ground_state_dt = normalize_phase(ground_state_dt)
        d_ground_state_dt = (ground_state_dt - ground_state) / dt
        # Construct a projector out of the ground subspace
        proj = np.identity(graph.num_independent_sets)
        proj = proj - tools.outer_product(ground_state, ground_state)
        if graph.degeneracy>1 and time == 0:
            # Project out of the ground subspace
            energies, states = SchrodingerEquation(hamiltonians=eq.hamiltonians).eig(k=graph.degeneracy)

            for i in range(graph.degeneracy-1):
                proj = proj - tools.outer_product(states[i+1, np.newaxis].T, states[i+1, np.newaxis].T)
        d_ground_state_dt = proj @ d_ground_state_dt
        # Multiply by 1/(H-E_0)
        # If at the end, remove the rows corresponding to degeneracies
        if time != 0:
            d_ground_state_dt = d_ground_state_dt[graph.degeneracy:]
            ham = ham[graph.degeneracy:, graph.degeneracy:]
        else:
            d_ground_state_dt = d_ground_state_dt[:-1]
            ham = ham[:-1, :-1]
        res = scipy.sparse.linalg.spsolve(ham, d_ground_state_dt).real
        overlap += np.linalg.norm(res)**2
    return overlap
Exemple #10
0
    def run(self, time, schedule, num=None, initial_state=None, full_output=True, method='RK45', verbose=False,
            iterations=None):
        if method == 'odeint' or method == 'trotterize' and num is None:
            num = self._num_from_time(time, method=method)

        if initial_state is None:
            # Begin with all qudits in the ground s
            initial_state = State(np.zeros((self.cost_hamiltonian.hamiltonian.shape[0], 1)), code=self.code,
                                  IS_subspace=self.IS_subspace, graph=self.graph)
            initial_state[-1, -1] = 1

        if self.noise_model is not None and self.noise_model != 'monte_carlo':
            initial_state = State(outer_product(initial_state, initial_state), IS_subspace=self.IS_subspace,
                                  code=self.code, graph=self.graph)

        if self.noise_model == 'continuous':
            # Initialize master equation
            if method == 'trotterize':
                master_equation = LindbladMasterEquation(hamiltonians=self.hamiltonian, jump_operators=self.noise)
                results, info = master_equation.run_trotterized_solver(initial_state, 0, time, num=num,
                                                                       schedule=lambda t: schedule(t, time),
                                                                       full_output=full_output, verbose=verbose)
            else:
                master_equation = LindbladMasterEquation(hamiltonians=self.hamiltonian, jump_operators=self.noise)
                results, info = master_equation.run_ode_solver(initial_state, 0, time, num=num,
                                                               schedule=lambda t: schedule(t, time), method=method,
                                                               full_output=full_output, verbose=verbose)
        elif self.noise_model is None:
            # Noise model is None
            # Initialize Schrodinger equation
            schrodinger_equation = SchrodingerEquation(hamiltonians=self.hamiltonian)
            if method == 'trotterize':
                results, info = schrodinger_equation.run_trotterized_solver(initial_state, 0, time, num=num,
                                                                            verbose=verbose, full_output=full_output,
                                                                            schedule=lambda t: schedule(t, time))
            else:
                results, info = schrodinger_equation.run_ode_solver(initial_state, 0, time, num=num, verbose=verbose,
                                                                    schedule=lambda t: schedule(t, time), method=method,
                                                                    full_output=full_output)

        else:
            assert self.noise_model == 'monte_carlo'
            # Initialize master equation
            master_equation = LindbladMasterEquation(hamiltonians=self.hamiltonian, jump_operators=self.noise)
            results, info = master_equation.run_stochastic_wavefunction_solver(initial_state, 0, time, num=num,
                                                                               full_output=full_output,
                                                                               schedule=lambda t: schedule(t, time),
                                                                               method=method, verbose=verbose,
                                                                               iterations=iterations)

        if len(results.shape) == 2:
            # The algorithm has output a single state
            out = [State(results, IS_subspace=self.IS_subspace, code=self.code, graph=self.graph)]
        elif len(results.shape) == 3:
            # The algorithm has output an array of states
            out = [State(res, IS_subspace=self.IS_subspace, code=self.code, graph=self.graph) for res in results]
        else:
            assert len(results.shape) == 4
            if self.noise_model != 'monte_carlo':
                raise Exception('Run output has more dimensions than expected')
            out = []
            for i in range(results.shape[0]):
                # For all iterations
                res = []
                for j in range(results.shape[1]):
                    # For all times
                    res.append(
                        State(results[i, j, ...], IS_subspace=self.IS_subspace, code=self.code, graph=self.graph))
                out.append(res)
        return out, info
Exemple #11
0
from scipy.linalg import expm
from qsim.codes.quantum_state import State
from typing import Union
from qsim.tools.tools import int_to_nary

__all__ = ['multiply', 'right_multiply', 'left_multiply', 'rotation']
logical_code = False
# Define Pauli matrices

X = X()
Y = Y()
Z = Z()
n = 1
d = 2
logical_basis = np.array([[[1], [0]], [[0], [1]]]).astype(np.complex128)
Q = outer_product(logical_basis[0], logical_basis[0])
P = outer_product(logical_basis[1], logical_basis[1])

code_space_projector = outer_product(logical_basis[0],
                                     logical_basis[0]) + outer_product(
                                         logical_basis[1], logical_basis[1])


def rotation(state: State,
             apply_to: Union[int, list],
             angle: float,
             op,
             is_involutary=False,
             is_idempotent=False):
    """
    Apply a single qubit rotation :math:`e^{-i \\alpha A}` to the input ``codes``.
Exemple #12
0
hamiltonians = [hc, hb]
ring_hamiltonians = [hc_ring, hb]

sim = qaoa.SimulateQAOA(g, cost_hamiltonian=hc, hamiltonian=hamiltonians)
sim_ring = qaoa.SimulateQAOA(ring,
                             cost_hamiltonian=hc_ring,
                             hamiltonian=ring_hamiltonians)
sim_ket = qaoa.SimulateQAOA(g, cost_hamiltonian=hc, hamiltonian=hamiltonians)
sim_noisy = qaoa.SimulateQAOA(g,
                              cost_hamiltonian=hc,
                              hamiltonian=hamiltonians,
                              noise_model='channel')

# Initialize in |000000>
psi0 = State(equal_superposition(N))
rho0 = State(outer_product(psi0, psi0))

noises = [quantum_channels.DepolarizingChannel(rates=(.001, ))]
sim_noisy.noise = noises * 2


class TestSimulateQAOA(unittest.TestCase):
    def test_variational_grad(self):
        # Test that the calculated objective function and gradients are correct
        # p = 1
        sim_ket.hamiltonian = hamiltonians
        F, Fgrad = sim_ket.variational_grad(np.array([1, 0.5]),
                                            initial_state=psi0)
        self.assertTrue(np.abs(F - 5.066062984904652) <= 1e-5)
        self.assertTrue(
            np.all(